【问题标题】:Why useState in React Hook not update state为什么 React Hook 中的 useState 不更新状态
【发布时间】:2023-03-21 23:16:01
【问题描述】:

当我尝试来自 React Hook 的示例时,我遇到了一个关于 useState 的问题。

在下面的代码中,当单击按钮时,我为document 添加事件并检查count 的值。 我的期望是在console.log 中获得count 并以相同的方式查看。但实际上,我在console 中得到了旧值(初始值)和视图中的新值。我不明白为什么视图中的count 发生了变化,而事件回调中的count 没有变化。

还有一件事,当我使用setCount(10);(修复一个数字)时。并多次单击按钮(> 2),然后单击外部,我从checkCount 只得到了 2 条日志。是不是 React 手表 count 不改变,那么下次不要 addEventListener

import React, { useState } from "react";

function Example() {
  const [count, setCount] = useState(0);

  const add = () => {
    setCount(count + 1);
    console.log("value set is ", count);
    document.addEventListener("click", checkCount);
  };

  const checkCount = () => {
    console.log(count);
  };

  return (
    <div>
      <p>You clicked {count} times</p>
      <p>Click button first then click outside button and see console</p>
      <button onClick={() => add()}>Click me</button>
    </div>
  );
}

export default Example;

【问题讨论】:

  • 是的,React 确实会检查 count 是否已更改,如果已更改,则仅重新渲染。
  • @PraveenKumarPurushothaman 我不是说工作正常,这里有一个非常严重的错误,事件内存泄漏..
  • 我能问一下,你想做什么。您目前在这里有一个非常严重的内存泄漏,每次单击该按钮时,您都会向 DOM 添加另一个事件侦听器。然后,您永远不会删除此类事件。通常这样的事件可以在 useEffect 钩子内附加/分离。
  • 为什么要在事件点击时添加事件监听器?

标签: reactjs react-hooks


【解决方案1】:

如果您想使用 document.addEventListener 捕获组件之外的事件,您将需要使用 useEffect 挂钩添加事件,然后您可以使用 useState 来确定您是否捕获。

useEffect 中的通知我正在传递[capture],这将使 useEffect 在此更改时被调用,对该捕获布尔值的简单检查确定我们是否添加事件。

通过使用useEffect,我们还避免了任何内存泄漏,这也可以解决当您卸载组件时,它也知道要删除事件。

const {useState, useEffect} = React;


function Test() {
  const [capture, setCapture] = useState(false);
  const [clickInfo, setClickInfo] = useState("Not yet");
  
  function outsideClick() {
    setClickInfo(Date.now().toString());
  }
  
  useEffect(() => {
    if (capture) {
      document.addEventListener("click", outsideClick);
      return () => {
        document.removeEventListener("click", outsideClick);
      }
    }
  }, [capture]);
  
  return <div>
    <p>
    Click start capture, then click anywhere, and then click stop capture, and click anywhere.</p>
    <p>{capture ? "Capturing" : "Not capturing"}</p>
    <p>Clicked outside: {clickInfo}</p>
    <button onClick={() => setCapture(true)}>
      Start Capture
     </button>
    <button onClick={() => setCapture(false)}>
      Stop Capture
    </button>
  </div>
}

ReactDOM.render(<React.Fragment>
  <Test/>
</React.Fragment>, document.querySelector('#mount'));
p { user-select: none }
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="mount"></div>

【讨论】:

  • 我了解您的示例,但无法使用钩子应用我的代码。我在下面有关于代码的答案。你能支持我吗?
【解决方案2】:

@Keith 我理解你的例子,但是当我申请时会有些困惑。在起源中,我总是调用函数是 handleClick 并且在运行 handleClickOutside 后仍然调用它,但现在我不知道如何使用钩子应用它。

这是我想要插入 Hook 的代码

class ClickOutSide extends Component {
  constructor(props) {
    super(props)
    this.wrapperRef = React.createRef();
    this.state = {
      active: false
    }
  }

  handleClick = () => {
    if(!this.state.active) {
      document.addEventListener("click", this.handleClickOut);
      document.addEventListener("contextmenu", this.handleClickOut);
      this.props.clickInside();
    } else {
      document.removeEventListener("click", this.handleClickOut);
      document.removeEventListener("contextmenu", this.handleClickOut);

    }
    this.setState(prevState => ({
      active: !prevState.active,
   }));
  };

  handleClickOut = event => {
    const { target } = event;
    if (!this.wrapperRef.current.contains(target)) {
      this.props.clickOutside();
    }

    this.handleClick()
  }

  render(){
    return (
      <div
        onDoubleClick={this.props.onDoubleClick}
        onContextMenu={this.handleClick}
        onClick={this.handleClick}
        ref={this.wrapperRef}
      >
        {this.props.children}
      </div>
    )
  }
}

export default ClickOutSide

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-09
    • 1970-01-01
    • 2021-09-22
    • 2021-08-24
    • 1970-01-01
    • 2020-09-22
    相关资源
    最近更新 更多