I am trying to delay the render of a parent component until all its children are fully ready to be rendered. Basically what I want to do is show a loading indicator on the parent component while the child component is not ready. Once the child component is completely ready to be rendered, then the loading indicator disappears and the parent component gets rendered along with its child immediately for a smooth user experience. What is happening currently is the parent component shows a loading indicator when its not ready to be rendered, then the loading indicator goes away when it is ready to be rendered, but it doesn't wait until the child component is ready, and thus that causes some delay which is not very smooth.
To address this issue, I used Zustand to lift the loading state from the child component to the parent component. Then, I dynamically rendered the parent component based on the readiness of all necessary data within the child component. However, this created an unexpected problem. My parent component just showed the loading indicator indefinitely and it seemed to not lift up the proper state to the parent component.
This is the related code to help better understand what I did. Note that if I remove the bit where I try to lift the loading state up, the code works fine but not as smooth as I'd like as described above:
Child Component:
const {
data: sequentialEvolutionDetails,
isLoading: sequentialEvolutionDetailsLoading,
} = usePokemonDetails(sequentialEvolutionIDs, 0);
let {
data: choiceEvolutionDetails,
isLoading: choiceEvolutionDetailsLoading,
} = usePokemonDetailsEvolution(choiceEvolutionIDs);
if (choiceEvolutionDetails && sequentialEvolutionDetails) {
choiceEvolutionDetails = choiceEvolutionDetails.map((evolutionPath) => [
...sequentialEvolutionDetails,
...evolutionPath,
]);
}
const {
setChoiceEvolutionDetailsLoading,
setSequentialEvolutionDetailsLoading,
} = useLoadingStore();
useEffect(() => {
setSequentialEvolutionDetailsLoading(sequentialEvolutionDetailsLoading);
setChoiceEvolutionDetailsLoading(choiceEvolutionDetailsLoading);
}, [sequentialEvolutionDetailsLoading, choiceEvolutionDetailsLoading]);
Parent Component:
const {
isChoiceEvolutionDetailsLoading,
isSequentialEvolutionDetailsLoading,
} = useLoadingStore();
if (
isPokemonDetailLoading ||
isPokemonLoading ||
isNearbyLoading ||
isChoiceEvolutionDetailsLoading ||
isSequentialEvolutionDetailsLoading
)
return <LoadingSpinner />;
Loading Store:
import { create } from "zustand";
interface LoadingStore {
isPokemonSpeciesLoading: boolean;
isSequentialEvolutionDetailsLoading: boolean;
isChoiceEvolutionDetailsLoading: boolean;
setPokemonSpeciesLoading: (loading: boolean) => void;
setSequentialEvolutionDetailsLoading: (loading: boolean) => void;
setChoiceEvolutionDetailsLoading: (loading: boolean) => void;
}
const useLoadingStore = create<LoadingStore>((set) => ({
isPokemonSpeciesLoading: false,
isSequentialEvolutionDetailsLoading: false,
isChoiceEvolutionDetailsLoading: false,
setPokemonSpeciesLoading: (loading) =>
set(() => ({ isPokemonSpeciesLoading: loading })),
setSequentialEvolutionDetailsLoading: (loading) =>
set(() => ({ isSequentialEvolutionDetailsLoading: loading })),
setChoiceEvolutionDetailsLoading: (loading) =>
set(() => ({ isChoiceEvolutionDetailsLoading: loading })),
}));
export default useLoadingStore;
Ignore my variable names they are a work in progress lol. Sorry I am relatively new to this so bare with me! Thank you so much.
It's just how you organize the states