✊🏿 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!

Why the app with circular dependencies doesn't work?

Hello everyone.
I have an app which has to download a lot of data. For convenience I’m trying to download the data bit by bit and store itermediate results in dcc.Store element.
The data is a python dictionary, and my idea was to download one key at a time.
After “submit” button is clicked, the app downloads first key and updates Store coponent. After that, as I hoped, the callback “update_index” would be fired again, because the “data” parameter has changed. However, this callback is not fired for the second time. Another callback – “test_callback”, that has the same “data” input, does get fired.
The only thing I could think about is the fact that these callbacks fire each other. Am I identifying the issue correctly and what can be done to achieve the result I want? Thanks!

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
from flask import Flask
import time

server = Flask('app')
app = dash.Dash(__name__,
                server=server)

app.layout = html.Div([
    dcc.Store(id='data'),
    html.Div(id='current_index'),
    html.Button(id='submit', n_clicks=0, children='Submit'),
    html.Div(id='test_div')
    ])


@app.callback(
    Output('data', 'data'),
    [Input('current_index', 'children')],
    [State('data', 'data')]
)
def download_data(current_index, stored):
    data = {
        '0': [1, 2, 3],
        '1': [2, 3, 4],
        '2': [3, 4, 5]
    }
    if current_index is not None:
        if stored is None:
            stored = {}
        print('downloading', current_index)
        time.sleep(1)
        stored[str(current_index)] = data[str(current_index)]
    return stored


@app.callback(
    Output('current_index', 'children'),
    [Input('submit', 'n_clicks'),
     Input('data', 'data')],
    [State('current_index', 'children')]
)
def update_index(n_clicks, data, current_index):
    ctx = dash.callback_context
    print(ctx.triggered)
    if n_clicks > 0:
        new_index = 0
    else:
        if data is not None:
            new_index = current_index + 1
            if new_index > 2:
                raise PreventUpdate
        else:
            new_index = None
    return new_index


@app.callback(
    Output('test_div', 'children'),
    [Input('data', 'data')],
)
def test_callback(data):
    if data is not None:
        return 'Test callback fired'


if __name__ == '__main__':
    app.run_server(debug=True, host='0.0.0.0', port=4202)