Skip to content

"Maximum update depth exceeded" error by updating the initialData of the dash-excalidraw component through re-keying its parent. #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
pip-install-python opened this issue May 8, 2025 · 0 comments
Assignees

Comments

@pip-install-python
Copy link
Owner

import dash
from dash import html, dcc, Input, Output, State
import dash_excalidraw
from dash.exceptions import PreventUpdate
import uuid
from datetime import datetime
import random

# Initialize the Dash app
app = dash.Dash(__name__, suppress_callback_exceptions=True)

# Initial empty canvas data (can be simplified further)
def get_initial_canvas_data(content="Initial"):
    return {
        'type': 'excalidraw',
        'version': 2,
        'source': 'Minimal-Bug-Reproducer',
        'elements': [
            {
                "id": str(uuid.uuid4()),
                "type": "text",
                "x": 50 + random.randint(-20, 20), # Slightly change position
                "y": 50 + random.randint(-20, 20),
                "width": 300,
                "height": 50,
                "angle": 0,
                "strokeColor": "#000000",
                "backgroundColor": "transparent",
                "fillStyle": "hachure",
                "strokeWidth": 1,
                "strokeStyle": "solid",
                "roughness": 1,
                "opacity": 100,
                "text": f"{content} - {datetime.now().time()}", # Change text content
                "fontSize": 20,
                "fontFamily": 1,
                "textAlign": "left",
                "verticalAlign": "top",
                "baseline": 18,
                "seed": random.randint(1, 1000000), # Change seed
                "version": 1,
                "versionNonce": random.randint(1, 1000000), # Change versionNonce
                "isDeleted": False,
                "updated": int(datetime.now().timestamp() * 1000)
            }
        ],
        'appState': {
            'gridSize': 20,
            'viewBackgroundColor': '#ffffff',
            "theme": "light" # Ensure theme is present, as it's often in appState
        },
        'files': {}
    }

initial_data_for_load = get_initial_canvas_data("Loaded at Start")

# Define the app layout
app.layout = html.Div([
    html.H1("Dash Excalidraw Bug Reproducer"),
    html.Button("Update Excalidraw with New Data", id="update-button", n_clicks=0),
    html.Div(id="status-output", style={"marginTop": "10px", "marginBottom": "10px"}),
    html.Div(
        id="excalidraw-wrapper-container", # This div's children will be updated
        children=html.Div( # The re-keyed div
            key='excalidraw-initial-key',
            children=dash_excalidraw.DashExcalidraw(
                id='excalidraw-instance',
                width='100%',
                height='500px',
                initialData=initial_data_for_load,
            ),
            style={"border": "1px solid lightgrey", "height": "500px"}
        )
    ),
    html.P("Open your browser's developer console (usually F12) to check for 'Maximum update depth exceeded' errors after clicking the button multiple times.")
])

@app.callback(
    Output("excalidraw-wrapper-container", "children"),
    Output("status-output", "children"),
    Input("update-button", "n_clicks"),
    prevent_initial_call=True
)
def update_excalidraw(n_clicks):
    if n_clicks == 0:
        raise PreventUpdate

    print(f"Button clicked: {n_clicks}")
    new_content = f"Update #{n_clicks}"
    new_excalidraw_data = get_initial_canvas_data(new_content)

    # Create the new DashExcalidraw component instance
    new_excalidraw_component = dash_excalidraw.DashExcalidraw(
        id='excalidraw-instance', # ID can remain the same as React handles identity by key
        width='100%',
        height='500px',
        initialData=new_excalidraw_data,
    )

    # Create a new wrapper div with a new unique key to force remount
    # Using a timestamp for the key is a reliable way to make it unique
    new_key = f'excalidraw-key-{datetime.now().timestamp()}'
    print(f"Generated new key: {new_key}")

    new_wrapper_div = html.Div(
        key=new_key,
        children=new_excalidraw_component,
        style={"border": "1px solid lightblue", "height": "500px"} # Visual cue for change
    )

    status_message = f"Excalidraw updated with new data at {datetime.now().strftime('%H:%M:%S')}. New key: {new_key}"
    print(status_message)

    return new_wrapper_div, status_message


if __name__ == '__main__':
    print("Starting Dash app on http://127.0.0.1:8050/")
    print("After clicking the button, check the browser's developer console for errors.")
    app.run(debug=True, port=8250)
@pip-install-python pip-install-python self-assigned this May 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant