Preserve imperative tree.update() props across node toggles#337
Conversation
There was a problem hiding this comment.
Pull request overview
Ports and updates the fix for #228/#229 to the current modules/ layout by separating “sync TreeApi props from React props” from “rebuild visible nodes on open/close changes”, so imperative tree.update() calls don’t get overwritten when nodes are toggled.
Changes:
- Removed
state.nodes.openfrom the “sync fromtreeProps” update dependencies. - Added a second memo keyed on
state.nodes.openthat rebuilds visible nodes usingapi.propsto preserve imperative updates.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| /* Rebuild visible nodes when open state changes, without clobbering | ||
| props set imperatively via api.update(). */ | ||
| useMemo(() => { |
There was a problem hiding this comment.
Good catch — you nailed it. CI surfaced the same regression and the amended commit (33e6de2) now bumps updateCount.current in the open-state memo as you suggested. Verified locally with the gmail-spec e2e (12/12 passing).
When a consumer calls tree.update() via the imperative handle, those props live on api.props. The existing useMemo re-ran on state.nodes.open changes and called api.update(treeProps), reverting api.props to the parent's React props and losing any imperative changes. Split into two effects: one syncs from treeProps, the other rebuilds visible nodes on open-state changes using api.props. Co-Authored-By: iamyunsin <yunsin@vip.qq.com> Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
6255487 to
33e6de2
Compare
Adds jest-environment-jsdom, @testing-library/react, and a React dev dependency for testing. Switches the jest testEnvironment to jsdom and adds a regression test that renders <Tree>, calls api.update() via the imperative ref to change rowHeight, then opens a node — verifying the imperative prop survives the resulting state.nodes.open change. The test fails on main (without the jameskerr#337 fix) and passes with it. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Force-pushed an amended commit that fixes a regression caught by CI. What was wrong: the original split- Fix: bump Verified locally: |
Adds jest-environment-jsdom, @testing-library/react, and a React dev dependency for testing. Switches the jest testEnvironment to jsdom and adds a regression test that renders <Tree>, calls api.update() via the imperative ref to change rowHeight, then opens a node — verifying the imperative prop survives the resulting state.nodes.open change. The test fails on main (without the jameskerr#337 fix) and passes with it. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Picks up #229 from @iamyunsin (which targeted the old
packages/path and went stale), ports the fix to the currentmodules/layout, and credits the original author viaCo-Authored-By.The bug
Closes #228 (partially — see Notes).
TreeProviderhad a singleuseMemothat re-ran on eithertreePropschanges orstate.nodes.openchanges, always callingapi.update(treeProps). That meant any prop a consumer set imperatively viatree.update({ ... })would be reverted to the parent's React props the next time a node was toggled.The fix
Split the effect:
useMemosyncs fromtreeProps(same as before, minus the open-state dep).useMemorebuilds visible nodes onstate.nodes.openchanges usingapi.props— preserving any imperative changes.Backward compatible: when no one calls
api.update()imperatively,api.props === treeProps, so behavior is unchanged.Notes
tree.update()''does not take effect immediately.'' That's a separate issue —api.update()mutatesthis.propsbut doesn't dispatch a Redux action, souseSyncExternalStoredoesn't notify. That requires a different fix and isn't in scope here.TreeApiunit test. Reproducing this bug requires React component rendering (jsdom +@testing-library/react), which is a larger infra change. Happy to do that in a follow-up if you'd like.🤖 Generated with Claude Code