I have a parent like this:
function ViewBudgetPage() {
const pathname = useParams();
const [plate, setPlate] = useState("");
const [bikeDataModal, setBikeDataModal] = useState(false);
useEffect(() => {
getBudgetByIdRequest(pathname.id).then((response) => {
setPlate(response.data.plate);
});
}, [pathname.id]);
function openBikeDataModal() {
setBikeDataModal(true);
}
function closeBikeDataModal() {
setBikeDataModal(false);
}
return (
<div className="text-center mt-5">
<input type="text" defaultValue={plate} disabled className="me-3" />
<button className="btn btn-outline-primary" onClick={openBikeDataModal}>
Click Me
</button>
<BikeDataModal
show={bikeDataModal}
close={closeBikeDataModal}
plate={plate}
/>
</div>
);
}
export default ViewBudgetPage;
I get the plate data in the useEffect and set it to the value.
The plate value is being passed to the modal.
The modal open only on click.
Inside the modal class I have another useEffect that uses the plate value in a backend request.
When first rendering the plate value is null and I get error from backend, after that I get the right values.
How to make my modal get the right plate value?
I am assuming that you are calling GET /listBikeByPlate
endpoint in BikeDataModal
component.
If that is the case, the problem is that you are rendering the BikeDataModal
when plate
is still undefined
/null
, consequently calling GET /listBikeByPlate
with no value for your query parameter plate
(according to the ?plate=
in screenshot)
So the best thing you can do is to avoid rendering the child component until the initial request in useEffect
has been finished.
My suggestion is to add a new state like so
const [isLoaded, setIsLoaded] = useState(false)
And then inside of your getBudgetByIdRequest
, set setIsFetching
to true
once the fetch is resolved/finished like so
useEffect(() => {
getBudgetByIdRequest(pathname.id).then((response) => {
setPlate(response.data.plate);
setIsLoaded(true)
});
}, [pathname.id]);
And finally do the conditional rendering right before your original return
block
if (!isLoaded) {
return <>Loading</>
}
So after the fetch is finished and your plate
has been set, your BikeDataModal
will now have the correct plate
data, making the correct API call.
In conclusion, you full code should be
function ViewBudgetPage() {
const pathname = useParams()
const [plate, setPlate] = useState('')
const [bikeDataModal, setBikeDataModal] = useState(false)
const [isLoaded, setIsLoaded] = useState(false)
useEffect(() => {
getBudgetByIdRequest(pathname.id).then((response) => {
setPlate(response.data.plate)
setIsLoaded(true)
})
}, [pathname.id])
function openBikeDataModal() {
setBikeDataModal(true)
}
function closeBikeDataModal() {
setBikeDataModal(false)
}
if (!isLoaded) return <>Loading</>
return (
<div className="text-center mt-5">
<input type="text" defaultValue={plate} disabled className="me-3" />
<button className="btn btn-outline-primary" onClick={openBikeDataModal}>
Click Me
</button>
<BikeDataModal show={bikeDataModal} close={closeBikeDataModal} plate={plate} />
</div>
)
}
export default ViewBudgetPage