skip to Main Content

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.

2

Answers


  1. 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>
      );
    }
    
    Login or Signup to reply.
  2. 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>
      );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search