Skip to content

[BUG] dash.Patch() reruns inital callback for all matching elements #3681

@Aaron-Wrote-This

Description

@Aaron-Wrote-This

Environment

dash                 4.0.0

Hello, I've been getting into the wonderful world of extensibility, dash.Patch() and pattern matching callbacks.
Click a button, a new input appears, ect. But I have run into an issue when using pattern matching callbacks.

When a new element is appended via dash. Patch(), the initial callbacks run against every element of that type.

I have created a minimum test app to show the issue.

When clicking the "Add Slider" button, I would expect to see the print_callback_value function run once per click. Instead I see it run multiple times, once per element.
This can be seen in the console as well as the debug dash callbacks view.
10 slider creations cause 56 init callbacks.

Image

This causes performance issues with multiple sliders. It creates flickering as the elements are setup, and may have errors related to unexpected reinit callbacks, they have no ctx.triggered.

I have also created this PR as a suggested fix. #3682

from dash import Dash, dcc, html, Input, Output, callback, State, ctx, Patch, MATCH, no_update, clientside_callback, ALL
from dash.exceptions import PreventUpdate

app = Dash(__name__)

app.layout = html.Div(
    children=[
        dcc.Button(id='add_slider_btn', children='Add Slider'),
        html.Div(id='slider_container', children=[])
])


@callback(
    Output({'type': 'slider','aio_id': ALL}, 'value'),
    Input({'type': 'slider','aio_id': ALL}, 'value'),
    prevent_initial_call=False
)
def print_callback_value(val):
    print(f'{ctx.triggered_id=} = {val}')
    raise PreventUpdate


@callback(Output("slider_container", "children"),
          Input("add_slider_btn", "n_clicks"),
          prevent_initial_call=True,
          )
def add_new_slider(n_clicks):
    sliders_container_patch = Patch()
    sliders_container_patch.append(
        dcc.Slider(id={
            'type': 'slider',
            'aio_id': str(n_clicks)
        },
            step=0.1,
            persistence=True, persistence_type='local'
        )
    )
    return sliders_container_patch


if __name__ == '__main__':
    app.run(debug=True)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions