React列表渲染仅展示单条数据,多接口fetch结果被覆盖问题求助
问题根源
- 列表渲染未添加唯一
key属性:React在渲染数组生成的元素列表时,必须为每个子元素指定唯一的key属性,否则Diff算法无法正确识别元素更新,可能出现渲染条目丢失的问题。 - 自定义
useFetch存在状态更新的闭包陷阱:你在异步回调中直接修改并提交同一个result数组引用,React会认为数组没有变化,可能不触发重渲染,或是因为多个异步请求返回顺序不确定,导致状态更新覆盖的问题。 - 修改后的
useFetch未正确使用Promise.all:你把fetch的回调写在Promise.all的map里,但没有返回fetch的Promise,导致Promise.all完全未生效,还是会出现异步更新顺序混乱的问题。
解决方案
1. 给列表渲染添加唯一key
修改ReportComponent代码,给每个Typography元素加唯一key:
function ReportComponent({ data }) { return data.map((datum) => ( // 用唯一标识作为key,如有数据id优先用id <Typography key={datum.name}> {datum.name}: {datum.data} </Typography> )); }
2. 重写useFetch逻辑,修复异步更新问题
正确使用Promise.all等待所有请求完成后再统一更新状态,避免多次更新的闭包问题:
import { useState, useEffect, useRef } from 'react'; const sameContents = (array1, array2) => array1.length === array2.length && array1.every((value, index) => value === array2[index]); function useFetch(urls) { const [data, setData] = useState(null); const [error, setError] = useState(null); const urlsRef = useRef(null); if (!urlsRef.current || !sameContents(urlsRef.current, urls)) { urlsRef.current = urls.slice(); } useEffect(() => { if (!urlsRef.current?.length) { setData([]); return; } const controller = new AbortController(); const { signal } = controller; // 正确返回Promise给Promise.all Promise.all( urlsRef.current.map((url) => fetch(url, { signal, mode: 'cors' }) .then((res) => { if (!res.ok) throw new Error('请求出错'); return res.json(); }) ) ) .then((results) => { if (!signal.aborted) { setData(results); setError(null); } }) .catch((err) => { if (signal.aborted) return; setError(err.message); setData(null); }); // 卸载时取消请求 return () => controller.abort(); }, [urlsRef.current]); return { data, error }; } export default useFetch;
内容的提问来源于stack exchange,提问作者Christina Stebbins
相关产品推荐
相关产品推荐

