-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
[charts] Fix LineChart
animation being stuck with initial drawing area value
#14553
[charts] Fix LineChart
animation being stuck with initial drawing area value
#14553
Conversation
Deploy preview: https://deploy-preview-14553--material-ui-x.netlify.app/ |
CodSpeed Performance ReportMerging #14553 will not alter performanceComparing Summary
|
…unknown-width-behaviour
// This effect is used to compute the size of the container on the initial render. | ||
// It is not bound to the raf loop to avoid an unwanted "resize" event. | ||
// https://github.com/mui/mui-x/issues/13477#issuecomment-2336634785 | ||
useEnhancedEffect(() => { | ||
// computeRun is used to avoid infinite loops. | ||
if (!stateRef.current.initialCompute || stateRef.current.computeRun > 20) { | ||
return; | ||
} | ||
|
||
const computedSize = computeSize(); | ||
if (computedSize.width !== width || computedSize.height !== height) { | ||
stateRef.current.computeRun += 1; | ||
} else if (stateRef.current.initialCompute) { | ||
stateRef.current.initialCompute = false; | ||
} | ||
}, [width, height, computeSize]); |
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.
Could you describe the behavior with for example what is currently happening step by step, and how this PR modify it?
I don't huderstand how adding a useEnhancedEffect
could help to prevent inifint loop.
If you want a nice reproduction of an infinit loop there is one here:
#12263 (comment)
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.
This useEffect doesn't prevent an infinite loop. Only computeRun > 20
does. It serves as a circuit breaker in case the layout never settles into a defined size, which would mean this useEffect would run indefinitely.
This useEffect only happens before/during
the first render, when the page layout is figuring out what size the components need. Hence it is different from the issues in your example, where the loop in on the render side.
To fix the loop in your example, we can try to handle it on the useEnhancedEffect
that has the ResizeObserver
inside. Though I'm not sure how useful it would be, since my current fix is only for layouts that will definitely settle into a defined width/height, but your example will never settle 😓
Explanation of what it does
The main idea of this useEnhancedEffect
is that everything in it will happen before we see anything, since it is running on the layout effect and committing changes to the state, the state will update synchronously.
The state updates until it settles on a size (new size is the same as last one) or it runs more than 20 times (usually it only requires 5-6 runs from what I tested).
Once one of these two conditions are met, the hook stops looping (width/height stop changing), and the first actual react render happens.
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.
I'm ok with the solution. But this will silently delay the painting without warning the developers about the improvement they could bring. We should add at least a warning if computeRun > 2
We can not do computeRun > 0
because the react strict mode trigger twice the useLayoutEffect. Si the ref
is updated twice before the state get updated.
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.
I had added a warning at first but thought it could be unnecessary and removed it 😅
Will add it back
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.
Hum, I actually removed it because it is an actual valid behaviour that wouldn't require a warning. 🤔
Like, if the user uses this inside a grid, this will always warn, even though a grid's width would eventually settle in the screen's width.
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 an actual valid behaviour
I disagree on this point. For me the valid behavior is "The container has a defined size". This PR is adding a nice fallback
I tried with Recharts and they have the same behavior as us currently.
Capture.video.du.2024-09-16.10-02-01.mp4
From my point of view it would be bad to have such loop without informing user since it silently fix something the developers could potentially do better.
In addition to a warning, it could be a warning plus a prop to silence the warning. Or no warning and a prop to activate the feature
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.
As "valid behaviour" I mean it is something the browser does on its own. Not that our behaviour is valid 😅
I would agree with a prop for this though.
Something like:
/**
* The chart will try to wait for the parent container to resolve its size
* before it renders for the first time.
*
* This can be useful in some scenarios where the chart appear to grow after
* the first render, like when used inside a grid.
*/
resolveSizeBeforeRender
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.
Good for me. We will see if we get issues about this. In such case, adding a paragraph about this prop in the docs could be the next step
Should improve the behaviour of #13477 when animations are enabled or not 😅
This fix is comprised of two parts
chart slowly expanding
render to happenWhile
#2
is not an issue of the chart per-se, we can make it work by adding some additional behaviour to theuseChartContainerDimensions
hook, so it calculates the necessary size it should takebefore
the first render, while trying to prevent an infinite loop in case the layout can't coalesce into a defined size.