skip to Main Content

I’ve read a ton of posts and articles, tried different approaches, inluding useContext, useReducer, etc. but i still can’t understand why state does not change and why the page is not rerendering?

const [access, setAccess] = useState(localStorage.getItem('access'));

    useEffect(() => {
        setAccess(localStorage.getItem('access'));
    }, []);

If i pass [access] to useEffect, it becomes an infinite loop. I’ve added the code in the parent component and passed access as an argument, still doesn’t work. No surprise there are more than 30 pages with similar posts and most of the answers are unclear, outdated or not working for me. AI also failed to solve this tiny problem. I’m using funcional components, most of the info I’ve found i about class-based components.

3

Answers


  1. Is your component server side or clien side?
    Check one of these examples here.
    localStorage or sessionStorage is readable only when clien side

    Login or Signup to reply.
  2. The reason your React component isn’t re-rendering when you update localStorage is that React doesn’t automatically track changes to localStorage. It only re-renders when the component’s state changes via useState or setState, and differs from the current value.

    When you do:

    const [access, setAccess] = useState(localStorage.getItem('access'));
    

    React grabs the initial value from localStorage, but it won’t re-render unless you call setAccess() with a new value.

    If you want the component to update when localStorage changes, you can listen to the storage event like this:

    useEffect(() => {
      const handleStorageChange = () => {
        setAccess(localStorage.getItem('access'));
      };
    
      window.addEventListener('storage', handleStorageChange);
      return () => window.removeEventListener('storage', handleStorageChange);
    }, []);
    

    However, this doesn’t fire for changes in the same tab, so after updating localStorage, you’ll need to manually update the state:

    localStorage.setItem('access', 'newValue');
    setAccess('newValue'); // This triggers the re-render
    

    So all in all it should look like this

    import React, { useState, useEffect } from 'react';
    
    const MyComponent = () => {
      const [access, setAccess] = useState(localStorage.getItem('access')); 
    
      useEffect(() => {
    
        const handleStorageChange = () => {
          setAccess(localStorage.getItem('access'));
        };
    
        window.addEventListener('storage', handleStorageChange);
    
        return () => {
          window.removeEventListener('storage', handleStorageChange);
        };
      }, []);
    
      const updateAccess = (newValue) => {
        localStorage.setItem('access', newValue);
        setAccess(newValue);
      };
    
      return (
        <div>
          <h1>Access Value: {access ? access : 'No Access'}</h1>
          <button onClick={() => updateAccess('newAccessValue')}>
            Update Access
          </button>
        </div>
      );
    };
    
    export default MyComponent;
    

    Let me know if this helps!

    Login or Signup to reply.
  3. You made a mistake using useEffect. In function components, useEffect works like componentDidMount or componentWillMount in class components. This is , the code inside useEffect is executed when the dependencies of useEffect change.

    But in your code, you don’t have any dependency so the useEffect will be executed like componentDidMound, in order words, it will be only once excuted once function component is mounted.

    In this caes, if you set initial state value of accces to null or an empty string, the page will be rendered, but since you already set initial state value of access to localStorage.getItem(‘access’), even if you try to setAccess(localStroage.getItem(‘access’) inside useEffect, the page will not rerender.

    Therefore, if you want to re-render the page based on changing the access value of localStroage, you need to listen the localStroage change event in useEffect and set the value to access to trigger rerender.

    Below is the sample code:

    const MyFunctionComponent = () => {
        const [access, setAccess] = useState(localStorage.getItem('access'))
    
    
        useEffect(() => {
            const handleStorageChange = () => {
                const updatedValue = localStorage.getItem('access');
                setAccess(updatedValue);
            };
    
            window.addEventListener('storage', onStorageChange);
    
            return () => {
                widow.removeEventListener('storage', onStorageChange);
            };
        }, [])
        
        return (
            // Please put your component content
        );
    }
    
    export default MyFunctionComponent;
    

    Note: you should use a cleanup function in useEffect to avoid potential mistakes in the future.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search