javascriptreactjsaxioszustand

How to call Zustand / React hook outside of React component?


I have this Zustand store to store authenticaction information about logged in user.

const authStore = (set: any) => ({
    ...initialState,
    doLogin: async (user: TLoggedInRequest) => {
        try {
            set(() => ({status: "pending"}))
            const result = await loginService.login(user)
            set(() => ({
                status: "resolved",
                user: result?.data.user,
                error: null
            }))
        } catch (error) {
            console.log("rejected error", error)
            set((state: any) => ({status: "rejected", error}))
        }
    },
    doLogout: async () => {
        await loginService.logout()
        set(() => initialState)
        history.push("/")
    }
});

This is HTTPApiClient that for communication with REST API uses Axios, example of GET method (the rest omitted for brevity).

async get<TResponse>(path: string): Promise<TResponse> {
    try {
        const response = await this.instance.get<TResponse>(path);
        return response.data;
    } catch (error: any) {
        handleServiceError(error);
    }
    return {} as TResponse;
}

And this piece of code is executed in React component when user is logging out.

const doLogoutSelector = (state: any) => state.doLogout;
const doLogout = useAuthStore(doLogoutSelector);

const signout = () => {
        doLogout()
        return <Navigate replace to="/"/>
}

I would like to logout user when HTTPApiClient gets 401 Unathorized status code from the backend. I am able to recognize the 401 code in client but I don't know how to call logout hook.

Q: How to call React the hook outside of React component?


Solution

  • The answer is simple:

    useAuthStore.getState().doLogout()
    

    E.g. my error-interceptor looks like:

    ...
    if (error instanceof AxiosError && response?.status === 401) {
      useAuth.getState().logout()
    }
    ...
    

    useAuth.ts

    export const useAuth = create((set, get) => ({
      logout: async () => {
        ...
      },
      ...
    }))