当前位置: 首页 > 知识库问答 >
问题:

如何同时更新父状态和子组件道具

汪信鸥
2023-03-14

我是新手,基本上我正在尝试立即更新父App.js组件的状态及其子组件(Team.jsPlayer.js)道具。当前仅更新父组件的状态。我会一步一步地解释清楚。

这里我有一个父组件App.js

export default function App() {
      const teams = [
        {
          Name: "Chicago Bulls",
          Players: ["Michael Jordan", "Dennis Rodman", "Scottie Pippen"],
          Championships: 6
        },
        {
          Name: "Golden State Warriors",
          Players: ["Stephen Curry", "Klay Thompson", "Draymond Green"],
          Championships: 5
        },
        {
          Name: "Los Angeles Lakers",
          Players: ["Kobe Bryant", "LeBron James", "Magic Johnson"],
          Championships: 17
        }
      ];
      const [selectedTeam, setSelectedTeam] = useState({});
    
      const players = [
        { Name: "LeBron James", MVPs: 4 },
        { Name: "Michael Jordan", MVPs: 5 },
        { Name: "Stephen Curry", MVPs: "2" }
      ];
      const [selectedPlayer, setSelectedPlayer] = useState({});
    
      const [modalContent, setModalContent] = useState(false);
      const clickedComponent = useRef(null);
      const [show, setShowModal] = useState(false);
    
      const showModal = () => {
        setShowModal(true);
      };
    
      const hideModal = () => {
        setShowModal(false);
      };
    
      const handleModalContent = (clicked) => {
        switch (clicked) {
          case "Team":
            clickedComponent.current = (
              <Team
                teams={teams}
                selectedTeam={selectedTeam}
                setSelectedTeam={setSelectedTeam}
              />
            );
            break;
          case "Player":
            clickedComponent.current = (
              <Player
                players={players}
                selectedPlayer={selectedPlayer}
                setSelectedPlayer={setSelectedPlayer}
              />
            );
            break;
          default:
            clickedComponent.current = null;
            break;
        }
      };
    
      return (
        <div className="App" style={{ justifyContent: "space-evenly" }}>
          <div
            style={{
              justifyContent: "center",
              width: "100%",
              display: "flex",
              flexWrap: "wrap",
              margin: "40px 0px 0px 0px"
            }}
          >
            <div
              className="table-cell"
              onClick={() => {
                handleModalContent("Team");
                setModalContent(true);
                showModal();
              }}
            >
              <div className="table-cell-text">Click to access Team component</div>
            </div>
            <div
              className="table-cell"
              onClick={() => {
                handleModalContent("Player");
                setModalContent(true);
                showModal();
              }}
            >
              <div className="table-cell-text">
                Click to access Player component
              </div>
            </div>
          </div>
          <h3 style={{ marginTop: "30px" }}>
            The last selected team was: {selectedTeam.Name}
            <br />
            The last selected player was: {selectedPlayer.Name}
          </h3>
          <Modal show={show} modalClosed={hideModal}>
            {(modalContent && clickedComponent.current) || null}
          </Modal>
        </div>
      );
    }

这个组件有两个对象数组(teamPlayer),分别作为道具发送到TeamPlayer组件。接收selectedPlayer和setSseltedPlayer。两个组件都有一个Modal组件和一个选择输入。在Team组件中,用户将选择一个团队,他们将显示所选团队的球员,而在Player组件中,将选择一个球员,他们将显示选中的玩家。

Team.js

const Team = (props) => {
  return (
    <div style={{ position: "relative", margin: "0 auto", width: "10em" }}>
      <h3>Select a team</h3>
      <div className="input-group col">
        <select
          onChange={(e) => {
            if (e === "") props.setSelectedTeam({});
            else {
              let foundTeam = props.teams.find(
                (team) => team.Name === e.target.value
              );
              props.setSelectedTeam(foundTeam);
            }
          }}
        >
          <option value="">Select a team...</option>
          {props.teams.map((team) => (
            <option key={team.Name} value={team.Name}>
              {team.Name}
            </option>
          ))}
        </select>
      </div>
      {Object.keys(props.selectedTeam).length > 0 ? (
        <div>
          <h3>{props.selectedTeam.Name} players: </h3>
          <br />
          {props.selectedTeam.Players.map((player, index) => (
            <div key={index}>{player}</div>
          ))}
        </div>
      ) : null}
    </div>
  );
};

