Adopting a React components for dash

Has anyone successfully translated a react component to dash?
The provided documentation is about a super simple

Hello World

type component (which is a great start, and the process is documented very well), but I was trying to create something a bit more sophisticated and a little lost, as I am not sure what is supported and what’s not.

@chriddyp do you think it is even possible to translate this to dash?
http://mathieudutour.github.io/react-progress-button
https://github.com/mathieudutour/react-progress-button/blob/master/src/index.js
I am willing to try, unless you know that it would not work due to some tech limitations (due to inability to translate handlePromise() for example)

1 Like

Great question @vlad!

The key to designing React component for Dash is coming up with the set of declarative (JSON-ifable) attributes that describe the component. The component will modify some of these attributes through user interaction (e.g. entering a value in dcc.Input updates the value property by calling setProps({value: newValue}) and all of the properties will be modifiable through the Dash application code through Output callbacks.

In this case, the react-progress-button might have an interface that’s like:

app.layout = html.Div([
    [...]
    ProgressButton(id='my-button', n_clicks=0)
])

@app.callback(Output(...), [Input('my-button', 'n_clicks')])
def do_something_when_the_button_is_clicked(number_of_times_the_button_has_been_clicked):
    # ...

However, the cool feature of the react-progress-button is its loading state. Although we could set a property like like is_loading that would toggle this button’s loading state on and off, I don’t think that there is a good way to toggle this property through a chain of Input and Output callbacks.

Ultimately, if we end up introducing web-socket or HTTP-push support, something like this might be possible:

app.layout = html.Div([
    ProgressButton(id='my-button', n_clicks=0)
    html.Div(id='output')
])

@app.callback(Output('output', 'children'), [Input('my-button', 'n_clicks')])
def long_data_processing_function(n_clicks):
    app.push_value('my-button', {'isLoading': True}) # web-socket or HTTP2 server push to front-end that sets the attribute
   
    output_value = some_really_long_running_function() # might take several seconds

    # when done, turn off the loading state
    app.push_value('my-button', {'isLoading': False})

    # and return the value to the front-end
    return output_value

In the meantime, we also need to built-in support for loading states so that we don’t have to design specialized components or complex input-output chains. Loading states will likely be customizable on the app, input, and output component level so that you could add a “loading” UI wherever you’d like (e.g. either grey out the entire screen or just add a spinner to the button or just add a “loading…” to the output elements).