fix(tree): stale closure in React.memo causing sibling folder collapse#1015
Merged
Merged
Conversation
onNodeChange in Tree was re-created every render with the current tree in its closure. Node.tsx uses React.memo with an isEqual that does not compare the onChange prop, so when a node's data hasn't changed it retains the old onNodeChange handler. The old handler's closure captures a stale tree snapshot that doesn't include subsequent collapse/expand operations on sibling folders. When invoked, cloneDeep(oldTree) rewinds other folders to their previous state, causing them to auto-collapse. Fix: wrap onNodeChange in useCallback([], ...) with a stable ref (treeRef) so the function identity never changes, but always reads the latest tree via the ref. Closes #1014
beyond-infra
force-pushed
the
fix/folder-collapse-stale-closure
branch
from
July 3, 2026 17:11
0f9ea76 to
bec0819
Compare
… test
The stale-closure fix assigned treeRef/onChangeRef during render, which
trips eslint's react-hooks/refs ("Cannot update ref during render").
Move the assignments into an effect; behavior is unchanged because the
refs are only read from event handlers, which fire after commit.
Also add a Tree.test.tsx regression for #1014: collapsing one folder
must not revert a sibling folder's collapse state.
Owner
|
感谢! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题
展开一个文件夹后,其他已展开的文件夹被自动折叠。Closes #1014。
根因
Node.tsx使用React.memo,其isEqual比较函数不检查onChange(即onNodeChange)prop 是否变化。当一个 Node 的data未变时,React.memo 复用旧 VNode,保留了旧的onNodeChangehandler。旧 handler 的闭包中
tree是创建时的快照,不包含之后其他文件夹的折叠/展开操作。当该 handler 被调用时,cloneDeep(旧tree)将其他文件夹的状态回退到过去的值。触发链路
修复
Tree.tsx中onNodeChange改为useCallback+ref:useCallback空依赖保证函数引用永不变(React.memo 稳定),内部通过 ref 始终读取最新tree和onChange。