export default Team;

Player.js

const Player = (props) => {
  return (
    <div style={{ position: "relative", margin: "0 auto", width: "10em" }}>
      <h3>Select a player</h3>
      <div className="input-group col">
        <select
          onChange={(e) => {
            if (e === "") props.setSelectedPlayer({});
            else {
              let foundPlayer = props.players.find(
                (player) => player.Name === e.target.value
              );
              props.setSelectedPlayer(foundPlayer);
            }
          }}
        >
          <option value="">Select a player...</option>
          {props.players.map((player) => (
            <option key={player.Name} value={player.Name}>
              {player.Name}
            </option>
          ))}
        </select>
      </div>
      {Object.keys(props.selectedPlayer).length > 0 ? (
        <div>
          <h3>
            {props.selectedPlayer.Name} MVPs: {props.selectedPlayer.MVPs}
          </h3>
        </div>
      ) : null}
    </div>
  );
};

export default Player;

因此,我的问题是,如果我在子组件中选择一个选项,它们不会立即收到更新的选定选项(我的意思是selectedTeamforTeam组件和selectedPlayerforPlayer组件),但在父组件App中,我会更新它们。因此,如果我想更新它们,我需要选择一个选项,关闭模式并再次打开它们。

例如,这里我有一个pp.js视觉对象:

如果我打开Team.js并选择一个团队,我在App.js中更新了selectedTeam,但在Team.js中没有更新:

因此,如果我关闭模式并再次打开Team组件,那么我已经更新了道具。因此,我有以下几点:

我对Player组件也有同样的问题,但在本例中是关于道具。selectedPlayer

如何使其正常工作,我的意思是,如何拥有道具。selectedTeam道具。selectedPlayer分别在应用程序玩家中立即更新?非常感谢。

代码沙盒

https://codesandbox.io/s/young-sun-gs117?file=/src/Team.js: 51-1127


共有2个答案

龚志文
2023-03-14

我知道如何使用HooksuseStateuseffect并在选择更改时更新该状态。

希望下面的Player示例有所帮助(在您的代码沙盒中工作,除非我没有回答您的问题):

import React, { useState, useEffect } from "react";
import "./styles.css";

const Player = (props) => {
  const [test, setTest] = useState("");

  useEffect(() => {
    console.log("props:", props);
    setTest(props.selectedPlayer);
  }, [props]);

  return (
    <div style={{ position: "relative", margin: "0 auto", width: "10em" }}>
      <h3>Select a player</h3>
      <div className="input-group col">
        <select
          value={props.selectedPlayer}
          onChange={(e) => {
            if (e === "") props.setSelectedPlayer({});
            else {
              let foundPlayer = props.players.find(
                (player) => player.Name === e.target.value
              );
              props.setSelectedPlayer(foundPlayer);
              setTest(foundPlayer);
            }
          }}
        >
          <option value="">Select a player...</option>
          {props.players.map((player) => (
            <option key={player.Name} value={player.Name}>
              {player.Name}
            </option>
          ))}
        </select>
      </div>

      <h3>{test.Name} MVPs: {test.MVPs}</h3>
      {/* {Object.keys(props.selectedPlayer).length > 0 ? (
        <div>
          <h3>
            {props.selectedPlayer.Name} MVPs: {props.selectedPlayer.MVPs}
          </h3>
        </div>
      ) : null} */}
    </div>
  );
};

export default Player;
谭富
2023-03-14

下面是您需要做的,我重构了您的代码并添加了一些注释,这样您就知道我做了什么。需要记住的一点是,您几乎不希望将组件存储在状态中。

