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

Redux store变更时React组件未重渲染,forceUpdate也无效如何解决?

问题根因

  • Reducer 违反 Redux 不可变更新原则,直接修改原 state 中的对象属性,且未返回新的 games 数组引用,Redux 无法检测到状态变更
  • 组件 connect 时未传入 mapStateToProps,没有订阅 Redux store 中的 games 状态变更,store 变化时组件不会收到新的 props
  • 组件内部用 useState 对传入的 games 做了本地缓存,仅在组件初始化时赋值一次,后续 props 中的 games 变更不会同步到本地 state
  • 强制更新逻辑属于无效操作,问题根源不在渲染触发,而在数据源没有同步更新

修复方案

1. 修复 Reducer 逻辑

所有状态变更都要返回新的对象/数组引用,禁止直接修改原 state 或传入的 payload 数据:

import { SET_GAMES, SET_GAME_VISIBLE, SET_GAME_INVISIBLE } from '../actions/games';

export const initialState = {
  games: [],
};

export default function games(state = initialState, action) {
  switch(action.type) {
    case SET_GAMES: {
      // 生成新数组,不修改原payload数据
      const newGames = action.payload.games.map(obj => ({
        ...obj,
        isVisible: true
      }))
      return {
        ...state,
        games: newGames,
      };
    }

    case SET_GAME_VISIBLE: {
      // 返回新数组,修改的项生成新对象避免修改原state
      return {
        ...state,
        games: state.games.map(obj => {
          if (obj.id === action.payload.id) {
            return {...obj, isVisible: true}
          }
          return obj
        })
      };
    }

    case SET_GAME_INVISIBLE: {
      return {
        ...state,
        games: state.games.map(obj => {
          if (obj.id === action.payload.id) {
            return {...obj, isVisible: false}
          }
          return obj
        })
      };
    }
    
    default:
      return state;
  }
}

2. 修复组件逻辑

补充 mapStateToProps 订阅 Redux 状态,增加 useEffect 同步 Redux 数据到本地状态,删除无用的强制更新代码:

import React, { useState, useEffect } from 'react';
import { ReactSortable } from 'react-sortablejs';
import ListItem from '@mui/material/ListItem';
import Checkbox from '@mui/material/Checkbox';
import { connect } from 'react-redux';
import { setGameVisible, setGameInvisible, setGames } from '../store/actions/games';

interface ItemType {
  id: string;
  name: string;
  isVisible: boolean;
}

interface IGamesListProps {
  games: ItemType[];
  setGameVisible: (id: string) => void;
  setGameInvisible: (id: string) => void;
  setGames: (games: ItemType[]) => void;
}

const GamesList: React.FunctionComponent<IGamesListProps> = ({games, setGameVisible, setGameInvisible, setGames}) => {
  const [state, setState] = useState<ItemType[]>(games);

  // 监听Redux的games变化,同步到本地state保证数据一致性
  useEffect(() => {
    setState(games)
  }, [games])

  const onCheckboxChangeHandle = (id: string, isVisible: boolean) => {
    isVisible ? setGameInvisible(id) : setGameVisible(id);
  }

  // 排序时如果需要持久化到Redux,调用对应action,不需要可以只保留setState
  const handleSortChange = (newList: ItemType[]) => {
    setState(newList)
    setGames(newList)
  }

  return (
    <ReactSortable list={state} setList={handleSortChange} tag='ul'>
      {state.map((item) => (
        <ListItem
          sx={{ maxWidth: '300px' }}
          key={item.id}
          secondaryAction={
            <Checkbox
              edge="end"
              onChange={() => onCheckboxChangeHandle(item.id, item.isVisible)}
              checked={item.isVisible}
            />
          }
        >
          {item.name}
        </ListItem>
      ))}
    </ReactSortable>
  );
};

// 订阅Redux中的games状态,映射到组件props
const mapStateToProps = (state: any) => ({
  games: state.games.games
})

export default connect(mapStateToProps, { setGameVisible, setGameInvisible, setGames })(GamesList);

如果不需要把排序结果同步到 Redux,删除 setGames 相关逻辑即可。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 18:24:05