✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
⚡️ Concerned about the grid? Kyle Baranko teaches how to predicting peak loads using XGBoost. Register for the August webinar!

Dash Bug? Callback runs multiple times on the same input trigger

Hi, a couple of my dash callbacks run multiple times even when the input trigger is only fired once. Does anyone know why this is the case?

app.callback(
    [Output("leafletmap", "children"),Output("session-map","data")],
    [   Input("apply-button","n_clicks"),
        Input("perf-type", "value"),
        Input("collapse8","is_open")
        ],
    [State("date-range-input", "start_date"),
        State("date-range-input", "end_date"),
        State("session-map","data")]
)
def choropleth_callback(apply,perf_type, collapse,start_date, end_date, storage):
    #if the card isn't active don't load the graph 
    if not collapse:
        raise PreventUpdate
    print("Performance Map is active...")
    
    if storage is None:
        storage = {}

    sql = # sql statement to get the data



    #update storage chache
    if sql in storage:
        print("accessing map df from storage ")
        df = pd.DataFrame.from_dict(storage[sql])
        storage[sql] = storage.pop(sql)
    else:
        print("accessing map df from db")
        conn=db_connection()
        df = pd.read_sql_query(sql, conn)
    
        storage[sql]=df.to_dict()
        if len(storage) > 5:
               storage.pop(next(iter(storage)))
        conn.close()

    # endregion

    minmax = get_minmax(df,perf_type)
    # Create geojson.
    geojson = dl.GeoJSON(data=get_data(df,perf_type), id="geojson", format="geobuf",
                        zoomToBounds=True,  # when true, zooms to bounds when data changes
                        cluster=True,  # when true, data are clustered
                        clusterToLayer=dlx.scatter.cluster_to_layer,  # how to draw clusters
                        zoomToBoundsOnClick=True,  # when true, zooms to bounds of feature (e.g. cluster) on click
                        options=dict(pointToLayer=dlx.scatter.point_to_layer),  # how to draw points
                        superClusterOptions=dict(radius=150),  # adjust cluster size
                        hideout=dict(colorscale= ["red","yellow","green"], color_prop=perf_type, **minmax))
    # Create a colorbar.
    colorbar = dl.Colorbar(colorscale=["red","yellow","blue"], id="colorbar", width=20, height=150, **minmax)
    
    mapOutput = dl.Map([dl.TileLayer(), geojson, colorbar],center=[43,-79],style={'width': '700px', 'height': '800px'},id = "lmap")
    
    return  [mapOutput,storage]