dash
dash copied to clipboard
[BUG] dcc.Store callback firing multiple times
Describe your context
dash 1.9.1
dash-bootstrap-components 0.8.3
dash-core-components 1.8.1
dash-daq 0.4.0
dash-html-components 1.0.2
dash-renderer 1.2.4
dash-table 4.6.1
- OS: MacOS 10.15.3
- Browser: Safari
- Version 13.0.5
Describe the bug
The dcc.Storage component seems to trigger twice (sometimes more) on starting the app and sometimes on subsequent triggers. See example below.
Minimal working example code:
import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Output, Input, State
from dash.exceptions import PreventUpdate
app = dash.Dash(__name__)
app.layout = html.Div([
dcc.Store(id='local', storage_type='local'),
html.Div(html.Button('localStorage', id='local-button')),
html.Div(0, id='local-clicks'),
])
@app.callback(Output('local', 'data'),
[Input('local-button', 'n_clicks')],
[State('local', 'data')])
def on_click(n_clicks, data):
if n_clicks is None:
raise PreventUpdate
app.logger.info(f"Updating data store")
data = data or {'clicks': 0}
data['clicks'] = data['clicks'] + 1
return data
@app.callback(Output('local-clicks', 'children'),
[Input('local', 'modified_timestamp')],
[State('local', 'data')]
)
def on_data(ts, data):
if ts is None:
raise PreventUpdate
app.logger.info(f"New data found! ({ts}, {data})")
return f"{ts}, {data['clicks']}"
if __name__ == '__main__':
app.run_server(debug=True, port=8077, threaded=True)
Example output:
Running on http://127.0.0.1:8077/
Debugger PIN: 597-637-135
New data found! (1584011957193, {'clicks': 24})
New data found! (1584011957193, {'clicks': 24})
Updating data store
New data found! (1584012443177, {'clicks': 25})
New data found! (1584012443177, {'clicks': 25})
Updating data store
New data found! (1584012445159, {'clicks': 26})
New data found! (1584012445159, {'clicks': 26})
Expected behavior
The callback should fire once.
I also faced the same issue with my dcc.store().
I update the store in a client-side call and then call the server callback.
here's a version inspired by your example.
Version Informations
dash 2.4.1 pypi_0 pypi
dash-core-components 2.0.0 pypi_0 pypi
dash-html-components 2.0.0 pypi_0 pypi
dash-daq 0.5.0 pypi_0 pypi
Reproduce the Bug.
import datetime
import dash
from dash import html, dcc
from dash.dependencies import Output, Input, State
from dash.exceptions import PreventUpdate
app = dash.Dash(__name__)
app.layout = html.Div(
[
dcc.Store(id="local", storage_type="local"),
html.Div(html.Button("localStorage", id="local-button")),
html.Div(0, id="local-clicks"),
]
)
app.clientside_callback(
"""
function(n_clicks, data) {
if (n_clicks) {
console.log("Updating data store");
data = data || {clicks: 0};
data.clicks = data.clicks + 1;
return data;
}
}
""",
Output("local", "data"),
[Input("local-button", "n_clicks")],
[State("local", "data")],
)
@app.callback(
Output("local-clicks", "children"),
[Input("local", "modified_timestamp")],
[State("local", "data")],
)
def on_data(ts, data):
print(datetime.datetime.now())
print(f"New data found! ({ts}, {data})")
print("-" * 20)
return f"{ts} - {data['clicks']}"
if __name__ == "__main__":
app.run_server(debug=True, port=8077)
Expected Output
2022-06-25 15:22:20.186572
New data found! (1656150740170, {'clicks': 85})
--------------------
Current Output
and in the browser console
Please help, is someplace I can look at if to resolve this.