Cannot destructure property of object from context

22,925

Solution 1

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";

Solution 2

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.

Solution 3

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>;
};
Share:
22,925
userNick
Author by

userNick

Updated on July 12, 2022

Comments

  • userNick
    userNick almost 2 years

    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;
    
  • userNick
    userNick about 4 years
    Thank you! I implemented your solution 2 and it works. That makes sense and I like keeping the two in separate files.