Hi,
I am updating my Dash app from version 2.11.1 to 3.0.0 and encountered an unexpected behavior with no_update
. When no_update
is returned as the output for a dcc.Store
, instead of preserving the existing data, it overwrites it with an object of type NoUpdate
. As a result, subsequent callbacks referencing this dcc.Store
receive an invalid value.
Attached a sample code where this behaviour can be replicated
import dash
from dash import Input, Output, State, callback_context, dcc, html, ctx, no_update
import dash_bootstrap_components as dbc
from dash_extensions.enrich import DashProxy, Output, Input, State, Serverside, html, dcc, ServersideOutputTransform
# Initialize Dash app
app = dash.Dash(__name__)
app = DashProxy(transforms=[ServersideOutputTransform()])
# Sample Dropdown Options (Replace with actual values)
query_dropdown_options = [
{"label": "ID1", "value": "id1"},
{"label": "ID2", "value": "id2"},
]
query_id_options = [
{"label": "qwer1234", "value": "qwer1234"},
{"label": "asdf5678", "value": "asdf5678"},
]
# Layout
app.layout = html.Div([
dcc.Store(id="store_dropdown"),
dbc.Row(
[
dbc.Col(
[
dbc.Row(
[
dbc.Col(
[
dcc.Dropdown(
id="my-multi-dynamic-dropdown",
placeholder="select",
style={"font-size": 12, "border-radius": 0, "width": "50%"},
options=query_id_options,
),
],
),
dbc.Col(
[
dcc.Dropdown(
id="my-multi-dynamic-dropdown_type",
options=query_dropdown_options,
value="id1",
searchable=False,
className="custom-dropdown",
clearable=False,
style={
"font-size": 12,
"border-radius": 0,
"padding-right": 0,
"width": "50%",
},
)
],
),
]
)
],
width=4,
id="id_dropdown_col",
),
dbc.Col(
dbc.Button(
"Query Data",
id="query-button",
className="mt-auto",
size="sm",
n_clicks=0,
),
id="analytics_query_button_col",
style={"display": "block"},
),
dbc.Col(
dbc.Button(
"Check Data",
id="check-button",
className="mt-auto",
size="sm",
n_clicks=0,
),
id="analytics_check_button_col",
style={"display": "block"},
),
],
style={"margin-top": "5px"},
),
dbc.Row(
dbc.Col(
html.Div(id='output-data'),
width=12
)
)
])
@app.callback(
Output("store_dropdown", "data"),
Output("output-data", "children", allow_duplicate=True),
Input("query-button", "n_clicks"),
State("my-multi-dynamic-dropdown", "value"),
State("my-multi-dynamic-dropdown_type", "value"),
)
def query(n_clicks, id, dropdown_type):
if n_clicks > 0:
if id is None or dropdown_type is None:
return Serverside(no_update), "Invalid dropdown value"
else:
return Serverside("hello"), "data_loaded"
return Serverside(no_update), no_update
@app.callback(
Output("output-data", "children", allow_duplicate=True),
Input("check-button", "n_clicks"),
State("store_dropdown", "data"),
)
def check(n_clicks, data):
if data is not None:
return len(data)
if __name__ == "__main__":
app.run(debug=True)
Dash Versions:
Error image:
Steps to replicate:
- Select one of the options in the first dropdown
- Click on query data which will print ādata_loadedā below check data btn
- Click on check data which will print 5 below the check data btn
- Then clear the first dropdown, click on the query data. which will print āInvalid dropdown valueā
- Then click on check data. The error pops up āTypeError: object of type āNoUpdateā has no len()ā