Search code examples
reactjsreact-context

useContext - userID undefined in app file


I have a problem. I want to access the user ID in the app.tsx file, but the problem is that the userID in the AuthContextProvider file has a value depending on the logged in user, but in the app.tsx file the value remains undefined.

How can i solve my problem?

App.tsx:

import "./shared/styles/crema.less";
import {
  AppContextProvider,
  AppLayout,
  AppLocaleProvider,
  AppThemeProvider,
  AuthRoutes,
} from "./domain";
import { BrowserRouter } from "react-router-dom";
import AuthContextProvider, { AuthContext } from "./pages/auth/context";
import { QueryClient, QueryClientProvider } from "react-query";
import { useContext, useEffect, useState } from "react";
import { Socket, io } from "socket.io-client";
import { func } from "prop-types";
const queryClient = new QueryClient();

export const newSocket: any = io("http://151.248.117.169:3001");

const App = () => {
  const authContext = useContext(AuthContext);
  console.log('userId: ', authContext, { authContext })
  const [socket, setSocket] = useState<any>();

  useEffect(() => {
    newSocket.connect();
    console.log("socket: ", newSocket)
    setSocket(newSocket);

    return () => {
      newSocket.disconnect();
    };
  }, []);


  useEffect(() => {
    socket?.emit('addNewAccount', {
      "id": 2,
      "type": 1,
    }, (val: any) => {
      console.log(val);
    });
  }, [socket]);

  return (
    <AppContextProvider>
      <AuthContextProvider>
        <QueryClientProvider client={queryClient}>
          <AppThemeProvider>
            <AppLocaleProvider>
              <BrowserRouter>
                <AuthRoutes>
                  <AppLayout />
                </AuthRoutes>
              </BrowserRouter>
            </AppLocaleProvider>
          </AppThemeProvider>
        </QueryClientProvider>
      </AuthContextProvider>
    </AppContextProvider>
  );
};

export default App;

AuthContextProvider.tsx:

import React, { createContext, useState, useEffect, ReactElement } from "react";
import { AuthContextProps } from "./types";
import { useCookies } from "react-cookie";
import { ILoginDto } from "../../../shared/services/auth/dtos/login-dto";
import {
  AUTH_TOKEN,
  EXHIBITOR_LOGO,
  EXHIBITOR_NAME,
  EXHIBITOR_STAND_DESIGN,
} from "../../../shared/constants/AppConst";
import { authService } from "../../../shared/services/auth";
import MainUtils from "../../../shared/utils/main";
import { notifier } from "../../../shared/functions/notifier";
import { Navigate, useNavigate, useParams, useRoutes } from "react-router-dom";
export const AuthContext = createContext<AuthContextProps>({});

const AuthContextProvider = ({ children }: { children: ReactElement<any, any> }) => {
  const [authenticated, setAuthenticated] = useState<boolean>(false);
  const [loading, setLoading] = useState<boolean>(false);
  const [visibleLogout, setVisibleLogout] = useState<boolean>(false);
  const [responseError, setError] = useState<any>("");
  const [cookies, setCookies, removeCookies] = useCookies([AUTH_TOKEN]);
  const [cookiesEmail] = useCookies(["email"]);
  const [userId, setUserId] = useState<any>();

  const logout = async () => {
    setLoading(true);
    await authService.logout().then(async (response: any) => { });
    removeCookies(AUTH_TOKEN);
    removeCookies(EXHIBITOR_NAME);
    setVisibleLogout(false);
    setLoading(false);
  };

  const login = async (values: any) => {
    setLoading(true);

    let request: ILoginDto = {
      email: values?.email,
      password: values?.password,
      fcm_token: values.fcm_token,
    };
    await authService
      .login(request)
      .then((response: any) => {
        setUserId(response?.data?.id);
        if (!MainUtils.isEmptyValue(response?.errors)) {
          response?.errors?.map((error: string) => {
            notifier(error, "error");
          });
        }
        if (response?.data?.token) {
          setCookies(AUTH_TOKEN, `${response?.data?.token}`, {
            path: "/",
            sameSite: true,
          });
          setCookies(EXHIBITOR_NAME, `${response?.data?.name}`, {
            path: "/",
            sameSite: true,
          });
          setCookies(EXHIBITOR_LOGO, `${response?.data?.logo}`, {
            path: "/",
            sameSite: true,
          });
          setCookies(
            EXHIBITOR_STAND_DESIGN,
            `${response?.data?.stand_design}`,
            {
              path: "/",
              sameSite: true,
            }
          );
        }
      })
      .catch(({ response }) => {
        const errorMessage: string =
          response?.data?.errors?.[
          Object.keys(response?.data?.errors)[0]
          ]?.[0] || "Something went wrong, try again later!";
        notifier(errorMessage, "error");
      });
    setLoading(false);
  };


  const recoverPassword = async (values: any) => {
    setLoading(true);
    await authService
      .resetPassword({ ...values, email: cookiesEmail["email"] })
      .then((response: any) => {
        if (response?.error) {
          setError(response?.error?.message);
        }
        if (response?.data) {
          setError("");
          window.location.href = "/sign-in";
        }
      });
    setLoading(false);
  };

  const resendCode = async (values: any) => {
    setLoading(true);
    await authService.resendCode({ ...values }).then((response: any) => {
      if (response?.error) {
        setError(response?.error?.message);
      }

      if (response) {
        setError("");
        window.location.replace("/confirm-code");
      }
    });
    setLoading(false);
  };

  const confirmCode = async (values: any) => {
    setLoading(true);
    await authService.confirmCode({ ...values }).then((response: any) => {
      if (response?.error) {
        setError(response?.error?.message);
      }
      setCookies("email", `${values?.email}`, {
        path: "/",
        sameSite: true,
      });
      if (response?.data) {
        setError("");
        <Navigate to={"forget-password"} replace />;
      }
    });
    setLoading(false);
  };

  return (
    <AuthContext.Provider
      value={{
        responseError: responseError,
        loading: loading,
        visibleLogout: visibleLogout,
        setVisibleLogout: setVisibleLogout,
        logout: logout,
        login: login,
        recoverPassword: recoverPassword,
        isAuthenticated: authenticated,
        setAuthenticated: setAuthenticated,
        confirmCode: confirmCode,
        userId: userId,
        resendCode,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
};

export default AuthContextProvider;

Solution

  • AuthContextProvider will provide the value and to access the values in a component, you have to wrap the provider where you mount the component eg: app.tsx.

    Here you are trying to access the AuthContext value in app.tsx. But App component is not wrapped by AuthContextProvider. I would suggest you move this provider to index.js and wrap it to App component, if you want to access it's context values in App.tsx.

    Like below:

    import {AppContextProvider} from '../domain';
    
    ReactDOM.createRoot(document.getElementById('root')).render(
        <AuthContextProvider>
            <App />
        </AuthContextProvider>
    )