Skip to content
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

[BUG] dcc.Location callback fires twice IDENTICALLY #1049

Open
schmidt-jake opened this issue Dec 16, 2019 · 36 comments
Open

[BUG] dcc.Location callback fires twice IDENTICALLY #1049

schmidt-jake opened this issue Dec 16, 2019 · 36 comments

Comments

@schmidt-jake
Copy link

schmidt-jake commented Dec 16, 2019

As far as I can tell, this flavor of the "duplicate dcc.Location callback" issue (#883) hasn't been documented yet. When I run a multipage app, reloading the page fires the callback twice with the same href / pathname / search payload. This is distinct from the other issue of having the callback return None and then returning the proper value(s).

import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import dash_bootstrap_components as dbc
import dash
import urllib

navbar = dbc.NavbarSimple(
    brand='Frac Planning App',
    brand_href='/',
    sticky='top',
)

body = dbc.Container(
    dbc.Row(
        dbc.Col(id='page-content')
    )
)

app.layout = html.Div([
    dcc.Location(id='url', refresh=False),
    navbar,
    body
])

@app.callback(Output('page-content', 'children'),
              [Input('url', 'href')],
              [State('url', 'pathname'), State('url', 'search')])
def display_page(href, pathname, search):
    print('HREF:', href)
    print('PATHAME:', pathname)
    print('SEARCH:', search)
    url = urllib.parse.urlparse(href)
    # print('RAW pathname:', url)
    print('TRIGGER(S):', [i['prop_id'] for i in dash.callback_context.triggered])
    if url.path == '/':
        return form.layout
    elif url.path == '/result':
        query = dict(urllib.parse.parse_qsl(url.query))
        return result.plot(**query)
    else:
        raise dash.exceptions.PreventUpdate

Here is the output. It doesn't always print in the same order:

HREF: http://houmedge201:5004/
PATHAME: /
HREF: http://houmedge201:5004/
SEARCH: 
PATHAME: /
TRIGGER(S): ['url.href']
SEARCH: 
TRIGGER(S): ['url.href']

Running on Linux. Versions used:

dash                       1.7.0
dash-core-components       1.6.0
dash-html-components       1.0.2
dash-renderer              1.2.2

I've tried the fix mentioned in #883 (comment) to no avail. Solving this is mission critical for my app because the duplicate callback crashes a subsequent database query.

Changing href via a html.Link makes the callback fire only once. However, users need to be able to share app URLs with query params, which right now is broken due to this bug.

@schmidt-jake schmidt-jake changed the title [BUG] dcc.Location callback fires twice IDENTICALLY [BUG] dcc.Location callback fires twice IDENTICALLY when reload=False Dec 16, 2019
@schmidt-jake schmidt-jake changed the title [BUG] dcc.Location callback fires twice IDENTICALLY when reload=False [BUG] dcc.Location callback fires twice IDENTICALLY Dec 16, 2019
@schmidt-jake
Copy link
Author

Is anyone else experiencing this issue?

@landert
Copy link

landert commented Jan 3, 2020

🙋‍♂️

@abogaard
Copy link

abogaard commented Jan 5, 2020

Me as well

@bfaivre
Copy link

bfaivre commented Jan 16, 2020

Same

@judithbach
Copy link

me too!

@davidolmo
Copy link

davidolmo commented Feb 4, 2020

me too. I tried to avoid the second time execution by using a data_store flag but for some reason, as the states and inputs are exactly the same, this can't be accomplished

@usser123
Copy link

I am experiencing the same issue. Callback with a 'pathname' property as input is being triggered 4 times. The result is that a chart on another page takes a few seconds to appear rather than appear instantly when I click on the button for that page. Critical issue.

jgoday added a commit to jgoday/dash that referenced this issue Feb 18, 2020
@jgoday
Copy link

jgoday commented Feb 18, 2020

I'm experiencing this issue too.
Digging a bit in the source code, it seems a dash-renderer problem with some components default state.
Here is a quick fix to avoid this problem in Location component (jgoday@5681290).

Need to figure out why this is happening with the location component anyway, maybe the real problem resides in dash-core-components/src/components/Loading.react.js ...) 🤔

@danjdo
Copy link

danjdo commented Feb 21, 2020

Is anyone else experiencing this issue?

Me too.

@ndepal
Copy link

ndepal commented Mar 27, 2020

I'm having the same issue on dash 1.9.1.

