【问题标题】:.map() method using prior state in React.map() 方法使用 React 中的先前状态
【发布时间】:2021-06-09 17:05:27
【问题描述】:

我的应用程序允许用户单击“字段”部分中的球员卡,然后让选定的球员卡出现在“团队”部分中。我有一个数组(称为 selectedPlayers),最初,每个元素都有一个默认玩家名称和默认玩家图像。当用户选择球员时,数组中的元素会被所选球员的姓名和图像一一替换。

在父组件中设置数组的状态,然后将数组作为道具传递给 TeamsWrapper 组件。然后我映射数组,为数组的每个元素返回一个 TeamsCard 组件。然而,我的 TeamsCards 总是落后于现实的一种选择。也就是说,在第一个玩家被选中后,第一张牌仍然显示默认信息;选择第二个玩家后,第一张卡现在反映第一次选择,但第二张卡仍显示默认信息。 TeamsWrapper 组件的代码如下:

import React from "react";
import "./style.css";
import TeamsCard from "../TeamsCard";

function TeamsWrapper(props) {
  const { selectedPlayers } = props;
  console.log('first console.log',selectedPlayers)
  return (
    <div className="teamsWrapper">
      {selectedPlayers.map((el, i) => {
        console.log('second console.log',selectedPlayers)
        console.log('third console.log',el)
        return (
          <div key={i}>
            <TeamsCard
              image={el.image}
              playerName={el.playerName}
            />
          </div>
        );
      })}
    </div>
  );
}

export default TeamsWrapper;

在父级是基于类的组件之前,我确实可以正常工作。但是,我将其更改为使用钩子用于其他目的的功能组件。所以,我认为这个问题与设置状态有关,但控制台日志表明其他东西(我认为)。选中第一个玩家后:

  • 第一个控制台日志显示了一个正确更新的数组(即第一个元素反映了所选玩家的数据,而不是占位符数据)
  • 第二个控制台日志反映了同样的情况
  • 但第三次打印仍然显示第一个元素的占位符数据

如上所述,当我继续选择球员时,第三张印刷品(以及 TeamsCards)总是落后一个选择。

编辑:

这里是父组件(Picks)的代码,但是我把不相关的内容删掉了,以便于理解。

import React, { useState } from "react";
import { useStateWithCallbackLazy } from "use-state-with-callback";
import TeamsWrapper from "../TeamsWrapper";
import FieldWrapper from "../FieldWrapper";

const Picks = () => {
  const initialSelectedPlayers = [
    { playerName: "default name", image: "https://defaultimage" },
    { playerName: "default name", image: "https://defaultimage" },
    { playerName: "default name", image: "https://defaultimage" },
    { playerName: "default name", image: "https://defaultimage" },
    { playerName: "default name", image: "https://defaultimage" },
    { playerName: "default name", image: "https://defaultimage" },
  ];

  const [count, setCount] = useStateWithCallbackLazy(0);
  const [selectedPlayers, setSelectedPlayers] = useState(
    initialSelectedPlayers
  );

  const handleFieldClick = (props) => {
    // check to make sure player has not already been picked
    const match = selectedPlayers.some(
      (el) => el.playerName === props.playerName
    );
    if (match) {
      return;
    } else {
      setCount(count + 1, (count) => {
        updatePickPhase(props, count);
      });
    }
  };

  const updatePickPhase = (props, count) => {
    if (count <= 15) {
      updateTeams(props, count);
    }
    // elseif other stuff which doesn't apply to this issue
  };

  const updateTeams = (props, count) => {
    const location = [0, 1, 2, 5, 4, 3];
    const position = location[count - 1];
    let item = { ...selectedPlayers[position] };
    item.playerName = props.playerName;
    item.image = props.image;
    selectedPlayers[position] = item;
    setSelectedPlayers(selectedPlayers);
  };

  return (
    <>
      <TeamsWrapper selectedPlayers={selectedPlayers}></TeamsWrapper>
      <FieldWrapper
        handleFieldClick={handleFieldClick}
        count={count}
      ></FieldWrapper>
    </>
  );
};

export default Picks;

感谢您的帮助!

【问题讨论】:

  • 这个组件应该像你期望的那样工作。我们需要查看存储状态的父级。可能会引起您注意的是,如果您修改数组,控制台将反映这一点,即使您在修改它之前记录了它。一般来说,在更新状态时,您应该创建新对象而不是修改以前的对象。
  • Ben,感谢您提供有关控制台日志记录的想法和提示。已添加父组件,尽管我不得不对其进行一些简化以专注于该问题。

标签: javascript reactjs methods


【解决方案1】:

当您更新数组时,您正在改变状态(更新现有变量而不是创建新变量),因此 React 不会接收更改,仅在 count 更改时重新渲染,请尝试

const updateTeams = (props, count) => {
  const position = count - 1;
  const newPlayers = [...selectedPlayers];
  newPlayers[position] = {playerName:props.playerName, image:props.image} 
  setSelectedPlayers(newPlayers);
};

这样 React 会看到它是一个新数组并重新渲染。

【讨论】:

    猜你喜欢
    • 2019-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-25
    • 1970-01-01
    • 1970-01-01
    • 2022-06-16
    • 1970-01-01
    相关资源
    最近更新 更多