Next.js 12项目函数重复渲染过多问题求助
问题求助:React组件重复渲染+子元素内调用函数错误
项目环境
使用Next.js 12,package.json配置如下:
{ "name": "next12firebase", "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint" }, "dependencies": { "eslint": "8.28.0", "eslint-config-next": "13.0.5", "firebase": "^9.14.0", "next": "13.0.5", "react": "18.2.0", "react-dom": "18.2.0", "react-firebase-hooks": "^5.1.1", "react-icons": "^4.7.1" }, "devDependencies": { "autoprefixer": "^10.4.13", "postcss": "^8.4.19", "tailwindcss": "^3.2.4" } }
需求
通过react-firebase-hooks的useCollectionData获取数据,当loading变为false后,执行数据处理逻辑,将结果存入datamap状态,后续用该状态遍历渲染内容。
当前代码问题
当前在JSX渲染逻辑中直接处理数据并调用setDatamap,导致两个核心错误:
- 每次渲染都会触发状态更新,引发无限重复渲染
- 在React子元素内调用状态更新函数,违反React渲染规则
当前临时代码:
export default function portfolio() { // ...省略其他代码 const [docs, loading, error] = useCollectionData(q); return ( // ...省略其他渲染内容 {!loading && docs.map((doc) => { console.log(doc) let tic = doc.stockTicker let data = { shares: doc.shares, price: doc.price, type: doc.type } let map = datamap; console.log(datamap) if(Array.from(datamap.keys).includes(tic) === false) { setDatamap(datamap.set(tic, [data])); console.log(tic + " " + data) } else { setDatamap((map.get(tic)).push(data)) } console.log(datamap) }) } // ...省略其他渲染内容 ) }
解决方案
将数据处理逻辑移至useEffect钩子中,仅在loading结束且数据更新时执行,同时保证状态更新的不可变性:
export default function Portfolio() { const [docs, loading, error] = useCollectionData(q); const [datamap, setDatamap] = useState(new Map()); // 监听loading和docs变化,处理数据 useEffect(() => { if (!loading && docs?.length) { // 创建新Map,避免直接修改原状态 const updatedMap = new Map(datamap); docs.forEach(doc => { const stockTicker = doc.stockTicker; const itemData = { shares: doc.shares, price: doc.price, type: doc.type }; if (updatedMap.has(stockTicker)) { // 用扩展运算符创建新数组,保证引用更新 const existingItems = updatedMap.get(stockTicker); updatedMap.set(stockTicker, [...existingItems, itemData]); } else { updatedMap.set(stockTicker, [itemData]); } }); setDatamap(updatedMap); } }, [loading, docs]); // 依赖项:loading或docs变化时触发 // 渲染逻辑 return ( <div> {loading ? ( <div>加载中...</div> ) : ( Array.from(datamap.entries()).map(([ticker, items]) => ( <div key={ticker}> <h3>{ticker}</h3> {items.map((item, index) => ( <div key={index}> 股份:{item.shares} | 价格:{item.price} | 类型:{item.type} </div> ))} </div> )) )} </div> ); }
关键说明
- 避免渲染时修改状态:数据处理放在
useEffect中,仅在依赖项变化时执行,杜绝无限重渲染 - 状态不可变性:更新Map和数组时创建新实例,React通过引用变化识别状态更新,确保组件正确重渲染
- 清晰的渲染逻辑:渲染阶段仅使用处理好的
datamap,不包含任何状态修改逻辑
内容的提问来源于stack exchange,提问作者Dotman
相关产品推荐
相关产品推荐

