在useEffect Hook中设置状态异常:无法存入对象数组至postMItems
React状态postMItems无法正确填充数组的问题解决
我需要将React状态postMItems设置为对象数组,现有代码能通过接口获取的数据正确填充临时数组existingM,但无法将相同数据存入postMItems状态。原代码如下:
const [postMItems, setPostMItems] = useState([]); let existingM = [] useEffect(() => { const fetchMItems = async () => { const endpoint = `http://${process.env.NEXT_PUBLIC_HOST}:1337/api/manufactureds?fields[0]=title&sort=id:ASC&populate[image][fields][0]=name&populate[image][fields][1]=url` const options = { method: 'GET', headers: { 'Authorization': `Bearer ${process.env.NEXT_PUBLIC_API_TOKEN}` } } const response = await fetch(endpoint, options) const data = await response.json(); console.log(data); for (let i = 0; i < data.data.length; i++) { let mID = data.data[i].id let mName = data.data[i].attributes.title let mImage = data.data[i].attributes.image.data ? data.data[i].attributes.image.data.attributes.url : '' setPostMItems([ ...postMItems, { mID: mID, mName: mName, mImage: mImage } ] ) console.log(postMItems); existingM.push( { mID: mID, mName: mName, mImage: mImage } ) } console.log(existingM) console.log(postMItems) } fetchMItems(); }, []);
问题原因
- React状态更新是异步的,加上
useEffect依赖为空数组,循环中每次调用setPostMItems时,引用的postMItems都是初始的空数组(闭包捕获了组件首次渲染时的状态),最终状态只会保留最后一次添加的元素。 - 循环内多次触发状态更新会导致组件重复重渲染,既影响性能也容易引发逻辑问题。
解决方案
直接将接口返回的数据处理成完整的目标数组,再一次性设置状态,这是最可靠高效的方式:
const [postMItems, setPostMItems] = useState([]); useEffect(() => { const fetchMItems = async () => { const endpoint = `http://${process.env.NEXT_PUBLIC_HOST}:1337/api/manufactureds?fields[0]=title&sort=id:ASC&populate[image][fields][0]=name&populate[image][fields][1]=url`; const options = { method: 'GET', headers: { 'Authorization': `Bearer ${process.env.NEXT_PUBLIC_API_TOKEN}` } }; const response = await fetch(endpoint, options); const data = await response.json(); // 用map遍历数据,直接生成目标数组 const newPostMItems = data.data.map(item => { const mID = item.id; const mName = item.attributes.title; const mImage = item.attributes.image.data ? item.attributes.image.data.attributes.url : ''; return { mID, mName, mImage }; }); // 一次性更新状态 setPostMItems(newPostMItems); console.log(newPostMItems); // 此时数组内容和原代码的existingM完全一致 }; fetchMItems(); }, []);
另一种可选方式(不推荐用于此场景)
如果特殊场景下需要在循环中更新状态,可以使用函数式更新,它会接收当前最新的状态作为参数,确保每次更新都基于最新值:
// 仅作示例,推荐使用上面的一次性更新方式 for (let i = 0; i < data.data.length; i++) { const mID = data.data[i].id; const mName = data.data[i].attributes.title; const mImage = data.data[i].attributes.image.data ? data.data[i].attributes.image.data.attributes.url : ''; setPostMItems(prevState => [...prevState, { mID, mName, mImage }]); }
内容的提问来源于stack exchange,提问作者H_alt
相关产品推荐
相关产品推荐

