I'm trying to immediatelly update a parent components' state so I can properly use it in a Child (nested) component. I will try to give as many details as possible so you an understand.
So basically I have a parent component ( App.js ):
import React, { useState } from "react";
import Child from "./Child";
import Modal from "./Modal";
import "./styles.css";
export default function App() {
const [options, setOptions] = useState([
{ Player: "Kevin Durant", Team: "Brooklyn Nets" },
{ Player: "LeBron James", Team: "Los Angeles Lakers" },
{ Player: "Michael Jordan", Team: "Chicago Bulls" }
]);
const [selectedOption, setSelectedOption] = useState({});
const [modalContent, setModalContent] = useState(null);
const [show, setShowModal] = useState(false);
const showModal = () => {
setShowModal(true);
};
const hideModal = () => {
setShowModal(false);
};
return (
<div className="App">
<div
className="row"
style={{
justifyContent: "center",
width: "100%",
margin: "40px 0px 0px 0px"
}}
>
<div
className="table-cell other"
onClick={() => {
setModalContent(() => (
<Child
options={options}
selectedOption={selectedOption}
setSelectedOption={setSelectedOption}
/>
));
showModal();
}}
>
<div className="table-cell-text">Click to access Child component</div>
</div>
</div>
<Modal
show={show}
modalClosed={hideModal}
width={"40%"}
title={"Choose a Player"}
>
{modalContent}
</Modal>
</div>
);
}
App.js ( parent component ) visual:
This component has an array of objects ( options ) that is sent to the Child component as props.
Array of objects I mentioned:
[
{ Player: "Kevin Durant", Team: "Brooklyn Nets" },
{ Player: "LeBron James", Team: "Los Angeles Lakers" },
{ Player: "Michael Jordan", Team: "Chicago Bulls" }
]
Basically the Child component has a Modal component and a select input, which will show the options.
Child.js :
import React from "react";
import Team from "./Team";
const Child = (props) => {
return (
<div style={{ position: "relative", margin: "0 auto", width: "10em" }}>
<div className="input-group col">
<select
className="form-control"
onChange={(e) => {
let foundOption = props.options.find(
(options) => options.Player === e.target.value
);
props.setSelectedOption(foundOption);
}}
>
<option value="">Select a Player...</option>
{props.options.map((option) => (
<option key={option.Player} value={option.Player}>
{option.Player}
</option>
))}
</select>
</div>
<Team selectedOption={props.selectedOption} />
</div>
);
};
export default Child;
Child.js visual:
The Child component also has a Team component. Basically the Team component receive the selectedOption as props and shows a div with the selectedOption.Team value.
Team.js :
import React from "react";
const Team = (props) => {
console.log(props.selectedOption);
return (
<div style={{ marginTop: "30px" }}>
Team:{" "}
{props.selectedOption !== undefined ? props.selectedOption.Team : ""}
</div>
);
};
export default Team;
The thing is, if I select an option, the Team component doesn't receive the updated selectedOption immediatelly. So, if I want to show the players' team, I need to select an option, close the modal and reopen it again.
I also recorded a video to show the issue: https://youtu.be/3P1tURgxvTQ
I would like to know how can I make it work properly, If you guys don't understand my question. please let me know and I will try to improve it. Thank you all!
My CodeSandbox:
This would be your App.js
file:
import React, { useState } from "react";
import Child from "./Child";
import Modal from "./Modal";
import "./styles.css";
export default function App() {
const [options, setOptions] = useState([
{ Player: "Kevin Durant", Team: "Brooklyn Nets" },
{ Player: "LeBron James", Team: "Los Angeles Lakers" },
{ Player: "Michael Jordan", Team: "Chicago Bulls" },
]);
const [selectedOption, setSelectedOption] = useState(); // <--- remove the {} from here because your checking props.selectedOption !== undefined in Team Comp
const [modalContent, setModalContent] = useState(false); // <--- the content state is now just a boolean
const [show, setShowModal] = useState(false);
const showModal = () => {
setShowModal(true);
};
const hideModal = () => {
setShowModal(false);
};
return (
<div className="App">
<div
className="row"
style={{
justifyContent: "center",
width: "100%",
margin: "40px 0px 0px 0px",
}}
>
<div
className="table-cell other"
onClick={() => {
setModalContent(true);
showModal();
}}
>
<div className="table-cell-text">Click to access Child component</div>
</div>
</div>
<Modal
show={show}
modalClosed={hideModal}
width={"40%"}
title={"Choose a Player"}
>
{modalContent && (
<Child
options={options}
selectedOption={selectedOption}
setSelectedOption={setSelectedOption}
/>
)}
</Modal>
</div>
);
}
This would be the Child.js
import React from "react";
import Team from "./Team";
const Child = (props) => {
return (
<div style={{ position: "relative", margin: "0 auto", width: "10em" }}>
<div className="input-group col">
<select
className="form-control"
onChange={(e) => {
let foundOption = props.options.find(
(options) => options.Player === e.target.value
);
props.setSelectedOption(foundOption);
}}
>
<option value="">Select a Player...</option>
{props.options.map((option) => (
<option key={option.Player} value={option.Player}>
{option.Player}
</option>
))}
</select>
</div>
<Team selectedOption={props.selectedOption} />
</div>
);
};
export default Child;
and this would be the Team.js
import React from "react";
const Team = (props) => {
console.log(props.selectedOption);
return (
<div style={{ marginTop: "30px" }}>
Team:{" "}
{props.selectedOption && props.selectedOption.Team || ""}
</div>
);
};
export default Team;
Although I'm not quite sure why you keep the options
as a state or why you need the selectedOption
in App.js
, it makes sense to put it in Child.js
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.