skip to Main Content

I’m encountering an issue with a React component that utilizes useState and useEffect hooks to manage state and persist it in localStorage. The component is intended to create a toggleable section with a title and content, where the expanded state is stored in localStorage. However, I’m experiencing difficulties where the state is not updating correctly, especially after page refreshes.

Here’s the code for the component:

const ToggleSection = ({ title, children }) => {
  const [expanded, setExpanded] = useState(false);

  useEffect(() => {
    const storedState = localStorage.getItem(`toggleSection_is_toggled_${title.replace(' ', '_')}`);

    if (storedState !== null) {
      setExpanded(storedState === 'true');
    }
  }, [title]);

  useEffect(() => {
    localStorage.setItem(`toggleSection_is_toggled_${title.replace(' ', '_')}`, expanded.toString());
  }, [expanded, title]);

  const toggleExpanded = () => {
    setExpanded(!expanded);
  };

  useEffect(() => {
    console.log("Updated Expanded:", expanded);
  }, [expanded]);

  console.log("Render Expanded:", expanded);

  return (
    <div className={Styles['toggle-section']}>
      <div className={Styles['toggle-header']} onClick={toggleExpanded}>
        <h2 className={Styles['toggle-title']}>{title}</h2>
        <span className={Styles['toggle-icon']}>{expanded ? '−' : '+'}</span>
      </div>
      {expanded && <div className={Styles['toggle-content']}>{children}</div>}
    </div>
  );
};

I expect the component to correctly update its state based on the value retrieved from localStorage and reflect those changes in the UI. However, after page refreshes, the state seems to be reset to false, even though the value in localStorage is correct.

I’ve tried logging the state at various points in the component, and it appears that the state is not being updated correctly after retrieving it from localStorage.

Could someone please help me understand what might be causing this issue and how I can ensure that the state is updated correctly based on the value from localStorage?

2

Answers


  1. This useEffect hook will run right away:

      useEffect(() => {
        localStorage.setItem(`toggleSection_is_toggled_${title.replace(' ', '_')}`, expanded.toString());
      }, [expanded, title]);
    

    And as soon as your component renders, it’s going to see that the default expanded state is false, and set local storage values based on that initial default value. You can do a few things, either set the initial state to null, and check to make sure it’s not null before setting local storage in that hook, or create another piece of state that would be something like const [initialRender, setInitialRender] = useState(true), and then set that to false in the first useEffect hook, and then check for that, but I really think the best approach would just be to set the values that are toggling because of the expanded state directly in the toggleExpanded function… that way you know it will only run when something is clicked.

    Login or Signup to reply.
  2. I do not have any information about the application that you are building, but if I would plan on building a scalable web app written in react and it has dynamic states like the state of the sideBar, I would prefer using the context hook. But a better solution would be using redux and redux-persist, it works really well when you have dynamic data and a complicated codebase, using context would help you in most cases but if you are thinking of having a scalable and maintainable codebase I would suggest using redux.

    Happy coding

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