Dcc.store : returning an array vs. returning a dict

Hello again. I’ve come to understand more about python and dash, but still a beginner and a longs way to go.

I have this:

@app.callback(
    Output("store", "data"),
    Output("text", "value"),
    Input("addbox", "n_clicks"),
    State("cikinput", "value"),
    State("store", "data"),
)
def store_data(n_clicks, oval, data):
    ctx = dash.callback_context
    input_id = ctx.triggered[0]["prop_id"].split(".")[0]
    if input_id == "addbox":
        data[n_clicks] = oval
        return data, dash.no_update
    else:
        return dash.no_update, data.get(oval, "")

which returns this:

[{‘0’: ‘CIK0000832988.csv’, ‘1’: ‘CIK0000832988.csv’}]

I think that’s called an array?

But from this snippet:

@app.callback(
    Output("store", "data"),
    Output("dropdown", "value"),
    Input("text", "value"),
    Input("submit", "n_clicks"),
    State("dropdown", "value"),
    State("store", "data"),
)
def update(text_value, n_clicks, op_value, data):
    ctx = dash.callback_context
    input_id = ctx.triggered[0]["prop_id"].split(".")[0]
    if input_id == "submit":
        data[n_clicks] = op_value
        return data, dash.no_update
    else:
        return dash.no_update, data.get(text_value, "")

returns it like this:

{‘0’: ‘abc’, ‘1’: ‘xyz’}

How can I control this? I can’t figure out how.

Thank you

Hey @shrykull,

An array is a list so adding onto that specific first example would look like: [{‘0’: ‘CIK0000832988.csv’, ‘1’: ‘CIK0000832988.csv’}, {‘0’: ‘CIK00032928.csv’, ‘1’: ‘CIK000832988.csv’}] as that store is built out further.

The problem you are most likely facing stems from how the store is initially configured or how the data is being manipulated. Here’s some tips & tricks that might help.

The Issue

The first callback returns: [{'0': 'CIK0000832988.csv', '1': 'CIK0000832988.csv'}] (a list containing a dict) The second callback returns: {'0': 'abc', '1': 'xyz'} (just a dict)

Root Cause

This typically happens when:

  1. The initial dcc.Store data is set differently (as a list vs dict)
  2. There’s inadvertent list wrapping happening somewhere

Solution

Here’s how to ensure consistent behavior:

1. Initialize the Store Properly

python

# In your layout
dcc.Store(id='store', data={})  # Initialize with empty dict, NOT []

2. Fix the First Callback

@app.callback(
    Output("store", "data"),
    Output("text", "value"),
    Input("addbox", "n_clicks"),
    State("cikinput", "value"),
    State("store", "data"),
)
def store_data(n_clicks, oval, data):
    ctx = dash.callback_context
    input_id = ctx.triggered[0]["prop_id"].split(".")[0]
    
    # Ensure data is always a dict
    if data is None:
        data = {}
    elif isinstance(data, list):
        # If it's a list with a dict inside, extract the dict
        data = data[0] if data and isinstance(data[0], dict) else {}
    
    if input_id == "addbox":
        data[str(n_clicks)] = oval  # Use string keys for consistency
        return data, dash.no_update
    else:
        return dash.no_update, data.get(oval, "")

3. Alternative: Use prevent_initial_call

If the issue is happening on initial load, you can prevent the callback from firing initially:

@app.callback(
    Output("store", "data"),
    Output("text", "value"),
    Input("addbox", "n_clicks"),
    State("cikinput", "value"),
    State("store", "data"),
    prevent_initial_call=True  # Add this
)

4. Debug Helper

To understand what’s happening, add this debug print:

def store_data(n_clicks, oval, data):
    print(f"Data type: {type(data)}, Data: {data}")  # Debug line
    # rest of your code

Best Practices for dcc.Store:

  1. Always initialize with the data type you want to maintain (dict in this case)
  2. Use string keys consistently (str(n_clicks) instead of n_clicks)
  3. Validate data type at the beginning of callbacks
  4. Consider using storage_type='session' if you want data to persist across page refreshes

The key is to ensure your store always maintains the same data structure (dictionary) throughout its lifecycle.

Hope this helps :grimacing: :+1:

1 Like