@BrunoGomesCoelho
Copy link

Having the same issue here unfortunately

@Samreay
Copy link

Samreay commented Mar 31, 2020

Yup, I also get this, very frustrating. Its not firing twice... its a single click on a dcc.Link is firing the change callback EIGHT times. A click on the daily dashboard, ventilation and back to daily gives the following console output:

@app.callback(Output("fluidContainer", "children"), [Input("url", "pathname")])
def display_dashboard(pathname):
    print(pathname)
    return locations.get(pathname)

Gives:

/daily
/daily
/daily
/daily
/daily
/daily
/daily
/daily
/daily
/daily
/ventilation
/ventilation
/ventilation
/ventilation
/ventilation
/ventilation
/ventilation
/ventilation
/ventilation
/ventilation
/daily
/daily
/daily
/daily
/daily
/daily
/daily
/daily
/daily
/daily

@pererumbo
Copy link

I'm facing exactly same situation than Samreay, anyone found the root cause? I've tried with both href and pathname as input but still same behaviour..

@wvwhome
Copy link

wvwhome commented Apr 8, 2020

I tried the first example on the documentation page: http://dash-docs.herokuapp.com/urls
On page reload, the callback runs twice. 04/10/2020: Continues with Dash v1.11.0.

@wvwhome
Copy link

wvwhome commented Apr 17, 2020

4/17/2020: However, Dash 1.11 is a great improvement over Dash 1.10 for chained callbacks with dcc.Location. I have a program with three callbacks. For the page load with Dash 1.10 the sequence was: 3, 2, 1, 1, 3, 2, 3. With Dash 1.11 the sequence is: 1, 1, 2, 3. So much better. I have a dozen other programs with similar improvements.
9/3/2020: Dash 1.16 fixes most of theses issues for my programs -- major improvement.

@rafaelqntn
Copy link

Same here.
I am going to watch this issue.

Thank you for the awesome job with Dash, by the way.

@tjmcdono
Copy link

tjmcdono commented May 1, 2020 via email

@hcai
Copy link

hcai commented Jun 1, 2020

same here

@ghost
Copy link

ghost commented Jun 16, 2020

any updates here? I am currently building a tool based on dash and I have a long process which is triggered by a callback - unfortunately this callback is triggered twice: so now I have to wait extra long for the output

@rusiano
Copy link

rusiano commented Jun 16, 2020

+1

@pkstacey
Copy link

Same issue here, when reading a cookie :/ waste of time and resource. Wondering if this is on the official fixit list for Plotly...

@grahamegee
Copy link

I thought I had a workaround using an lru_cache, but it actually doesn't help that much, as the handler gets called multiple times before the first response gets returned.

grahamegee pushed a commit to limejump/agile-insights that referenced this issue Dec 2, 2020
@Hootie9lives
Copy link

+1

@Paulito123
Copy link

Having the same problem, no fix for this?

@TashaStenner
Copy link

Is there any fix? Or a workaround for this available?

@Stayermax
Copy link

I'm still having this issue with dash 2.3.1, did anybody find working solution?

@Samreay
Copy link

Samreay commented May 25, 2022

@alexcjohnson @T4rk1n sorry for the personal tag, but thought it might be useful to make sure that this issue has some more visibility and is on the roadmap.

I assume its been buried in the backlog in the last two years, but seems like its still an issue for many users.

@luggie
Copy link

luggie commented Oct 17, 2022

