Search code examples
reactjsreact-typescript

How can I make a context fetch data prior to being created?


I am trying to implement a loading Page. I have two contexts that both require GET requests to load information. One is for authentication and another is for fetching the current user profile state. Both utilize a useEffect to fetch the data.

For example, the Profile context useEffect appears like this.

    ...
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        getProfile()
            ...
            setLoading(false);
        
    }, [])

My main context appears like this,

export const AppContextComponent: React.FC<Props> = ({ children }) => {
    const authContext = useAuthContext();
    const profileContext = useProfileContext();

    const isLoading = authContext.loading || profileContext.loading;

    if (isLoading) {
        return <div> Loading... </div>;
    }

    return (
        <AuthContextComponent>
            <ProfileContextComponent>
                { children } 
            </ProfileContextComponent>
        </AuthContextComponent>
    )
}

Now, the problem I am having is that both child contexts initialize their "loading" state to True, because they're initialized to True the isLoading on the top level context will be True. However, because I never create a context component, the useEffect will never be called to make the GET request and later changing the loading state to False.

Is it possible to call the useEffect on the child contexts in order to make the GET request and update the loading state to False while still not "create it" because I want to return my loading page.


Solution

  • You can create another component to have the loading logic and then call that component after context initialization.

    export const LoadingComponent = React.FC<Props> = ({ children }) => {
        const authContext = useAuthContext();
        const profileContext = useProfileContext();
    
        const isLoading = authContext.loading || profileContext.loading;
    
        if (isLoading) {
            return <div> Loading... </div>;
        }
    
        return children
    }
    
    export const AppContextComponent: React.FC<Props> = ({ children }) => {
        return (
            <AuthContextComponent>
                <ProfileContextComponent>
                    <LoadingComponent>
                        { children } 
                    </LoadingComponent>
                </ProfileContextComponent>
            </AuthContextComponent>
        )
    }