我是 React 的新手,基本上我正在尝试一次更新父 App.js
组件的状态及其子组件(Team.js
和 Player.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>
);
}
这个组件有两个对象数组(teams
和 players
),它们分别作为 props 发送到 Team
和 Player
组件。 Team
还接收 selectedTeam
和 setSelectedTeam
作为道具。 Player
接收 selectedPlayer
和 setSelectedPlayer
。两个组件都有一个 Modal
组件和一个选择输入。在 Team
组件中,用户将选择一个球队,并显示所选球队的球员,而在 Player
组件中,将选择一个球员,并显示他们的数量所选球员的MVP。
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;
所以我的问题是,如果我在子组件中选择一个选项,他们不会收到更新的选定选项(我的意思是 selectedTeam
组件的 Team
和 {selectedPlayer
{1}} 组件)立即但在父组件 Player
中我更新了它们。因此,如果我希望它们得到更新,我需要选择一个选项,关闭模态并再次重新打开它们。
例如,这里我有 App
视觉效果:
如果我打开 App.js
并选择一个团队,我会在 Team.js
中更新 selectedTeam
但在 App.js
中没有:
因此,如果我关闭模态并再次重新打开 Team.js
组件,那么我已更新 Team
。所以我有以下几点:
我对 props.selectedTeam
组件有同样的问题,但在本例中是关于 Player
我怎样才能让它正常工作,我的意思是,我怎样才能在 props.selectedPlayer
中同时更新 props.selectedTeam
和 props.selectedPlayer
,例如 App
和 {{1 }}, 分别?谢谢!
代码沙盒
https://codesandbox.io/s/young-sun-gs117?file=/src/Team.js:51-1127
答案 0 :(得分:0)
我知道的方法是只使用 Hooks useState
和 useEffect
并在选择更改时更新该状态。
希望 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;
答案 1 :(得分:0)
这是你需要做的,我重构了你的代码并添加了一些注释,这样你就知道我做了什么。要记住的一件事是,您几乎不想将组件存储在状态中。
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>
);
}