【问题标题】:Passing data between components in React/Redux在 React/Redux 中的组件之间传递数据
【发布时间】:2020-06-25 08:41:54
【问题描述】:

我是 React 新手,我正在尝试构建一个应用程序,将足球运动员分成两支球队,但在将数据从一个组件传递到另一个组件时遇到了困难。

我已经安装了 redux 和 react-redux。

在我的 reducer.js 中,我获取了一个玩家列表并将它们打乱,将打乱的列表添加到 state:

const shufflePlayers = (state) => {
  return {
    ...state,
    shuffledList: [
      ...state.playersList.sort(() => Math.random() - 0.5)
    ]
  }
}

然后在 'src/components/DisplayTeams.index.js' 中,我将 'shuffledList' 数组映射到 props:

import { connect } from "react-redux";
import DisplayTeams from "./DisplayTeams";

const mapStateToProps = (state) => {
  return {
    shuffledList: state.shuffledList,
  };
};

export default connect(mapStateToProps)(DisplayTeams);

最后,在“src/components/DisplayTeams.js”中,我尝试在列表中呈现“shuffledList”数组:

import React from 'react';
import '../../App.css';

const DisplayTeams = ({ shuffledList }) => (

  <div>
    <ul>
      {shuffledList.map((player, index) => (
        <li key={index}>{player.name}</li>
      ))}
    </ul>
  </div>

);

export default DisplayTeams;

但出现 TypeError: Cannot read property 'map' of undefined,表明 'shuffledList' 数组为空或根本没有设置。

任何帮助将不胜感激!

【问题讨论】:

  • 你在mapState中有console.log(state)看看是什么吗?
  • 这一行shuffledList: state.shuffledList 似乎根本不对,所以是的,只是看看你的状态如何。
  • 以及shuffledList的初始状态是什么?
  • 请注意,在 shufflePlayers 函数中,shuffledList: [ ...state.playersList.sort() ] 会改变原始的 state.playersList 数组 - 您需要在 before 排序为 .sort( ) 改变原始数组:shuffledList: [...state.playersList].sort()
  • state.shuffledList 是 state.playersList 的一个副本,你不应该将值保存在你可以从 state 计算出来的 state 中,而是使用 selector。

标签: reactjs redux react-redux


【解决方案1】:

两件事:

  1. 你应该添加添加一个初始状态,你可以直接在reducer文件中设置它

     const initialState = {
         // other reducer parts here
         shuffledList: []
     }
    
  2. reducer 应该检查动作类型,否则它会在任何动作上运行。像这样的:

     const shufflePlayers = (state = initialState, action) => {
        switch (action.type) {
    
           case actionTypes.SHUFFLE_LIST: {
               // use a new array, avoid mutating the previous state
               const sortedList = [...state.playersList].sort(() => Math.random() - 0.5)
    
               return {
                   ...state,
                   shuffledList: sortedList
               }
           }
    
     }
    

【讨论】:

    【解决方案2】:

    不要在state中复制数据,list和shuffledList是同一个数据,shuffledList是list的计算结果。

    您可以使用选择器从列表中计算混洗列表,以防止它在渲染上重新计算您可以使用重新选择(无论如何都应该使用它)并记住混洗结果,只要列表不改变。

    const { Provider, useSelector } = ReactRedux;
    const { createStore, applyMiddleware, compose } = Redux;
    const { createSelector } = Reselect;
    
    const initialState = {
      list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
    };
    const reducer = (state = initialState) => state;
    //selectors
    const selectList = (state) => state.list;
    //if state.list changes then it will shuffle again
    const selectShuffledList = createSelector(
      [selectList],
      (list) => [...list].sort(() => Math.random() - 0.5)
    );
    const selectTeams = createSelector(
      [selectShuffledList, (_, size) => size],
      (shuffledList, teamSize) => {
        const teams = [];
        shuffledList.forEach((item, index) => {
          if (index % teamSize === 0) {
            teams.push([]);
          }
          teams[teams.length - 1].push(item);
        });
        return teams;
      }
    );
    const selectTeamsCurry = (teamSize) => (state) =>
      selectTeams(state, teamSize);
    //creating store with redux dev tools
    const composeEnhancers =
      window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
    const store = createStore(
      reducer,
      initialState,
      composeEnhancers(
        applyMiddleware(() => (n) => (a) => n(a))
      )
    );
    const App = () => {
      //you can re render app with setCount
      const [count, setCount] = React.useState(0);
      //setting count has no effect on teams because
      // state.list didn't change and selectShuffledList
      // will use memoized shuffled result
      const teams = useSelector(selectTeamsCurry(3));
      return (
        <div>
          <button onClick={() => setCount((w) => w + 1)}>
            re render {count}
          </button>
          <pre>{JSON.stringify(teams, undefined, 2)}</pre>
        </div>
      );
    };
    
    ReactDOM.render(
      <Provider store={store}>
        <App />
      </Provider>,
      document.getElementById('root')
    );
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/reselect/4.0.0/reselect.min.js"></script>
    
    
    <div id="root"></div>

    【讨论】:

      【解决方案3】:

      上面的代码看起来不错。您可以检查初始状态的 shuffledList,也可以在调度操作时检查 Redux 存储。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-02-15
        • 2022-01-20
        • 2019-01-04
        • 1970-01-01
        • 1970-01-01
        • 2017-03-11
        • 2019-02-21
        相关资源
        最近更新 更多