useContext Cannot read properties of undefined (reading 'name')

Advertisements

I am saving a user object into the browser cookies and want to read its properties in the frontend.
The error I am getting is:

Cannot read properties of undefined (reading 'name')
TypeError: Cannot read properties of undefined (reading 'name')
    at ProfileCard (http://localhost:3000/main.2a650ebd2579fa9c50cd.hot-update.js:56:26)

userContext.jsx

import axios from 'axios';
import { createContext, useState, useEffect } from 'react';

export const UserContext = createContext({});

export function UserContextProvider({ children }) {
    const [user, setUser] = useState(null);
    useEffect(() => {
        if (!user) {
            axios.get('/profile').then(({ data }) => {
                setUser(data);
            });
        }
    }, []);

    return <UserContext.Provider value={user}>{children}</UserContext.Provider>;
}

index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import {
    BrowserRouter as Router,
    Routes,
    Route,
    Navigate,
} from 'react-router-dom';

import './index.css';

import App from './App';
import Signup from './pages/auth/Signup';
import Login from './pages/auth/Login';
import axios from 'axios';
import { Toaster } from 'react-hot-toast';
import { UserContextProvider } from './context/userContext';

axios.defaults.baseURL = 'http://localhost:8000';
axios.defaults.withCredentials = true;

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <UserContextProvider>
        <Toaster position='bottom-right' toastDuration={{ duration: 2000 }} />
        <Router>
            <Routes>
                <Route path='/dashboard' element={<App />} />
                <Route path='/signup' element={<Signup />} />
                <Route path='/login' element={<Login />} />
                <Route exact path='/' element={<Navigate to='/dashboard' />} />
            </Routes>
        </Router>
    </UserContextProvider>
);

ProfileCard.jsx

import React, { useState, useContext } from 'react';
import { Link } from 'react-router-dom';
import { UserContext } from '../../context/userContext';

export default function ProfileCard() {
    const [isProfileExpanded, setProfileExpanded] = useState(false);
    const { user } = useContext(UserContext);

    return (
                       ...
                        <a
                            className='block px-4 py-2 text-sm text-gray-700'
                            role='menuitem'
                        >
                            {user.name}
                        </a>
                       ...

The profile with the user gets stored in the browser like this:

{
    "email": "test@gmail.com",
    "id": "66599569fd060626919b7ed7",
    "name": "Luke",
    "iat": 1717685285
}

Why can’t I access these properties of the object? The route to the backend is working perfectly fine and giving back the correct data I need but I simply cannot access it in the frontend.

>Solution :

The value of useContext is exactly what you set it to in the provider. Sometimes that is an object with properties in it, but other times it is a singular value.

You have set it to be user, so the correct way to access the user through context would be

// const { user } = useContext(UserContext);
const user = useContext(UserContext);

You are getting an error because user is null, and by destructuring the value of the context, it’s actually trying to access a user property on the user (user.user -> null.user).

While making this change will fix this specific error, you will still need to account for the fact that user will be null initially, since later on in the component user.name will not work (null.name).

You can help this by setting the initial state to an empty object

const [user, setUser] = useState({});

or by accounting for it using the nullsafe operator (?.) in your component

const user = useContext(UserContext);
    
return (
  ...
  <a
    className='block px-4 py-2 text-sm text-gray-700'
    role='menuitem'
  >
    {user?.name}
  </a>
  ...
);

Leave a ReplyCancel reply