React结合React-RND与DevExtreme TabPanel时,子组件更新状态引发输入框失焦且文本不更新的问题
React结合React-RND与DevExtreme TabPanel时,子组件更新状态引发输入框失焦且文本不更新的问题
嘿,我之前也碰到过类似的坑!这种输入框失焦+文本不更新的情况,大概率是组件重渲染时DOM被重新创建导致的,咱们一步步来排查解决:
首先排查最常见的问题:不稳定的key值
React靠key来识别组件的身份,如果你的RND元素或者DroppableBox子组件的key用了索引(比如index)或者每次渲染都会变化的值,状态更新后React会直接卸载旧组件、挂载新组件,输入框自然就失焦了。
解决办法:给每个列表项用稳定且唯一的key,比如你数组里每个对象的id字段:
{tabPanelData.map(tab => ( <TabPanelItem key={tab.id}> {tab.contents.map(item => ( <RND key={item.id} {...rndProps}> <DroppableBox item={item} updateTabPanelText={updateTabPanelText} /> </RND> ))} </TabPanelItem> ))}
然后优化状态更新函数的稳定性
如果你的updateTabPanelText函数每次父组件渲染都会重新创建,子组件会因为props变化触发不必要的重渲染,也会导致输入框失焦。
用useCallback把这个函数包裹起来,只在依赖项变化时重新生成:
import { useCallback } from 'react'; // 父组件中定义 const updateTabPanelText = useCallback((tabId, itemId, newText) => { setTabPanelData(prevData => { return prevData.map(tab => { if (tab.id !== tabId) return tab; return { ...tab, contents: tab.contents.map(item => item.id === itemId ? {...item, text: newText} : item ) }; }); }); }, []); // 这里的依赖项根据实际情况调整,用函数式更新可以减少依赖
让子组件避免不必要的重渲染
给DroppableBox套个memo,这样只有当props真正变化时才会重新渲染:
import { memo } from 'react'; const DroppableBox = memo(({ tabId, updateTabPanelText, item }) => { return ( <input type="text" value={item.text} onChange={(e) => updateTabPanelText(tabId, item.id, e.target.value)} /> ); });
最后检查DevExtreme TabPanel的配置
有些TabPanel会默认卸载未激活的标签页内容,切换回来时重新渲染组件,这也会导致输入框失焦。你可以查下DevExtreme的文档,看看有没有类似keepTabContent或者cacheEnabled这类属性,开启它来保留标签页的DOM结构。
按照这个顺序排查下来,应该就能解决输入框失焦和文本不更新的问题啦!
备注:内容来源于stack exchange,提问作者Faizan Ansari
相关产品推荐
相关产品推荐

