使用dnd-kit-sortable-tree时输入框输字符即失焦求助
解决dnd-kit-sortable-tree输入框输入时失焦的问题
问题原因分析
输入框每输入一个字符就失焦,核心原因有两点:
- 内联TreeItemComponent触发组件频繁卸载/挂载:你在
SortableTree中用内联函数作为TreeItemComponent的取值,每次父组件因state更新重渲染时,这个内联函数会生成新的组件引用。dnd-kit会判定树项组件发生变化,卸载旧的TreeItem实例并挂载新实例,导致输入框失去焦点。 - 局部state与全局state不同步:TreeItem内部维护了
sample局部state,当全局items更新后,局部state未及时同步,即使手动调用focus也会因为组件重新挂载失效。
修复方案
1. 避免内联传递TreeItemComponent
将TreeItem组件直接传递给TreeItemComponent prop,额外的回调函数通过extraProps传递,确保组件引用稳定,避免频繁重建。
2. 移除TreeItem的局部state
直接使用全局state中的props.item.value作为输入框的值,消除状态不一致问题,同时减少不必要的重渲染。
3. 用useCallback包裹状态更新函数
优化回调函数的引用稳定性,减少父组件重渲染对树项的影响。
修改后的完整代码
import React, { useState, useRef, useCallback } from "react"; import { SimpleTreeItemWrapper, SortableTree } from "dnd-kit-sortable-tree"; import sizeof from "object-sizeof"; export default function NestedSortableTree() { const [items, setItems] = useState(initialViableMinimalData); console.log(sizeof(items), items, "bytes"); // 用useCallback包裹,保持函数引用稳定 const handleItemChange = useCallback((itemId, newValue) => { setItems((prevItems) => { const updateItems = (nodes) => nodes.map((node) => { if (node.id === itemId) { return { ...node, value: newValue }; } if (node.children) { return { ...node, children: updateItems(node.children) }; } return node; }); return updateItems(prevItems); }); }, []); return ( <SortableTree items={items} onItemsChanged={setItems} TreeItemComponent={TreeItem} extraProps={{ onItemChange: handleItemChange }} // 传递额外回调 /> ); } const TreeItem = React.forwardRef((props, ref) => { const inputRef = useRef(null); const onChange = (event) => { const newValue = event.target.value; props.onItemChange(props.item.id, newValue); }; return ( <SimpleTreeItemWrapper {...props} ref={ref} disableCollapseOnItemClick> <input ref={inputRef} className="border" value={props.item.value} // 直接使用全局state的值 onChange={onChange} /> </SimpleTreeItemWrapper> ); }); const initialViableMinimalData = [ { id: 1, value: "Jane", children: [ { id: 4, value: "John", type: "text" }, { id: 5, value: "Sally" }, ], }, { id: 2, value: "Fred", children: [ { id: 6, value: "Eugene", children: [ { id: 7, value: "John" }, { id: 8, value: "Sally" }, ], }, ], }, { id: 3, value: "Helen" }, ];
额外说明
- 去掉内联组件后,TreeItem的引用保持稳定,dnd-kit不会再频繁卸载/挂载树项,输入框焦点得以正常保留。
- 直接使用全局state的值,避免了局部state与全局state的同步问题,输入响应更直接流畅。
内容的提问来源于stack exchange,提问作者ch3t
相关产品推荐
相关产品推荐

