Daily Tips - Convert a React Component to Dash πŸ‘Œ

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.
dw

Yes, it’s a weather component.

I found it at random. :smile_cat:

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. :yum:




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?

4 Likes