11

Re-posting a similar question to my last because of a new issue. I'm trying to use context with hooks to manage authentication in my react app. I'm getting the error TypeError: Cannot destructure property 'isAuthenticated' of 'Object(...)(...)' as it is undefined., yet when I console.log the property where it's defined, I see false not undefined.

I have the context definition and provider in authContext.js

import React, { useState, useEffect, createContext } from "react";
import axios from "axios";

const AuthContext = createContext();
export { AuthContext };

const AuthContextProvider = (props) => {
  const [isAuthenticated, setIsAuthenticated] = useState(false);

  const setAuth = (boolean) => {
    setIsAuthenticated(boolean);
  };

  const apiOptions = {
    url: "users/is-verified",
    method: "GET",
    headers: {
      token: localStorage.token,
    },
  };

  function isAuth() {
    axios(apiOptions)
      .then((response) => {
        console.log("auth ran");
        const resData = response.data;
        resData === true ? setIsAuthenticated(true) : setIsAuthenticated(false);
      })
      .catch((error) => {
        console.log(error.response);
      });
  }

  useEffect(() => {
    isAuth();
  }, []);
  console.log(isAuthenticated);
  return (
    <AuthContext.Provider
      value={{ isAuthenticated, setIsAuthenticated, setAuth }}
    >
      {props.children}
    </AuthContext.Provider>
  );
};

export default AuthContextProvider;

Then I have my routes wrapped in the provider in app.js

import React from "react";
import {
  Switch,
  Route,
} from "react-router-dom";
import "./App.css";
import Register from "./components/pages/register";
import AuthContextProvider from "./components/context/authContext";
import RegisterRoutes from "./components/routing/registerRoutes";

function App() {

  return (
    <AuthContextProvider>
      <div className="App h-100 ">
        <Switch>
          <Route
            exact
            path="/register"
            render={(props) => (
              <RegisterRoutes {...props} />
            )}
          />
        </Switch>
      </div>
    </AuthContextProvider>
  );
}

export default App;

Then I have a RegisterRoutes component that returns one of two pages based on the isAuthenticated value

import React, { useContext } from "react";
import AuthContext from "../context/authContext";
import { Redirect } from "react-router-dom";
import Register from "../pages/register";

function RegisterRoutes(props) {
  const { isAuthenticated, setAuth } = useContext(AuthContext);
  console.log(isAuthenticated);

  return !isAuthenticated ? (
    <Register {...props} setAuth={setAuth} />
  ) : (
    <Redirect to="/login" />
  );
}

export default RegisterRoutes;

9 Answers 9

12

Your default export is AuthContextProvider (a component), not AuthContext (a context object): that won't work as you expect. Furthermore you are trying to export the context object inside another object:

// WRONG: export context inside {}
const AuthContext = createContext();
export { AuthContext };

Solution 1

Instead export the context variable normally (not as default):

// Export the variable
export const AuthContext = createContext();

// This works
import { AuthContext } from "../context/authContext";

Solution 2 (recommended)

A better practice is to keep the context in a separate file and export it as default:

// File AuthContext.js

import React, { createContext } from "react";

const AuthContext = createContext();

export default AuthContext;

// Import it in another file
import AuthContext from "./AuthContext.js";
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! I implemented your solution 2 and it works. That makes sense and I like keeping the two in separate files.
6

I solved this by doing a simple thing. In index, react-app, just put my provider involving my App.

ReactDOM.render(
  <React.StrictMode>
    <AuthProvider>
      <App />
    </AuthProvider>
  </React.StrictMode>,
  document.getElementById("root")
);

I have the same problem when I try set logging in localStorage.

Comments

2

For people using gatsby and context API in the page component:

you need to wrap root element with context provider in gatsby-browser.js and in gatsby-ssr.js.

Example:

import React from 'react';

import { CustomProvider } from './src/context/CustomProvider';

export const wrapRootElement = ({ element }) => {
  return <CustomProvider>{element}</CustomProvider>;
};

Comments

0

Try in your App.js define the value = {{state, dispatch}} in provider

 <UserContext.Provider value ={{state, dispatch}}>
        <Routing/>
      </UserContext.Provider>

Comments

0

you must put this {} for wrape the context during the send in other file

import {AuthContext} from "../context/authContext";

import { Redirect } from "react-router-dom";

import Register from "../pages/register";

function RegisterRoutes(props) {

  const { isAuthenticated, setAuth } = useContext(AuthContext);

Comments

0

enter image description here

This is the way I solved it, wrapping all the component in app.js file with authProvider.

Comments

0

My error was resolved once I added the AuthState in my App.js file.

import { Routes, Route } from "react-router-dom";
import { BrowserRouter as Router } from "react-router-dom";
import Home from "./screens/Home";
import "./index.css";

import Register from "./components/Register";
import Login from "./components/Login";
import AuthState from "./context/auth/AuthState";
function App() {
  return (
    <>
      <AuthState>
          <Router>
            <Navbar />
            <Routes>
              <Route exact path="/" element={<Home />} />
              <Route exact path="/register" element={<Register />} />
              <Route exact path="/login" element={<Login />} />
            </Routes>
          </Router>
      </AuthState>
    </>
  );
}

export default App;

Comments

0

In my case, I was using a custom hook with a property dependent on useContext which I was never exposing to the route. Don't forget to wrap your components with context providers!

Comments

0

This is works for me

    <BrowserRouter>
    <AppContext>
        <Header/>
        <Routes>
            <Route path="/" element={<Home/>} />
            <Route path="/category/:id" element={<Category />} />
            <Route path="/product/:id" element={<SingleProduct />} />
        </Routes>
        <Newsletter />
        <Footer />
    </AppContext>
</BrowserRouter>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.