React应用使用useEffect与useQueries时出现过度重渲染问题求助
问题分析与解决方案
核心问题拆解
setUploadedImages不生效:useEffect依赖为空数组,不会监听ImagesDate的状态变化,当图片请求完成后无法触发状态更新。- 过度重渲染:每次组件渲染时,
urls是通过data?.data.pictures.map()生成的新数组,导致useImageUpload内的useQueries重复执行,引发不必要的请求和渲染;同时未处理data未加载时的边界情况,可能导致无效计算。
针对性修复方案
1. 修复 useEffect 依赖,触发状态更新
将 ImagesDate 加入 useEffect 的依赖数组,确保图片请求状态变化时能同步更新 uploadedImages,同时增加边界判断避免报错:
2. 稳定 urls 引用,避免 useQueries 重复执行
使用 useMemo 缓存 urls 数组,仅当 data 变化时重新生成,避免每次渲染创建新数组导致 useQueries 重复发起请求。
3. 处理空值边界,避免无效请求
在 useImageUpload 中默认传入空数组,并给每个查询添加 enabled 配置,确保仅当有效 URL 存在时才发起请求。
修改后的完整代码
ShellUpdate 组件:
const ShellUpdate: React.FC = () => { const { id } = useParams(); const { data } = useGetShells(parseInt(id as string)); // 用 useMemo 缓存 urls,仅在 data 变化时更新 const urls = useMemo(() => { return data?.data.pictures?.map((item: { url: string }) => item.url) || []; }, [data]); const ImagesDate = useImageUpload(urls); const [uploadedImages, setUploadedImages] = useState<File[]>([]); useEffect(() => { // 检查所有图片请求是否完成并成功 const allRequestsSuccess = ImagesDate.every(result => result.status === 'success'); if (allRequestsSuccess && ImagesDate.length > 0) { const files = ImagesDate.map(res => res.data).filter(Boolean) as FileWithPath[]; setUploadedImages(files); } }, [ImagesDate]); // 监听 ImagesDate 变化 }
useImageUpload 自定义 Hook:
export const useImageUpload = ( updateInitalImages: string[] = [] ): QueryObserverResult<FileWithPath>[] => { const queryResults = useQueries( updateInitalImages.map(imageUrl => ({ queryKey: [queryKeys.imageData, imageUrl], queryFn: () => getImageFile(imageUrl), enabled: !!imageUrl, // 仅当 URL 有效时发起请求 })) ); return queryResults; };
额外优化建议
- 在
useGetShells中添加enabled: !!id,避免id为空时发起无效请求; - 如果业务允许,可直接使用
ImagesDate中的数据渲染,无需将文件存入state,减少一次状态更新带来的重渲染; - 可通过
ImagesDate.some(result => result.isLoading)统一判断图片加载状态,实现加载中提示。
内容的提问来源于stack exchange,提问作者이호섭
相关产品推荐
相关产品推荐

