React中useEffect结合dispatch时如何避免无限循环?
解决地图移动时React组件无限更新导致的
Maximum update depth exceeded错误 问题分析
你遇到的无限更新循环,根源在于依赖项与状态更新的循环触发:
- 你的
useEffect依赖了dataProperties,而每次执行dispatch(setProperties(_response))都会修改dataProperties - 状态修改后,
useEffect因为依赖项变化再次执行,重新过滤并更新状态,形成无限循环
解决方案
核心思路是分离原始数据与展示数据:在Redux中分别存储「全量原始房源数据」和「过滤后的可视区域房源数据」,避免过滤操作修改原始数据导致的循环触发。
步骤1:修改Redux Store结构
新增专门用于存储过滤后数据的状态,区分原始数据与展示数据:
// store/StoreInfo.js const initialState = { rawProperties: [], // 存储所有原始房源数据 filteredProperties: [], // 存储可视区域内的房源(用于展示) mapMoveEnd: null }; // 新增action用于更新过滤后数据 export const setFilteredProperties = (data) => ({ type: 'SET_FILTERED_PROPERTIES', payload: data }); // 保留原始数据的更新action export const setRawProperties = (data) => ({ type: 'SET_RAW_PROPERTIES', payload: data }); export const setMapMoveEnd = (map) => ({ type: 'SET_MAP_MOVE_END', payload: map }); const storeInfoReducer = (state = initialState, action) => { switch(action.type) { case 'SET_RAW_PROPERTIES': return {...state, rawProperties: action.payload}; case 'SET_FILTERED_PROPERTIES': return {...state, filteredProperties: action.payload}; case 'SET_MAP_MOVE_END': return {...state, mapMoveEnd: action.payload}; default: return state; } }; export default storeInfoReducer;
步骤2:修改Properties组件逻辑
基于原始数据执行过滤,更新展示数据,避免依赖展示数据导致的循环:
import React from "react"; import { useSelector, useDispatch } from "react-redux"; import { setFilteredProperties } from "../../store/StoreInfo"; const Properties = () => { const dispatch = useDispatch(); // 获取原始全量房源数据 const rawProperties = useSelector((state) => state.storeInfo.rawProperties); // 获取地图移动结束的状态 const mapMoveEnd = useSelector((state) => state.storeInfo.mapMoveEnd); // 获取过滤后的展示数据 const filteredProperties = useSelector((state) => state.storeInfo.filteredProperties); React.useEffect(() => { if (mapMoveEnd && rawProperties.length) { // 基于原始数据过滤可视区域内的房源 const visibleProperties = rawProperties.filter((accommodation) => { return mapMoveEnd .getBounds() .contains([accommodation.latitude, accommodation.longitude]); }); // 更新过滤后的展示数据 dispatch(setFilteredProperties(visibleProperties)); } }, [mapMoveEnd, dispatch, rawProperties]); // 仅依赖原始数据和地图状态,不会循环触发 return ( <div> {filteredProperties.map((property) => ( <div style={{ display: "flex", padding: "10px", borderBottom: "1px solid gray" }} key={`property_${property.id}`} // 建议使用房源唯一ID作为key,不要用index > <h3>Name: {property.name}</h3> </div> ))} </div> ); }; export default Properties;
关键优化点
- 数据分离:原始数据仅在初始化或全量更新时修改,过滤操作不会影响它,避免
useEffect重复触发 - Key优化:用房源的唯一标识(如
id)替代index作为列表项的key,提升列表渲染性能 - 依赖控制:
useEffect仅依赖mapMoveEnd和rawProperties,只有地图移动或原始数据变化时才执行过滤
内容的提问来源于stack exchange,提问作者Katyellen
相关产品推荐
相关产品推荐