Still present in dash 2.6.1 :(

@Samreay
Copy link

Samreay commented Oct 17, 2022

Thankfully there's streamlit instead now to develop in. How can it be three years, a javascript fix posted, and direct dev tags, but not even a comment from any of the core team?

@ned2
Copy link
Contributor

ned2 commented Oct 20, 2022

Hey @Samreay, @luggie, or @Stayermax, do you have a minimal reproducible example of a Dash app that exhibits the Location callback firing twice?

Looking back through the history of the issue, I can't actually find any code that can be used to reproduce the issue, which makes triage/diagnosis of the problem difficult. There are likely other possible causes of duplicate callbacks firing based on custom code/env setup, which would need to be eliminated from possibility.

I had a a go at creating a minimal reproducible example from the original post (which itself was not reproducible), but don't see the behaviour. Do you in your setup? or does the example need to be changed?

from dash import Dash, html, dcc, Input, State, Output

app = Dash(__name__)

app.layout = html.Div([html.Div(id="page-content"), dcc.Location(id="url")])


@app.callback(
    Output("page-content", "children"),
    Input("url", "href"),
    State("url", "pathname"),
    State("url", "search"),
)
def display_page(href, pathname, search):
    print("HREF:", href)
    print("PATHAME:", pathname)
    print("SEARCH:", search)
    if pathname == "/":
        return html.Div(f"HOME - Search: {search}")
    return html.Div(f"{pathname} - Search: {search}")


if __name__ == "__main__":
    app.run_server(debug=True)

@Samreay
Copy link

Samreay commented Oct 21, 2022

Apologies mate, I'm now in a different role at a different company, so don't have access to the source to try and create a minimal example.

@serensoner
Copy link

serensoner commented Oct 23, 2022

Hey @Samreay, @luggie, or @Stayermax, do you have a minimal reproducible example of a Dash app that exhibits the Location callback firing twice?

Looking back through the history of the issue, I can't actually find any code that can be used to reproduce the issue, which makes triage/diagnosis of the problem difficult. There are likely other possible causes of duplicate callbacks firing based on custom code/env setup, which would need to be eliminated from possibility.

I had a a go at creating a minimal reproducible example from the original post (which itself was not reproducible), but don't see the behaviour. Do you in your setup? or does the example need to be changed?

from dash import Dash, html, dcc, Input, State, Output

app = Dash(__name__)

app.layout = html.Div([html.Div(id="page-content"), dcc.Location(id="url")])


@app.callback(
    Output("page-content", "children"),
    Input("url", "href"),
    State("url", "pathname"),
    State("url", "search"),
)
def display_page(href, pathname, search):
    print("HREF:", href)
    print("PATHAME:", pathname)
    print("SEARCH:", search)
    if pathname == "/":
        return html.Div(f"HOME - Search: {search}")
    return html.Div(f"{pathname} - Search: {search}")


if __name__ == "__main__":
    app.run_server(debug=True)

It's been a while since I worked on dash, but I created a minimal repro, but unfortunately only in the older versions:

dash==1.9.0
dash-renderer==1.7.0
Flask==2.0.0
Jinja2==3.0.3
markupsafe==2.1.1
werkzeug==2.0.0
itsdangerous==0.24
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import dash

app = dash.Dash()

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

@app.callback(Output('content', 'children'),
              [Input('url', 'pathname')])
def display_page(pathname):
    print(f'you are now at: {pathname}')
    return pathname

app.run_server(host='0.0.0.0', debug=True)

@Stayermax
Copy link

Stayermax commented Oct 23, 2022 via email

@ned2
Copy link
Contributor

ned2 commented Nov 3, 2022

Thanks heaps @serensoner! I can confirm that your example has duplicate callback invocations, when run with Dash 1.9. However not on the most recent Dash, where there's only one callback invocation. Bisecting suggests that this bug was actually fixed in Dash 1.16.... which was released September 4 2020, interestingly, about the time you were speculating @alexcjohnson that this bug could have been fixed: plotly/dash-core-components#858 (comment)

@alexcjohnson, given we can't identify a reproducible example showing this bug in the latest Dash, maybe this issue should be closed? If someone is able to come up with an example showing it's still there, might be better to start with a fresh issue.

@alexcjohnson
Copy link
Collaborator

@ned2 thanks for digging into this. Good to know at least some of these cases have been fixed! @luggie any chance you can post an app showing the problem you're still seeing? We really need a reproduction case in order to get to the bottom of this. After plotly/dash-core-components#858 (comment) I seem to have felt we had more to do:

The boundaries of the problem have changed a little, as evidenced by this test, but it’s definitely not fixed.

but my comment may just have been based on the preceding comment by @astrowonk rather than having seen the problem myself.

@astrowonk
Copy link

@ned2 thanks for digging into this. Good to know at least some of these cases have been fixed! @luggie any chance you can post an app showing the problem you're still seeing? We really need a reproduction case in order to get to the bottom of this. After plotly/dash-core-components#858 (comment) I seem to have felt we had more to do:

The boundaries of the problem have changed a little, as evidenced by this test, but it’s definitely not fixed.

but my comment may just have been based on the preceding comment by @astrowonk rather than having seen the problem myself.

It's worth noting that whatever I was experiencing was unrelated to this issue. My old comment on the other issue/PR was inaccurate. I am not aware of this issue affecting anything I'm doing at the moment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests