React中useState初始化selectionNames为空数组问题排查
问题根因
useState的初始值仅在组件首次渲染时生效。组件第一次渲染时names的初始值是空数组[],此时执行init(names)传入的参数就是空数组,得到的selectionNames初始值自然是空数组。- 后续
useEffect中接口请求返回、调用setNames更新names时,useState(init(names))不会重复执行,selectionNames不会随names自动更新,因此控制台打印结果始终为空数组。 - 你之前尝试直接在
useEffect中修改names添加selected字段的方案无法运行,核心是两个问题:一是接口请求是异步的,组件同步执行阶段拿不到接口返回的数据;二是React状态必须通过对应的setState方法更新才会触发重渲染,直接修改状态对象本身不会同步到视图。
修复方案
方案1:单状态维护(推荐,匹配你最初的设计思路)
不需要同时维护names和selectionNames两个状态,直接在接口返回数据后一次性处理好selected字段,存入单个状态即可:
export default function Display() { // 直接存储带selected字段的列表,无需额外存原始names数据 const [selectionNames, setSelectionNames] = useState([]) useEffect(() => { axios.post("") .then(res => { // 拿到接口数据第一时间做格式化,添加selected字段 const processedList = res.data.names.map((item) => { return { ...item, types: item.types.map((t) => ({ ...t, selected: true })) }; }); setSelectionNames(processedList) }) .catch(err => { console.log(err) }) }, []); const change = (id, item, value) => { setSelectionNames((s) => s.map((currItem) => { // 在这里写你原有的选中状态更新逻辑即可 if (currItem.id !== id) return currItem; // 其余字段更新逻辑... return currItem; })); }; return ( <> {selectionNames.map((item) => /* 原有渲染逻辑 */)} </> ); }
方案2:保留双状态,增加联动逻辑
如果你确实需要保留原始names状态做其他逻辑处理,可以新增一个监听names的useEffect,在names拿到接口数据后再初始化selectionNames:
export default function Display() { const [names, setNames] = useState([]) const [selectionNames, setSelectionNames] = useState([]); useEffect(() => { axios.post("") .then(res => { console.log(res) setNames(res.data.names) }) .catch(err => { console.log(err) }) }, []); // 监听names变化,接口返回数据后同步初始化selectionNames useEffect(() => { if (names.length === 0) return; const processed = names.map((item) => { return { ...item, types: item.types.map((t) => ({ ...t, selected: true })) }; }); setSelectionNames(processed); }, [names]) const change = (id,item, value) => { setSelectionNames((s) => s.map((item) => { /* 原有选中更新逻辑 */ return item; })); }; return ( <> {selectionNames.map((item) => /* 原有渲染逻辑 */)} </> ); }
额外提醒:你贴的代码存在两处笔误,运行前需要修正:一是
init函数里写的{..item}是语法错误,对象展开运算符需要写三个点即{...item};二是change函数里调用的setSelectionStandards和你定义的状态更新方法setSelectionNames命名不一致,会导致选中逻辑失效,需要统一命名。
内容的提问来源于stack exchange,提问作者ZPaulB
相关产品推荐
相关产品推荐

