I take a name from the path and give it to useeffect->dispatch and if array empty navigate to='', if not empty must show array. Navigate always works on the first render, the second time work normally. I'm trying to change useEffect to useLayoutEffect, but it also works on the first render.
file
const { car } = useParams();
const { carArray } = useSelector(state => state.carStore);
useEffect(() => {
dispatch(getCar(JSON.stringify(car)))
}, [car])
return (<div>
{!carArray ? <Navigate to={"/"} : carArray.map..}
</div>)
api
export const getCar = createAsyncThunk(
'get/car',
async (str) => {
const response = await axios.post("", str)
.then((r) => {
return r.data
})
.catch((err) => {
console.log(err)
})
return response
}
)
slice
builder.addCase(getCar.fulfilled, (state, action) => {
state.carArray = action.payload
})
console.log works like this
This is because returning JSX always happens before useEffect
, one solution is to create a state to handle the "loading" phase (the first render):
const [loading, setLoading] = useState(true);
//...
useEffect(() => {
dispatch(getCar(JSON.stringify(car)));
setLoading(false);
}, [car]);
//...
if (loading) {
return <div>Loading...</div>;
} else {
return (<div>
{!carArray ? <Navigate to={"/"} : carArray.map..}
</div>)
}
If your goal is to get the data during the first render, then useEffect
is not the right way to go,it runs after the first render so it is abvious that the redux state is still an empty array then.
You have mentionned useLayoutEffect
but it will not help achieving what you want, the only way is to dispatch getCar
action earlier, before the component mounts, geting the id to pass to the function won't be a problem.