0

I am uplifting a state between two components, and it is working. But when i go into the function that changes my state in the component that catches the data it updates but at the same time goes back to the old state

///COMPONENT THAT THROWS DATA///

import './styles/headerBar.css';
import { useEffect, useState } from 'react';

function HeaderBar(props) {
  const [state, set_state] = useState();

  const OnClickHandler = () => {
    set_state('open');
  };

  useEffect(() => {
    props.throwData(state);
  });

  return (
    <div className="wrapper header_container">
      <ul>
        <li>
          <h1 className={state == 'open' ? 'green' : 'black'}>B</h1>
        </li>
        <li onClick={OnClickHandler}>
          <span class="material-icons md-18">menu</span>
        </li>
      </ul>
    </div>
  );
}

export default HeaderBar;

///COMPONENT THAT RETRIEVE THE DATA

import './styles/menuBar.css';
import HeaderBar from './HeaderBar';
import { useEffect, useState } from 'react';

function MenuBar() {
  const [actual_class, set_class] = useState();

  const Change_class = value => {
    set_class(value);

    console.log(actual_class);
  };

  const Close_menu = () => {
    set_class(previous_state => {
      return 'closed';
    });

    console.log(actual_class);
  };

  return (
    <div>
      <div className={actual_class == 'open' ? 'hide_it' : 'show_it'}>
        <HeaderBar throwData={Change_class} />
      </div>
      <div className="wrapper menu_container">
        <h1 onClick={Close_menu}>I'am header bar</h1>
      </div>
    </div>
  );
}

export default MenuBar;

When i run "Close_menu" by clicking in the h1 tag, it turns to the new state, but soon goes back to the old one.

  • Does this answer your question? [The useState set method is not reflecting a change immediately](https://stackoverflow.com/questions/54069253/the-usestate-set-method-is-not-reflecting-a-change-immediately) – Konrad Apr 11 '23 at 15:26

2 Answers2

0
useEffect(() => {
  props.throwData(state);
});

this is a closure over the initial state, and useEffect is not restrained, it fires after every single render. So after every single render it calls throwData with the current/old state.

Besides, the entire construct with all the indirections through different states and effects is more complicated than needed. Check this out:

function HeaderBar(props) {
  return (
    <div className="wrapper header_container">
      <ul>
        <li>
          <h1 className={props.isOpen ? 'green' : 'black'}>B</h1>
        </li>
        <li onClick={props.onMenuClick}>
          <span class="material-icons md-18">menu</span>
        </li>
      </ul>
    </div>
  );
}


function MenuBar() {
  const [isOpen, setOpen] = useState(false);

  return (
    <div>
      <div className={isOpen ? 'hide_it' : 'show_it'}>
        <HeaderBar isOpen={isOpen} onMenuClick={() => setOpen(true)} />
      </div>
      <div className="wrapper menu_container">
        <h1 onClick={() => setOpen(false)}>I'am header bar</h1>
      </div>
    </div>
  );
}
Thomas
  • 11,958
  • 1
  • 14
  • 23
0

TL;DR: Move the HeaderBar's state up to the MenuBar.

NL;PR: If you have a child state that updates a parent's related state, perhaps you don't need in the child and belongs only to the parent that passes it down.

function HeaderBar({state, onClickHandler}) {
  return (
    <div className="wrapper header_container">
      <ul>
        <li>
          <h1 className={state === "open" ? "green" : "black"}>B</h1>
        </li>
        <li onClick={onClickHandler}>
          <span className="material-icons md-18">menu</span>
        </li>
      </ul>
    </div>
  );
}

function MenuBar() {
  const [actualClass, setClass] = useState();

  const closeMenu = useCallback(() => {
    setClass((previous_state) => {
      return "closed";
    });
    return true;
  }, []);

  const onClickHandler = useCallback(() => {
    setClass("open");
  }, []);

  return (
    <div>
      <div className={actualClass === "open" ? "hide_it" : "show_it"}>
        <HeaderBar state={actualClass} onClickHandler={onClickHandler} />
      </div>
      <div className="wrapper menu_container">
        <h1 onClick={closeMenu}>I'am header bar</h1>
      </div>
    </div>
  );
}
David I. Samudio
  • 2,364
  • 18
  • 21