-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Improve performance of context components re-rendering #3066
base: dash-3.0
Are you sure you want to change the base?
Conversation
The test_redraw shows failure with 5 redraw instead of 2. There is two cases of additional redraw that need to be fixed in this pr:
|
{Array.isArray(layout) ? ( | ||
layout.map((c, i) => | ||
isSimpleComponent(c) ? ( | ||
c | ||
) : ( | ||
<TreeContainer | ||
<DashWrapper |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, new component - is this going to break any legacy code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it shouldn't as this is an internal component.
@@ -1,4 +1,4 @@ | |||
type Config = { | |||
export type DashConfig = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 for the name change - why does it have to be exported?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is used in the new DashWrapper.tsx.
@@ -26,6 +26,18 @@ export const apiRequests = [ | |||
'loginRequest' | |||
]; | |||
|
|||
function callbackNum(state = 0, action) { | |||
// With the refactor of TreeContainer to DashWrapper |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thank you for the explanation
@@ -0,0 +1,425 @@ | |||
import React, {useMemo, useCallback} from 'react'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I'm going to trust you on this - I don't know enough of Dash and TypeScript to review something this large. @emilykl can you please have a look? (who else might be a good reviewer?)
I think for the additional redraw might be coming from the new path, before it was |
Hi. Are there any updates on this? |
I ran the dmc-docs using this branch, and it's much faster! Thanks so much for doing this PR. This will make large apps using DMC perform much better. On the import dash_mantine_components as dmc
from dash import Dash, _dash_renderer
_dash_renderer._set_react_version("18.2.0")
from dash_iconify import DashIconify
app = Dash(external_stylesheets=dmc.styles.ALL)
app.layout = dmc.MantineProvider(
dmc.Checkbox(
label="Custom checked icon",
checked=True,
icon=DashIconify(icon="ion:bag-check-sharp"),
size="lg",
)
)
if __name__ == "__main__":
app.run(debug=True)
Here's one of the error messages (There are a few more as well)
UpdateIt's not just the DashIconify library. It's not possible to pass any components to the icon prop: import dash_mantine_components as dmc
from dash import Dash, _dash_renderer, html
_dash_renderer._set_react_version("18.2.0")
FONT_AWESOME = "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
app = Dash(external_stylesheets=[FONT_AWESOME])
app.layout = dmc.MantineProvider([
html.I(className="fa-solid fa-bag-shopping fa-3x"),
dmc.Checkbox(
label="Custom checked icon",
checked=True,
icon=html.I(className="fa-solid fa-bag-shopping fa-3x"),
size="lg",
)
])
if __name__ == "__main__":
app.run(debug=True) |
@AnnMarieW I removed the |
@T4rk1n Thanks for your speedy response. I updated to use Update: Actually it doesn't work 😢 It doesn't throw errors, but it doesn't render correctly 🤔 |
There's one other user of |
I removed the The proper way to handle this kind of pattern (send data up/down stream the component tree) in react is with context components, which this PR fixes their performance. |
Thanks for the suggestion of using context instead. We are using the You make a good point here:
Given that this PR substantially increases performance, would you consider keeping the |
Yes, I'll put it back since it's used everywhere. There could be an alternative |
This would be awesome:
❤️ ❤️ |
Not sure I can add back those props in the way it was, there was another component in between the TreeContainer and the library component that is not longer the case. Might need to refactor the new Wrapper to have a middle component but that changes the order of renders and is not as optimal as a single component since it add overhead. |
And I think now with this to access the child props the new path would be just without a level and the |
Actually, the props are not there anymore in the wrapper, they are now gotten from the selector, so the old hack cannot work anymore with this solution. |
Is there a "new hack" that might be easier than using context? |
A Context solution might only be valid in some cases, for the mantine checkbox case, it want to add extra props to the component. I see a couple solution for those cases:
For accessing the props (dcc.Tabs cases), a new |
I have a question about the |
I added the |
@AnnMarieW This will be ready for merge, I'd like to get the api right before and I am thinking of one last minute change. Putting |
I agree - it would be more consistent. Is there any use-case for the |
@@ -73,6 +73,11 @@ const Textarea = ({ | |||
); | |||
}; | |||
|
|||
Textarea.dashPersistence = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this the recommended way of setting default for persistence?
It will only work in Dash >=3 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, only for dash>=3 for support of the persistence props that was previously in defaultProps
in functional components and react 18.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it work in dash< 3 to have the default for persistence set in the function signature? If not, we should check if Dash 3.0 is being use and if not use defaultProps
? Is the best way to check for Dash 3.0 by seeing if window.dash_component_api
exists?
I also I get an error when trying to set default props in the function signature when the prop is a required prop by Mantine. This might be a separate issue, but do you know how to handle that case?
This is the error, it's like the prop is not getting passed to Mantine, even though it's defined with a default in the function:
"TypeError: Required argument opened was not specified."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it work in dash< 3 to have the default for persistence set in the function signature?
No it doesn't work since the check is explicit on the defaultProps
.
Is the best way to check for Dash 3.0 by seeing if window.dash_component_api exists?
Yes that is the quickest check.
"TypeError: Required argument opened was not specified."
This an error on the Python side of the component, it should have a check if a required prop has a default in the metadata. If you built the components on this branch before I merged 3.0 yesterday might just need to rebuild with the latest changes.
I don't think so, it requires the componentPath which is not something the clientside callbacks would really know about. |
Fix #3057
Gif showing only the clicked button is re-rendered: