首页 > 解决方案 > 在 React/Redux 中的组件之间传递数据

问题描述

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

我安装了 redux 和 react-redux。

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

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

然后在“src/components/DisplayTeams.index.js”中,我将“shuffledList”数组映射到道具:

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' 数组为空或根本没有设置。

任何帮助都感激不尽!!

标签: reactjsreduxreact-redux

解决方案


您不应该在状态下复制数据,列表和 shuffledList 是相同的数据,但 shuffledList 是列表的计算结果。

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

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>


推荐阅读