【问题标题】:React-component is not re-rendered when the store is changed, neither automatically nor even by force update当 store 改变时,React-component 不会重新渲染,既不会自动也不会强制更新
【发布时间】:2021-12-17 15:55:47
【问题描述】:

此功能组件应显示一个排序列表,其中每个项目的复选框都会更改存储中的值。

由于某些原因,当商店更改时它不会重新渲染。如果没有重新渲染器,它(以及整个应用程序)工作得非常曲折和半途而废。我怀疑这是因为商店对象保持不变,尽管有新内容。但我不明白如何解决它。我什至在复选框处理程序中插入了强制更新,但由于某种原因它也不起作用。

组件:

import React, { useState, useReducer } 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 } from '../store/actions/games';

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

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

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

  // eslint-disable-next-line
  const [ignored, forceUpdate] = useReducer(x => x + 1, 0); // this way of force updating is taken from the official React documentation (but even it doesn't work!)

  const onCheckboxChangeHandle = (id: string, isVisible: boolean) => {
    isVisible ? setGameInvisible(id) : setGameVisible(id);
    forceUpdate(); // doesn't work :(((
  }

  return (
    <ReactSortable list={state} setList={setState} 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>
  );
};

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

减速机:

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: {
      for(let obj of action.payload.games) {
        obj.isVisible = true;
      }
      return {
        ...state,
        games: action.payload.games,
      };
    }

    case SET_GAME_VISIBLE: {
      for(let obj of state.games) {
        if (obj.id === action.payload.id) {
          obj.isVisible = true;
        };
      }
      return {
        ...state,
      };
    }

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

感谢您的帮助!

【问题讨论】:

    标签: reactjs typescript redux


    【解决方案1】:
    注意:根据您提供的信息,我提出了问题的想法,但我在这里发布,因为它会解释性和冗长。
    • 首先,您不会通过mapStateToProps 将新游戏传递到状态更改的组件中,即使您这样做了,useState 也不会将新游戏道具值用于非首次渲染。您必须使用 useEffect 并触发游戏的更改并在本地设置为状态。

    此时你必须发现内部状态是多余的,你可以删除它并完全依赖于 redux 状态。

    const mapStateToProp = (state) => ({
      games: state.games // you may need to change the path
    })
    
     connect(mapStateToProp, { setGameVisible, setGameInvisible })(GamesList);
    
    • 其次,您制作的减速器会更改单个游戏项目,但不会更改游戏列表本身。因为它是嵌套的,并且默认情况下引用检查是作为严格相等引用检查在 redux state === state 中完成的。这可能不会导致问题,因为顺便说一下外部状态会发生变化,但我认为值得一提。
    for(let obj of action.payload.games) {
      obj.isVisible = true; // mutating actions.payload.games[<item>]
    }
    return {
      ...state,
      games: [...action.payload.games], // add immutability for re-redenr
    };
    
    // or use map 
    return {
      ...state,
      games: action.payload.games.map(obj => ({...obj, isVisible:true})),
    };
    
    • 第三,你的forceUpdate 确实会导致组件重新渲染,你可以通过添加一个console.log 来测试它,但它不会重新绘制你的组件的整个子树,包括如果他们的道具的内部孩子不要因为性能问题而改变。 React 尝试尽可能高效地更新。还有 key 优化层,如果项目的顺序和它们的 ID 没有改变,它会阻止改变

    【讨论】:

    • 谢谢!当我删除内部组件状态并将 redux-store 传输到 ReactSortable 时,问题得到了解决。
    • 很高兴听到这个消息,编码快乐 :)
    猜你喜欢
    • 2021-11-24
    • 2020-04-22
    • 2020-01-20
    • 1970-01-01
    • 2021-06-13
    • 2016-05-09
    • 2018-11-29
    • 2020-10-03
    • 1970-01-01
    相关资源
    最近更新 更多