简体   繁体   中英

Why useState in React Hook not update state

When i try example from React Hook, i get a problem about useState .

In code below, when click button, i add event for document and check value of count . My expect is get count in console.log and view as the same. But actual, i got old value (init value) in console & new value in view . I can not understand why count in view changed and count in callback of event not change.

One more thing, when i use setCount(10); (fix a number). And click button many time (>2), then click outside, i got only 2 log from checkCount . Is it React watch count not change then don't addEventListener in next time.

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;

If you want to capture events outside of your component using document.addEventListener, you will want to use the useEffect hook to add the event, you can then use the useState to determine if your capturing or not.

Notice in the useEffect I'm passing [capture] , this will make it so the useEffect will get called when this changes, a simple check for this capture boolean determines if we add the event or not.

By using useEffect, we also avoid any memory leaks, this also copes with when your unmount the component, it knows to remove the event too.

 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> 

@Keith i understand your example but when i apply get some confuse. In origin, i always call function is handleClick and still call it after run handleClickOutside but now i don't know how to apply that with hook.

This is my code that i want insted of 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM