Reputation: 3665
I have a React component that makes an AJAX call, sets a state variable and then passes that state variable into a component.
Main component:
export default function MyView({ assetId }) {
const [asset, setAsset] = useState();
const [beanstalk, setBeanstalk] = useState();
const [loading, setLoading] = useState(true);
useEffect(() => {
loadAsset();
}, []);
const loadAsset = async () => {
const _asset = await findAssetById(assetId);
setLoading(false);
if(_asset) {
setAsset(_asset);
await loadBeanstalk(_asset.id);
}
};
const loadBeanstalk = async (assetId) => {
const _beanstalk = await getBeanstalkFromDB(assetId);
setBeanstalk(_beanstalk);
};
return (
{ loading ? (
<div>Loading...</div>
) : (
<h3>{asset.name}</h3>
<ChildComponent beanstalk={beanstalk} />
)}
)
}
Child component:
export default function ChildComponent({ beanstalk }) {
const [loadbalancer, setLoadbalancer] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
console.log("Beanstalk will print as undefined here:");
console.log(beanstalk);
getLoadbalancer();
}, []);
const getLoadbalancer = async () => {
if(beanstalk) {
const _loadbalancer = await getLoadbalancer(beanstalk);
setLoading(false);
setLoadbalancer(_loadbalancer);
}
}
return (
{ loading ? (
<div>Loading...</div>
) : (
<h3>{loadbalancer.name}</h3>
)}
)
}
My understanding is that the main component renders when state changes, so when I call setBeanstalk(_beanstalk)
it should re-render with the beanstalk
state variable set... so why does ChildComponent always render the Beanstalk as null when I know it's being returned from the database? I know it has something to do with the order of rendering.
Upvotes: 1
Views: 240
Reputation: 4054
So the issue seems to be one of order of operations. What you can try to do is one of the following:
Move your setLoading(false)
call into loadBeanstalk()
so that your ChildComponent
only renders once you have fully loaded the stuff.
const loadAsset = async () => {
const _asset = await findAssetById(assetId);
if(_asset) {
setAsset(_asset);
await loadBeanstalk(_asset.id);
} else {
setLoading(false);
}
};
const loadBeanstalk = async (assetId) => {
const _beanstalk = await getBeanstalkFromDB(assetId);
setBeanstalk(_beanstalk);
setLoading(false);
};
Attach beanstalk
to your useEffect
hook in ChildComponent
.
useEffect(() => {
console.log("Beanstalk will print as undefined here:");
console.log(beanstalk);
getLoadbalancer();
}, [ beanstalk ]);
Upvotes: 1