Home > Blockchain >  Problem passing the state and setter function as props to child components
Problem passing the state and setter function as props to child components

Time:01-26

I have this structure of components in react :

 <App/>
      <NavBar/>
      <HeroSection/>
         <OpenNavBtn/> (this is in hero section)

I have this state in the App component : const [mainMenuIsClosed, setMainMenuIsClosed] = useState(true);

I passed the mainMenuIsClosed state, and the setMainMenuIsClosed setter function as props to HeroSection component and then to the OpenNavBtn component; I also passed them to the NavBar component;

The problem is that when I try to click on the open button the state changes to false, and then when i try to click on the close button, it changes to true, and then false when i click on the open and finally when i click on the close btn again the state doesn t change anymore.

import "./App.css";

import { Fragment, useState } from "react";
import HeroSection from "./HeroSection";
import NavBar from "./NavBar";

    function App() {
      const [mainMenuIsClosed, setMainMenuIsClosed] = useState(true);
    
      return (
        <Fragment>
          <NavBar
            mainMenuIsClosed={mainMenuIsClosed}
            setMainMenuIsClosed={setMainMenuIsClosed}
          />
          <HeroSection
            mainMenuIsClosed={mainMenuIsClosed}
            setMainMenuIsClosed={setMainMenuIsClosed}
          />
        </Fragment>
      );
    }

import "./NavBar.css";
import { useState } from "react";

export default function NavBar(props) {
  function closeNav() {
    const navbar = document.querySelector(".gaming__navbar");
    navbar.addEventListener("drag", function () {
      navbar.classList.remove("gaming__navbar-opened");
      props.setMainMenuIsClosed(
        (prevMainMenuIsClosed) => !prevMainMenuIsClosed
      );
    });
  }

  const displayCloseBtn = props.mainMenuIsClosed ? null : (
    <button onm ouseDown={closeNav} className="gaming__navbar-close-btn">
      <img
        className="gaming__navbar-close-icon"
        src="../Assets/arrowBack.png"
      />
    </button>
  );
}

export default function HeroSection(props) {
  return (
    <section className="gaming__hero-section">
      <OpenNavBtn
        mainMenuIsClosed={props.mainMenuIsClosed}
        setMainMenuIsClosed={props.setMainMenuIsClosed}
      />
 )
}

export default function OpenNavBtn({ mainMenuIsClosed, setMainMenuIsClosed }) {
  function openNav() {
    setMainMenuIsClosed((prevMainMenuIsClosed) => !prevMainMenuIsClosed);
return mainMenuIsClosed ? (
    <button onClick={openNav} className="gaming__open-nav-btn">
      <MenuSvg />
    </button>
  ) : null;
}

CodePudding user response:

It's maybe due to setting state inside eventlistner without any if condition. Try something like this

function closeNav() {
 const navbar = document.querySelector(".gaming__navbar");
  navbar.addEventListener("drag", function () {
   navbar.classList.remove("gaming__navbar-opened");
  });
 props.setMainMenuIsClosed(false);

}

And for openNav

function openNav() {
 setMainMenuIsClosed(true);
}

Hope It maybe be helpful.

CodePudding user response:

I'm going to make some assumptions about what you're trying to do vs the code you've written. I think you're looking to do this:

const App = () => {
    const [isOpen, setIsOpen] = useState(false);

    return (
        <>
            <NavBar isOpen={isOpen} setIsOpen={setIsOpen} />
            <HeroSection isOpen={isOpen} setIsOpen={setIsOpen} />
        </>
    );
};

const NavBar = ({ isOpen, setIsOpen }) => {
    return isOpen ? (
        <>
            <NavBarOpen />
            <button
                onClick={() => {
                    setIsOpen(false);
                }}
            >
                Close Nav
            </button>
        </>
    ) : (
        <NavBarClosed />
    );
};

const HeroSection = ({ isOpen, setIsOpen }) => {
    return (
        <>
            <MyHeroSection />
            {!isOpen && <button
                onClick={() => {
                    setIsOpen(true);
                }}
            >
                Open Nav
            </button>}
        </>
    );
};

You'll note there are no class selectors etc involved. Where possible it's best to let React do what it does best... manage state and decide what gets rendered depending on that state.

When you start adding Vanilla JS event listeners and adding/dropping classes you're heading into pseudo React and will often run into the sorts of issues being experienced here as your components won't be re-rendering.

NB: An even better solution would be to use the React Context API but this is a little more complex.

  • Related