fixes aggressive remounting - #3934
Conversation
|
KoolADE85
left a comment
There was a problem hiding this comment.
Good catch, such a sneaky issue!
Mukller
left a comment
There was a problem hiding this comment.
Verified the mechanism against DashWrapper.tsx on master: freshRenders.current += 1 lives in the useMemo(..., [_newRender]) block, so on first mount with _newRender set the counter reaches 1 before the useEffect runs — hence > 1 correctly suppresses the spurious resetComponentState dispatch that caused #3846/#3929. The core fix looks right.
Two edge cases worth considering, plus one request:
1. StrictMode / double-invoked renders. In development React StrictMode can invoke the render pass twice; if both invocations increment the ref before effects flush, freshRenders.current hits 2 on the very first mount and the remount bug resurfaces in dev builds. Does dash-renderer run wrappers under StrictMode anywhere? If yes, an escape hatch like comparing against a "seen first commit" boolean ref instead of counting renders might be more robust:
const didInitialRender = useRef(false);
useEffect(() => {
if (_newRender && didInitialRender.current) {
dispatch(resetComponentState({ itempath: componentPath }));
}
didInitialRender.current = true;
}, [...]);2. Instance reuse across paths. freshRenders never resets when componentPath changes (renderedPath.current = componentPath updates, counter doesn't). If Dash ever recycles a wrapper instance for a different component, the new component's legitimate first _newRender will have counter > 1 and get an immediate state reset. Probably rare, but cheap to guard by resetting the counter (or using the boolean above) when renderedPath.current !== componentPath.
3. Tests. The diff is 1 line — could you add a renderer test reproducing the #3846 sequence (initial render must not dispatch resetComponentState) so it stays fixed?
Nice find either way — the root cause (reset firing on first render) matches both linked issues precisely.



fixes:
Issue was that on the first render of a component, it would trigger it to remount and clear the
layoutHashessince it wasnt protected to see if it was the very first time that the component was rendering.