You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;

关键优化点

  1. 数据分离:原始数据仅在初始化或全量更新时修改,过滤操作不会影响它,避免useEffect重复触发
  2. Key优化:用房源的唯一标识(如id)替代index作为列表项的key,提升列表渲染性能
  3. 依赖控制:useEffect仅依赖mapMoveEnd和rawProperties,只有地图移动或原始数据变化时才执行过滤

内容的提问来源于stack exchange,提问作者Katyellen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 14:17:57