Repository navigation
Serious performance issues related to React context #3057
Description
When using components associated with the XxxProvider, severe performance issues can arise when there is a large amount of page content. Here are some examples related to well-known component libraries in the Dash ecosystem:
- with
dmc
In dmc, it is required that the application be wrapped inside the MantineProvider. With the React Developer Tools, you can see that any interaction with an internal component will trigger a re-render of all components on the current page.

import dash_mantine_components as dmc
from dash import Dash, _dash_renderer
_dash_renderer._set_react_version("18.2.0")
app = Dash(external_stylesheets=dmc.styles.ALL)
app.layout = dmc.MantineProvider([dmc.Button("test", style={"margin": 5})] * 200)
if __name__ == "__main__":
app.run(debug=True)Even placing components from dcc under the MantineProvider will cause the same issue:

import dash_mantine_components as dmc
from dash import Dash, _dash_renderer, dcc
_dash_renderer._set_react_version("18.2.0")
app = Dash(external_stylesheets=dmc.styles.ALL)
app.layout = dmc.MantineProvider([dcc.Input(style={"margin": 5})] * 200)
if __name__ == "__main__":
app.run(debug=True)- with
fac
In fac, the similar component AntdConfigProvider is not a must-use, but the same issue will also occur:

import dash
from dash import html
import feffery_antd_components as fac
app = dash.Dash(__name__)
app.layout = html.Div(
fac.AntdConfigProvider(
[fac.AntdButton("test", type="primary", style={"margin": 5})] * 100
)
)
if __name__ == "__main__":
app.run(debug=True)However, the issue of global re-rendering does not occur with components within html, such as for html.Div (which has the functionality to update the click event to the component's n_clicks property):
- with
dmc
import dash_mantine_components as dmc
from dash import Dash, _dash_renderer, html
_dash_renderer._set_react_version("18.2.0")
app = Dash(external_stylesheets=dmc.styles.ALL)
app.layout = dmc.MantineProvider(
[html.Div(style={"height": 25, "border": "1px solid black", "marginBottom": 5})]
* 100
)
if __name__ == "__main__":
app.run(debug=True)- with
fac
import dash
from dash import html
import feffery_antd_components as fac
app = dash.Dash(__name__)
app.layout = html.Div(
fac.AntdConfigProvider(
[html.Div(style={"height": 25, "border": "1px solid black", "marginBottom": 5})]
* 100
)
)
if __name__ == "__main__":
app.run(debug=True)I hope to receive more help on this issue, to explore the deeper reasons and possible solutions.
Activity
T4rk1n commentedon Nov 4, 2024
The onClick is only added if there is an id, if you add an id it trigger the setProps all the time and the context get changed.
I think the culprit is here:
dash/dash/dash-renderer/src/reducers/layout.js
Line 18 in 7afb2ed
It's a new layout object on every prop change, the topmost component is thus always updated.
BSd3v commentedon Nov 4, 2024
I noticed this back when using dmc 0.12, however, I utilized a workaround that will no longer work due to the dependence of
MantineProvider.Here is an example that is even slower for me:
Any selection change takes about 1 second to render.
T4rk1n commentedon Nov 4, 2024
If you change here:
dash/dash/dash-renderer/src/reducers/layout.js
Lines 15 to 18 in fa7d30a
For
Then only the component props will be updated in the redux store. But then the component doesn't update the props since they are passed down from the top components to the bottom, this is how it got the new props.
We'll need to change the way the components get their props by using a selector on the redux state instead of the props being passed down. This can be done like:
When the props is updated it trigger the re-render in that selector only for that component. Just need to find a way (or refactor
TreeContainer.jsentirely) to use those props instead of thepropsbeing passed from the top of the tree.gvwilson commentedon Feb 6, 2025
Included in Dash 3.0 release candidate