Hi there,
You know, they said that the entire React ecosystem can be used in Dash applications, right? Today weβre going to try converting or wrapping a React component to dash.
Look at the result first.
Yes, itβs a weather component.
I found it at random.
With the selected components to be converted, letβs do it step by step from the official docs.
We need nodejs and cookiecutter. And the plotly team has prepared a template for us.
cookiecutter https://github.com/plotly/dash-component-boilerplate.git
Emm, it looks like this template hasnβt been updated for a while. If I donβt have virtualenv
, its error message even mentioned py2, and it pulls the latest version of dash for me, but still comes with deprecated components such as dash-*-components
that repeatedly warn me when running code.
tree -L 1
.
βββ CONTRIBUTING.md
βββ DESCRIPTION
βββ LICENSE
βββ MANIFEST.in
βββ NAMESPACE
βββ Project.toml
βββ R
βββ README.md
βββ _validate_init.py
βββ dash_weather
βββ deps
βββ index.html
βββ inst
βββ man
βββ node_modules
βββ package-lock.json
βββ package.json
βββ pytest.ini
βββ requirements.txt
βββ review_checklist.md
βββ setup.py
βββ src
βββ tests
βββ usage.py
βββ venv
βββ webpack.config.js
βββ webpack.serve.config.js
The file structure is like this, but donβt worry about this pile, the files we need to modify are mainly under /src
.
tree
.
βββ demo
β βββ App.js
β βββ index.js
βββ lib
βββ LazyLoader.js
βββ components
β βββ DashWeather.react.js
βββ fragments
β βββ DashWeather.react.js
βββ index.js
These two DashWeather.react.js
are the target files, I donβt know why they have the same name.
The first one.
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { DashWeather as RealComponent } from '../LazyLoader';
/**
* ExampleComponent is an example component.
* It takes a property, `label`, and
* displays it.
* It renders an input with the property `value`
* which is editable by the user.
*/
export default class DashWeather extends Component {
render() {
return (
<React.Suspense fallback={null}>
<RealComponent {...this.props} />
</React.Suspense>
);
}
}
DashWeather.defaultProps = {
api_key: 'YOUR-API-KEY',
city: '',
lat: 48.137154,
lon: 11.576124,
lang: 'en',
unit: 'metric',
service: 'OpenWeather',
style: {
fontFamily: 'Helvetica, sans-serif',
gradientStart: '#0181C2',
gradientMid: '#04A7F9',
gradientEnd: '#4BC4F7',
locationFontColor: '#FFF',
todayTempFontColor: '#FFF',
todayDateFontColor: '#B5DEF4',
todayRangeFontColor: '#B5DEF4',
todayDescFontColor: '#B5DEF4',
todayInfoFontColor: '#B5DEF4',
todayIconColor: '#FFF',
forecastBackgroundColor: '#FFF',
forecastSeparatorColor: '#DDD',
forecastDateColor: '#777',
forecastDescColor: '#777',
forecastRangeColor: '#777',
forecastIconColor: '#4BC4F7',
}
};
DashWeather.propTypes = {
/**
* The ID used to identify this component in Dash callbacks.
*/
id: PropTypes.string,
/**
* ----.
*/
city: PropTypes.string,
/**
* ----.
*/
api_key: PropTypes.string.isRequired,
/**
* ----.
*/
lat: PropTypes.number,
/**
* ----.
*/
lon: PropTypes.number,
/**
* ----.
*/
lang: PropTypes.string,
/**
* ----.
*/
unit: PropTypes.string,
/**
* ----.
*/
service: PropTypes.string,
/**
* ----.
*/
style: PropTypes.object,
/**
* Dash-assigned callback that should be called to report property changes
* to Dash, to make them available for callbacks.
*/
setProps: PropTypes.func
};
export const defaultProps = DashWeather.defaultProps;
export const propTypes = DashWeather.propTypes;
The second JSX file.
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { defaultProps, propTypes } from '../components/DashWeather.react';
import ReactWeather, { useOpenWeather, useWeatherBit, useVisualCrossing } from 'react-open-weather';
const DashWeather = (props) => {
const { id, api_key, city, lat, lon, lang, unit, service, style } = props;
const services = {
'OpenWeather': useOpenWeather,
'WeatherBit': useWeatherBit,
'VisualCrossing': useVisualCrossing
};
const { data, isLoading, errorMessage } = services[service]({
key: api_key,
lat: lat,
lon: lon,
lang: lang,
unit: unit
});
return (
<ReactWeather
isLoading={isLoading}
errorMessage={errorMessage}
data={data}
lang={lang}
theme={style}
locationLabel={city}
unitsLabels={{ temperature: 'C', windSpeed: 'Km/h' }}
showForecast
onChange={
/*
* Send the new value to the parent component.
* setProps is a prop that is automatically supplied
* by dash's front-end ("dash-renderer").
* In a Dash app, this will update the component's
* props and send the data back to the Python Dash
* app server if a callback uses the modified prop as
* Input or State.
*/
e => setProps({ value: e.target.value })
}
/>
);
};
DashWeather.defaultProps = defaultProps;
DashWeather.propTypes = propTypes;
export default DashWeather;
We can see that the first file is mainly for type checking and default value assignment of class properties. It imports the second JSX file via LazyLoader.js
. The second file is the exact component logic. The template initially provides an example of a class component, but I only have functional components. Donβt forget to export.
Once the React components are arranged, we can execute npm run build
. Then, if there is no error, we will have a Dash component.
The usage.py
file is for testing.
import dash_weather
from dash import Dash, Input, Output, State, html, dcc
app = Dash(__name__)
app.layout = html.Div(
[
dcc.Loading(
dash_weather.DashWeather(
id="dw-1",
api_key="ef2c6429000-my-key-00016a24009833",
city="New York",
lat=43,
lon=75,
lang="en",
unit="metric",
service="OpenWeather",
)
),
html.Br(),
lat := dcc.Input(type="number"),
lon := dcc.Input(type="number"),
city := dcc.Input(),
btn := html.Button("Update"),
]
)
@app.callback(
[Output("dw-1", "lat"), Output("dw-1", "lon"), Output("dw-1", "city")],
Input(btn, "n_clicks"),
[State(lat, "value"), State(lon, "value"), State(city, "value")],
prevent_initial_call=True,
)
def update(n, lat, lon, city):
return lat, lon, city
if __name__ == "__main__":
app.run_server(debug=True)
Iβm new to React. If there is anything that needs to be improved, please feel free to let me know.
There are not so many examples of custom components, Iβm looking forward to someone sharing some different examples of how to modify this template.
Hope you like this. XD
Keywords: Creating Your Own Components, Custom Components, React, Cookiecutter, dash-component-boilerplate
Other Daily Tips series:
Daily Tips - If I have a Bunch of Triggers
Daily Tips - Share the Function
Daily Tips - How many Ways to share Dash in a company?
Daily Tips - Give your Component a Name
Daily Tips - Share Dash to Social Media
Daily Tips - Double-click to open Dash
Daily Tips - What rows of data have I modified?
Daily Tips - Write the Simplest Client-side Callback
Daily Tips - Some simple Expressions
Daily Tips - IoT? Real Real-time Data and Live Update
Daily Tips - Which formatter is your favorite?