React递归组件中修改子项状态时如何保持下拉菜单展开
问题根因
你遇到的展开下拉自动关闭的核心原因是递归组件RecursiveComponent定义在了App组件内部:
- 每次点击复选框触发
setData修改根状态时,App组件都会重新渲染 - 重新渲染时会生成全新的
RecursiveComponent函数实例,React判定这是不同的组件类型,会直接卸载旧组件、挂载新组件 - 旧组件内部存储的
showChildren状态会随着组件卸载被销毁,新挂载的组件showChildren默认值为false,就出现了展开项自动关闭的现象
修复方案
把RecursiveComponent移到App组件外部定义,将需要用到的选中回调方法通过props透传即可,修正后的完整代码如下:
import React, { useState } from "react"; import "./styles.css"; const beData = [ { id: 1, label: "fruit", checked: false, children: [ { id: 23, label: "apples", checked: false }, { id: 21, label: "orange", checked: false } ] }, { id: 32, label: "dairy", checked: false } ]; // 递归组件移到App外部定义,避免重复生成组件实例 const RecursiveComponent = ({ data, onCheck }) => { const [showChildren, setShowChildren] = useState(false); return ( <div> <label style={{ display: "flex", alignItems: "center" }}> <button onClick={() => setShowChildren(!showChildren)} type="button"> v </button> <input checked={data.checked} onChange={() => onCheck(data.id)} type="checkbox" /> <p>{data.label}</p> </label> <div style={{ paddingLeft: "30px" }}> {data.children?.length > 0 && showChildren && data.children.map((child) => ( <RecursiveComponent data={child} key={child.id} onCheck={onCheck} /> )) } </div> </div> ); }; export default function App() { const [data, setData] = useState(beData); const recursiveMap = (data, key) => { return data.map((i) => { let result = { ...i }; if (i.id === key) result = { ...i, checked: !i.checked }; if (i.children?.length) result.children = recursiveMap(i.children, key); return result; }); }; const handleCheck = (key) => setData(recursiveMap(data, key)); return ( <div className="App"> {data.map((item) => ( <RecursiveComponent data={item} key={item.id} onCheck={handleCheck} /> ))} </div> ); }
内容的提问来源于stack exchange,提问作者Bleau
相关产品推荐
相关产品推荐