export default function App() {
  const teams = [
    {
      Name: "Chicago Bulls",
      Players: ["Michael Jordan", "Dennis Rodman", "Scottie Pippen"],
      Championships: 6,
    },
    {
      Name: "Golden State Warriors",
      Players: ["Stephen Curry", "Klay Thompson", "Draymond Green"],
      Championships: 5,
    },
    {
      Name: "Los Angeles Lakers",
      Players: ["Kobe Bryant", "LeBron James", "Magic Johnson"],
      Championships: 17,
    },
  ];
  const players = [
    { Name: "LeBron James", MVPs: 4 },
    { Name: "Michael Jordan", MVPs: 5 },
    { Name: "Stephen Curry", MVPs: "2" },
  ];

  // This makes typo mistake less and will give you auto complete option
  const componentType = {
    team: "Team",
    player: "Player",
  };

  const [selectedTeam, setSelectedTeam] = useState({});
  const [selectedPlayer, setSelectedPlayer] = useState({});
  // the modalContent state and show state are doing the same thing so one of them is unneccessary
  const [show, setShowModal] = useState(false);
  const [clickedComponent, setClickedComponent] = useState("");

  const showModal = () => {
    setShowModal(true);
  };

  const hideModal = () => {
    setShowModal(false);
  };

  const handleModalContent = (clicked) => {
    setClickedComponent(clicked);
  };

  return (
    <div className="App" style={{ justifyContent: "space-evenly" }}>
      <div
        style={{
          justifyContent: "center",
          width: "100%",
          display: "flex",
          flexWrap: "wrap",
          margin: "40px 0px 0px 0px",
        }}
      >
        <div
          className="table-cell"
          onClick={() => {
            handleModalContent(componentType.team);
            showModal();
          }}
        >
          <div className="table-cell-text">Click to access Team component</div>
        </div>
        <div
          className="table-cell"
          onClick={() => {
            handleModalContent(componentType.player);
            showModal();
          }}
        >
          <div className="table-cell-text">
            Click to access Player component
          </div>
        </div>
      </div>
      <h3 style={{ marginTop: "30px" }}>
        The last selected team was: {selectedTeam.Name}
        <br />
        The last selected player was: {selectedPlayer.Name}
      </h3>
      <Modal show={show} modalClosed={hideModal}>
        {clickedComponent === componentType.player ? (
          <Player
            players={players}
            selectedPlayer={selectedPlayer}
            setSelectedPlayer={setSelectedPlayer}
          />
        ) : clickedComponent === componentType.team ? (
          <Team
            teams={teams}
            selectedTeam={selectedTeam}
            setSelectedTeam={setSelectedTeam}
          />
        ) : null}
      </Modal>
    </div>
  );
}
 类似资料:
  • 在父组件中: 我有一个布尔状态: 我将其发送到子组件: 根据布尔值,我希望它呈现不同的组件。

  • 我正在学习如何应对,我整天都在试图找到解决问题的办法,但都没有成功。然后决定在这里提出我的第一个问题。 我有子组件,包括React-Datepicker组件和单独的“第二天”和“前一天”按钮来更改选定的日期。 SelectedDate存储在父组件的状态中。 我试图从子组件更新父组件的状态,当状态更新时,子组件应该重新呈现,因为该状态作为道具传递给同一个子组件。 我已设法从child更改父状态,但子

  • 我是reactjs的新手,我不知道如何从父组件中更改子组件的状态。下面是代码 每当对父组件中的执行时,我希望子组件接收。 有什么建议吗?

  • 假设我的父组件有两个子组件: 我从Child2获得一个输入,并将其传递给父组件(到目前为止,我知道该怎么做)。但是,我需要将该输入传递给Child1,以更新它的状态。 我怎么能那么做?

  • 我正在将父组件的状态从父组件传递到子组件。在子组件中,我有一个不同的状态。我正在对子组件的状态执行一些操作,并且结果必须添加到父组件的状态。因此,在我的父组件中,我编写了一个回调函数,该函数将更新父组件的状态。代码为: 因此,这个函数随后作为道具传递给子组件: 然后在我的子组件中,我试图实现回调函数为: 但这并没有达到预期效果。这是正确的方法吗?有人能帮我吗? 我试图通过实现这里提供的解决方案来解

  • 这个问题在这里已经得到了回答,但事情总是在变化。 基本上,父组件获取一些数据,子组件需要这些数据。 这是子组件。