Почему useState в React Hook не обновляет состояние - PullRequest
0 голосов
/ 09 июля 2019

Когда я пробую пример из React Hook, у меня возникает проблема с useState.

В коде ниже, когда я нажимаю кнопку, я добавляю событие для document и проверяю значение count. Я ожидаю получить count в console.log и посмотреть как то же самое. Но на самом деле, я получил старое значение (начальное значение) в console и новое значение в поле зрения. Не могу понять, почему count в поле зрения изменилось и count в обратном вызове события не изменилось.

Еще одна вещь, когда я использую setCount(10); (исправить номер). И нажмите кнопку много раз (> 2), затем нажмите снаружи, я получил только 2 журнала из checkCount. Это часы 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;

Ответы [ 2 ]

0 голосов
/ 10 июля 2019

@ Кит, я понимаю твой пример, но когда я подам заявку, получишь некоторую путаницу.По происхождению я всегда вызываю функцию 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

0 голосов
/ 09 июля 2019

Если вы хотите захватывать события вне вашего компонента с помощью 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>
...