如何使用 React hooks 来确定侧边栏是否应该显示?

How to use React hooks to determine if sidebar should show?

我已经阅读了一些关于 React Hooks 的介绍,想做一个简单的应用程序,在 header 组件中有一个按钮,它决定主应用程序是否应该显示侧边栏。该按钮在 header 中设置了变量 showSidebar,我想在我的主要组件中再次读取它。为简洁起见,删除了实际显示侧边栏的代码。

这是index.js:

import React, { useState } from "react";
import ReactDOM from "react-dom";

import Header from "./header";
import "./styles.css";

function App() {
  const [showSidebar, setShowSidebar] = useState(true);

  return (
    <div className="App">
      <Header />
      <h1>Sidebar toggler</h1>

      <p>
        Should I show sidebar? <b>{showSidebar.toString()}</b>
      </p>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

这是 header.js:

import React, { useState } from "react";
export default function Header() {
  const [showSideBar, setShowSidebar] = useState(true);
  const toggleSidebar = () => setShowSidebar(!showSideBar);

  return (
    <header>
      Button in header toggles sidebar:
      <button onClick={() => toggleSidebar()}>
        Toggle sidebar (state: {showSideBar.toString()})
      </button>
    </header>
  );
}

我是 React 的新手,但不明白为什么状态在 index.js 中没有更新?我还用代码做了一个CodeSandbox

useState 是存储 local 状态,为了比较你可以认为它类似于 class 组件中的 setState (虽然在实际上他们不是 exactly equivalent)。因此,在 App 中设置 setShowSidebar 不会反映与在 Header 中设置的相同的值,反之亦然。

看起来 Header 不需要任何形式的本地状态,如果它只是改变外部组件的状态,您可以传入事件处理程序和任何相关状态 Header 需要代替道具

index.js

function App() {
  const [showSidebar, setShowSidebar] = useState(true);
  const toggleSidebar = useCallback(() => setShowSidebar(value => !value));

  return (
    <div className="App">
      <Header onClick={toggleSidebar} showSideBar={showSidebar} />
      <h1>Sidebar toggler</h1>
      <p>
        Should I show sidebar? <b>{showSidebar.toString()}</b>
      </p>
    </div>
  );
}

header.js

export default function Header(props) {
  return (
    <header>
      Button in header toggles sidebar:
      <button onClick={props.onClick}>
        Toggle sidebar (state: {props.showSideBar.toString()})
      </button>
    </header>
  );
}

你做错的是在 Header 中声明了一个你不应该做的单独状态,因为它与 parent 的状态无关。传递 parent 状态和回调以将 parent 状态作为道具更新到 header。将 showSidebar 作为 props 传递给 Header 组件:

import React, { useState } from "react";
import ReactDOM from "react-dom";

import Header from "./header";
import "./styles.css";

function App() {
  const [showSidebar, setShowSidebar] = useState(true);

  return (
    <div className="App">
     // Pass prop here
      <Header 
        showSidebar={showSidebar} 
        toggleSidebar={()=>{setShowSidebar(!showSidebar)}}
         />
      <h1>Sidebar toggler</h1>

      <p>
        Should I show sidebar? <b>{showSidebar.toString()}</b>
      </p>
    </div>
  );
}

// and then in your Header,
export default function Header(props) {
  return (
    <header>
      Button in header toggles sidebar:
      <button onClick={props.toggleSideBar}>
        Toggle sidebar (state: {props.showSideBar.toString()})
      </button>
    </header>
  );
}

您想在 parent 组件(您需要读取它的地方)中保留状态 showSidebar 并将更改它的功能传递给 header 组件(您需要的地方改变 showSidebar)

要做 toggleSidebarindex.js

const toggleSidebar = () => setShowSidebar(!showSideBar);

然后像这样将函数传递给 Header 组件

<Header toggleSidebar={toggleSidebar} />

现在像这样在 Header 组件的 clickEvent 上调用它

<button onClick={() => toggleSidebar()}>

记得在你的 Header 组件中包含道具

export default function Header({toggleSidebar}) {

你应该在 App.js 本身中有你的 toggleSidebar 函数,并在 Header 组件中传递 toggleSidebar 函数和 showSidebar 状态作为道具。

App.js

function App() {
  const [showSidebar, setShowSidebar] = useState(true)
  const toggleSidebar = () => setShowSidebar(!showSidebar)

  return (
    <div className="App">
      <Header showSideBar={showSidebar} onClick={toggleSidebar} />
      <h1>Sidebar toggler</h1>

      <p>
        Should I show sidebar? <b>{showSidebar.toString()}</b>
      </p>
    </div>
  )
}

Header.js

import React from 'react'
export default function Header(props) {
  return (
    <header>
      Button in header toggles sidebar:
      <button onClick={props.onClick}>
        Toggle sidebar (state: {props.showSideBar.toString()})
      </button>
    </header>
  )
}

Demo