Skip to content
This repository was archived by the owner on Jun 3, 2024. It is now read-only.
This repository was archived by the owner on Jun 3, 2024. It is now read-only.

Store component breaks with nested data. #332

Closed
@bcliang

Description

@bcliang

The Store component should support serialization and deserialization of standard python variable types (JSON.stringify() and JSON.parse()). However, the component does not properly validate the data if it is a dictionary with keys comprising of either lists or additional dicts:

  • return dict(mykey=[])
  • return dict(mykey = dict())

The data is saved properly to session/local storage (I did not try memory), but fails after componentUpdate. I didn't dig into it, but believe this is a result of how the dataCheck function evaluates this type of data structure against what is already stored (always returns true, data has changed). End result is that modified_timestamp callback is triggered in an infinite loop.

function dataCheck(data, old) { ... }

I'm currently working around this issue by serializing the information myself rather than relying on the built-in handler.
return json.dumps(dict(mykey=[]))

See below for a demo. Issue applies to empty/non-empty lists/dicts.

import json
import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output, State

app = dash.Dash(__name__)


app.layout = html.Div([
    dcc.Store(
        id='store',
        storage_type='local'
    ),
    html.Button(
        id='btn1',
        children='break me'
    ),
    html.Button(
        id='btn2',
        children='pre-serialize (safe)'
    ),
    html.Div(id='output')
])


@app.callback(
    Output('store', 'data'),
    [Input('btn1', 'n_clicks'),
     Input('btn2', 'n_clicks')],
    [State('btn1', 'n_clicks_timestamp'),
     State('btn2', 'n_clicks_timestamp')]
)
def unsafe_click(n_clicks1, n_clicks2, tm_clicks1, tm_clicks2):
    if n_clicks1 is None and n_clicks2 is None:
        raise dash.exceptions.PreventUpdate

    data = dict(key=[])  # dict(key=dict())
    tm_clicks1 = tm_clicks1 or -1
    tm_clicks2 = tm_clicks2 or -1
    if tm_clicks2 > tm_clicks1:
        data = json.dumps(data)

    return data


@app.callback(
    Output('output', 'children'),
    [Input('store', 'modified_timestamp')],
    [State('store', 'data')]
)
def add_to_storage(timestamp, data):
    if timestamp is None:
        raise dash.exceptions.PreventUpdate

    print('current storage is {}'.format(data))
    print('modified_timestamp is {}'.format(timestamp))

    return json.dumps(data)


if __name__ == '__main__':
    app.run_server(debug=True, threaded=True, port=3033)

Metadata

Metadata

Assignees

Labels

dash-type-bugSomething isn't working as intended

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions