admin管理员组

文章数量:1397048

I'm ing from a Vue background and I'm having a really hard time understanding how to show something conditionally when the HTML is split into multiple parts.

Suppose I got the following structure:

import React, { useState } from "react";
const [mobileNavOpen, setMobileNavOpen] = useState(false);

function Home() {
  return (
    <div>
      <button
        onClick={(): void => setMobileNavOpen(true)}
        type="button"
        className="btn"
      >
        X
      </button>
      {mobileNavOpen && <MobileNav />}
    </div>
  );
}

function MobileNav() {
  return (
    <div>
      <button
        onClick={(): void => setMobileNavOpen(false)}
        type="button"
        className="btn"
      >
        X
      </button>
    </div>
  );
}

export default Home;

How would I be able to access [mobileNavOpen, setMobileNavOpen] in both Home() and MobileNav(). Basically what I want to achieve is a Home Component where users can press a button upon which a MobileMenu Component opens with yet another button they can use to close the menu again.

Right now, the 2nd line from the top const [mobileNavOpen, setMobileNavOpen] = useState(false); results in Error: Invalid hook call. Hooks can only be called inside of the body of a function ponent. but where would I put it?

Should this line be in the Home() Component and all child ponents emit an event to show or close the Menu? Or do I need a state management library for something as simple as this? What is the "React" way to do this?

I'm ing from a Vue background and I'm having a really hard time understanding how to show something conditionally when the HTML is split into multiple parts.

Suppose I got the following structure:

import React, { useState } from "react";
const [mobileNavOpen, setMobileNavOpen] = useState(false);

function Home() {
  return (
    <div>
      <button
        onClick={(): void => setMobileNavOpen(true)}
        type="button"
        className="btn"
      >
        X
      </button>
      {mobileNavOpen && <MobileNav />}
    </div>
  );
}

function MobileNav() {
  return (
    <div>
      <button
        onClick={(): void => setMobileNavOpen(false)}
        type="button"
        className="btn"
      >
        X
      </button>
    </div>
  );
}

export default Home;

How would I be able to access [mobileNavOpen, setMobileNavOpen] in both Home() and MobileNav(). Basically what I want to achieve is a Home Component where users can press a button upon which a MobileMenu Component opens with yet another button they can use to close the menu again.

Right now, the 2nd line from the top const [mobileNavOpen, setMobileNavOpen] = useState(false); results in Error: Invalid hook call. Hooks can only be called inside of the body of a function ponent. but where would I put it?

Should this line be in the Home() Component and all child ponents emit an event to show or close the Menu? Or do I need a state management library for something as simple as this? What is the "React" way to do this?

Share Improve this question asked Mar 11, 2020 at 21:39 Alex GoglAlex Gogl 7191 gold badge9 silver badges27 bronze badges 0
Add a ment  | 

4 Answers 4

Reset to default 4
import React, { useState } from "react";

function Home() {
  const [mobileNavOpen, setMobileNavOpen] = useState(false);
  return (
    <div>
      <button
        onClick={() => setMobileNavOpen(true)}
        type="button"
        className="btn"
      >
        X
      </button>
      {mobileNavOpen && <MobileNav setMobileNavOpen={setMobileNavOpen} />}
    </div>
  );
}

function MobileNav({setMobileNavOpen}) {
  return (
    <div>
      <button
        onClick={() => setMobileNavOpen(false)}
        type="button"
        className="btn"
      >
        X
      </button>
    </div>
  );
}

export default Home;
  1. you have to move the useState hook to the ponent body
  2. pass down the state setter function to your child ponent

if your Home() Component renders MobileNav() Component you should put const [mobileNavOpen, setMobileNavOpen] = useState(false) in Home() like:

const Home = () => {
   const [mobileNavOpen, setMobileNavOpen] = useState(false)

   return ( 
   <>
    ...
    <MobileNav 
      handleMobileNav={mobileNavOpen}
    />
    ...
   </>)
}

const MobileNav = ({ handleMobileNav }) => {

   return <></>
}

A simple way would be to pass the state modifier down to the child ponent. For this the hook needs to be moved inside the parent ponent.

import React, { useState } from "react";


function Home() {
  const [mobileNavOpen, setMobileNavOpen] = useState(false);
  return (
    <div>
      <button
        onClick={(): void => setMobileNavOpen(true)}
        type="button"
        className="btn"
      >
        X
      </button>
      {mobileNavOpen && <MobileNav setMobileNavOpen={setMobileNavOpen} />}
    </div>
  );
}

function MobileNav(setMobileNavOpen) {
  return (
    <div>
      <button
        onClick={(): void => setMobileNavOpen(false)}
        type="button"
        className="btn"
      >
        X
      </button>
    </div>
  );
}

export default Home;

Alternatively, you could abstract this a little so that your child ponent defines only what's required:

import React, { useState } from "react";

function Home() {
  const [mobileNavOpen, setMobileNavOpen] = useState(false);
  return (
    <div>
      <button
        onClick={(): void => setMobileNavOpen(true)}
        type="button"
        className="btn"
      >
        X
      </button>
      {mobileNavOpen && <MobileNav onClose={() => setMobileNavOpen(false)} />}
    </div>
  );
}

function MobileNav(onClose) {
  return (
    <div>
      <button
        onClick={(): void => onClose()}
        type="button"
        className="btn"
      >
        X
      </button>
    </div>
  );
}

export default Home;

The docs provide some good best practices for managing shared state.

Should this line be in the Home() Component and all child ponents emit an event to show or close the Menu?

Yes. Then pass state to the MobileNavComponent

本文标签: javascriptReact Hookshow to share state between two functionsStack Overflow