CustomHook:避免在回调中使用旧的作用域

时间:2020-05-07 17:12:35

标签: reactjs react-hooks

我是React的新手,我创建了一个最小的测试应用程序来说明scope的问题。

import React, { useState, useEffect } from 'react';
import logo from './logo.svg';
import './App.css';


function useCounter(topic, defaultMsg) {
  const [message, setMessage] = useState(defaultMsg);

  const increment=() =>{
      console.log("increment from " + message);
      setMessage(message+1);
  }

  return [message, increment];
}

export default function App() {
  const [counter, incrementCounter] = useCounter("anyData", 0);


  return (
    <div>
      <p>you clicked: {counter} times</p>

      <button
        onClick={() => {
          console.log("sending ");
          incrementCounter(counter); //works 
          incrementCounter(counter); //doesn't work because using the old scope
        }}
      >
        Click me
      </button>
    </div>
  );
}

输出

App.js:10 increment from 0
App.js:10 increment from 0  //should be 1
App.js:27 sending 
App.js:10 increment from 1 
App.js:10 increment from 1  //should be 2

如果按下按钮,则incrementCounter被调用两次。预期的行为:每次单击都会使计数器增加2。但是,这并不是因为useCounter钩似乎使用了message的旧值。因此,每次点击都会使计数器增加1。我知道为什么这样不起作用,也不知道如何解决。

您将如何解决该问题?

1 个答案:

答案 0 :(得分:1)

问题是事件处理程序中的状态更新调用是成批处理的,因此在不使用回调方法的情况下多次调用setState不会正确更新值

思考代码

      incrementCounter(counter); 
      incrementCounter(counter); 

 setMessage(message + 1);
 setMessage(message + 1);

现在,这两个调用已合并,将应用于setState的最终更改为message + 1,其中1

状态更新也是异步的,不会立即反映出来

如果将setMessage实现更改为function state update

setMessage(prevMessage => prevMessage+1);

您将看到期望的输出,因为在这种情况下,批处理不是由react执行的,并且状态将增加两次。但是,由于setState的异步特性,您仍将在控制台中看到相同的输出

Sample DEMO