Implementing dcc.Store on multi page app

This is more of an overall design/architecture question. I have an app with 4 pages on it and currently each page connects back to the database each time a control is changed which doesn’t entirely efficient.

Enter the dcc.Store component which seems amazing so is the best practice to create 1 store per app or create 1 store per page and which type of store is recommended? I was thinking of doing store based on session since multiple users can be on this dash app at a time.

Any thoughts welcome. Thanks!!

Anyone have any suggestions on this?

Thanks!

Hi @tphil10

I’m not sure there if there is one “best practice” – it really depends on how you use the data in your app.

For example you could use one dcc.Store() for your entire app and have the data for each page in a dictionary. However, if you use that as an Input in several callback, every time time any of the data changes, it will trigger the callbacks. Maybe you want that to happen … or maybe you only want the callback to trigger when the data for that one page changed.

The storage_type is how it’s stored in each user’s browser:

storage_type ( a value equal to: ‘local’, ‘session’, ‘memory’ ; default 'memory' ): The type of the web storage. memory: only kept in memory, reset on page refresh. local: window.localStorage, data is kept after the browser quit. session: window.sessionStorage, data is cleared once the browser quit.

Yea i’ll have to think around this. Each of my pages references the same kind of data but different timeframes of it. For example my first page is only looking at data that was gathered today whereas the second page is analyzing data that’s been gathered over the past 2 years.

I’m thinking i can create a single store for all the pages and load up the data upon the page changing. Then any filters the user uses on that page will retrieve from the store instead of having to go back to the database.

Hi @tphil10
I’m new to dash and struggling with actually implementing this. I believe there’s no documentation to this as well.
I have a dcc.Store() in the main app. Now how do I access this from different pages. I tried directly accessing from the callback, but it didn’t work. I tried importing the main app’s layout into the other page, that too didn’t work. I’m confused.

Could you please provide an example that shows how to use dcc.Store() in multipage apps.

Hi @rics
if you have dcc.Store storing data on the main app page. You should be able to use the Callback Input on any other page to retrieve the data. For example:

@app.callback(
    Output(.....)
    Input('stored_data_from_main_page', 'data')
)
def update_something(data):
    DoSomethingWithData
    return something

Did that work for you?

Hey @adamschroeder

Thanks for the response!
But unfortunately that didn’t work.
It gives the error: A nonexistent object was used in an Input of a Dash callback. The id of this object is intermediate_store_data and the property is data. The string ids in the current layout are: [url, page_content, DatePickerRange5, data_table_delay5]

where my main app page looks like:

app1 = Dash(__name__, suppress_callback_exceptions=True, external_stylesheets=[dbc.themes.BOOTSTRAP])

app1.layout = html.Div([
    dcc.Location(id='url', refresh=False),
    html.Div(id='page_content')
])

index_page = dbc.Container([
                                               dbc.Row([........]),
                                               dbc.Row([........]),
                                               dcc.Store(id='intermediate_store_data', data=[], storage_type='memory')
                        ])

The other page(not main app page) where I need the output from the dcc.Store has the layout which looks like this:

delay5_layout = dbc.Container([
    dbc.Row([
        dbc.Col([
            dcc.DatePickerRange(id='DatePickerRange5',
                                start_date=date.today(),
                                end_date=date.today()),
        ]),
    ]),

    html.Br(),

    dbc.Row(id='data_table_delay5',
            children=[]
            ),

], style={'padding': 10})

Your problem is the storage_type. The ‘memory’ store reverts to the default on every page refresh so you have to set the storage_type in other mode/type like ‘session’, because navigate between pages has the same effect that page refreshing.

Check the storage types in:

Store documentation

1 Like

Hey @jeffresh
I tried all three storage types, but it shows the same error.

It’s seems like a page structure problem. Do you have a callback in the same scope than the app.layout that handles the pages content? something like:

@callback(Output('page-content', 'children'),
          Input('url', 'pathname'))
def display_page(pathname: str) -> dbc.Container:

    if pathname == '/':
        return page1.layout
    if pathname == '/page2':
        return page2.layout
    return error_page.layout

Yes, my main page looks like this:

homepage.py

app1 = Dash(**name**, suppress_callback_exceptions=True, external_stylesheets=[dbc.themes.BOOTSTRAP])

app1.layout = html.Div([
dcc.Location(id=‘url’, refresh=False),
html.Div(id=‘page_content’)
])

index_page = dbc.Container([
dbc.Row([…]),
dbc.Row([…]),
dcc.Store(id=‘intermediate_store_data’, data=[], storage_type=‘memory’)
])

@callback(
    Output('intermediate_store_data', 'data'),
    Input('datePickerRange', 'start_date'),
    Input('datePickerRange', 'end_date'),
    Input('dropdown_id', 'value'),
    Input('order_status', 'value'),
    Input('service', 'value')
)
def intermediate_data(a,b,c,d,e):
-------
return

@callback(
    Output'total_order_count', 'children'),
    Input('intermediate_store_data', 'data'),
    
)
def homepage(a):
--------
return

@app1.callback(
    Output('page_content', 'children'),
    Input('url', 'pathname')
)
def display_page(pathname):
    if pathname == '/delay5':
        return delay5_layout
    elif pathname == '/delay10':
        return delay10_layout
    else:
        return index_page

And my other page looks like this:

delay5_report.py

delay5_layout = dbc.Container([
dbc.Row([
dbc.Col([
dcc.DatePickerRange(id=‘DatePickerRange5’,
start_date=date.today(),
end_date=date.today()),
]),
]),

html.Br(),

dbc.Row(id='data_table_delay5',
        children=[]
        ),

], style={‘padding’: 10})

In delay5_report.py, I can’t access the dcc.Store ‘intermediate_store_data’ data. Works fine for homepage.py

@rics - I’m not sure I understand how you are structuring your app, but you could try using pages to make a multi-page app - it’s new in dash 2.5.1. See the updated docs here: Multi-Page Apps and URL Support | Dash for Python Documentation | Plotly

For an example, see the folder multi_page_store/ for an app that shares data between callbacks on different pages using a dcc.Store component.

It’s seems correct so the only thing for me that could be the reason is the imports. But first of all, dont mix @app.callback and @callback dont know if woud be any problem but if you use @callback, use it for your entire app just to keep consistency.

Then I recommend you to import the callbacks of delay_5 within delay5_report.py. Then import delay5_report.py page in homepage.py

The error is because delay5_report5 callback “cannot see” the store. To check that your previous code is correct, try first to copy the code (layout and callbacks) of report_5 in homepage.py. If it works, the error is due to the way thay your are doing your imports.

Hey @jeffresh
I found out the issue. I was using the dcc.Store in my page layout but instead that needs to be defined in the main app layout where url and page-content is defined.

Now I can access the store data from anywhere just as @adamschroeder said.

Thanks both of you! :slight_smile:

1 Like