首页 > 解决方案 > React:useReducer Hook 首先触发两次,不是 StrictMode

问题描述

不是StrictMode引起的问题。
这是我的代码,一个计数器:

let outsideCount = 0
function Counter() {
  const [count, setCount] = useReducer(doCounting, 0)

  function doCounting(count) {
    console.log(`count: ${count}`)
    console.log(`outsideCount: ${outsideCount}`)
    console.log('---------divider---------')

    outsideCount++
    return count + 1
  }

  return (
    <div>
      <span>count: {count}</span>
      <button onClick={setCount}>Click Me!</button>
    </div>
  )
}

和输出:单击1次:

count: 0
outsideCount: 0
---------divider---------
count: 0
outsideCount: 1
---------divider---------  // <<<<<<< That's the point I confused. why it triggered twice?

点击2次:

count: 1
outsideCount: 3            // <<<<<<< I KNEW that cause by StrictMode
---------divider---------  // this time it only trigger once.
// ^^^^^^^^^ but why it trigger twice only at the first click?

点击3次:

click 3 time:
count: 2
outsideCount: 5            // <<<<<<< I KNEW that cause by StrictMode
---------divider---------
// ^^^^^^^^^ the third time trigger once like expected. the first-click confused me.

我已经知道StrictMode每次点击都会outsideCount添加两次,因为它测试了一些程序员可能不会注意到的副作用。
在构建为生产之后,outsideCount按预期添加一次。

但是为什么第一次点击会触发doCounting两次功能呢?我第console一次点击时显示 2 个分隔线。
此外,在构建为生产之后,当我第一次单击时doCounting 仍然触发两次。

不寻找其他解决方案或好的/坏的做法,只是想知道为什么

标签: javascriptreactjsuse-reducer

解决方案


尽管行为或代码的运行顺序尚不清楚,
但我想我对此有所了解:function-memory-address

该功能doCounting被触发并在第一次单击时执行某些操作:
--->console打印,value返回,
然后重新渲染组件,因此再次doCounting重新创建该功能。 然后,不知何故,再次触发重新创建的函数

我想第二次是 React 真正想做的正确方式。我猜

避免函数内存地址更改的最简单方法就像我们避免对象内存地址更改的相同方法:useMemouseCallbackdeclare-it-outside

// useMemo
const doCounting = useMemo(() => value => {
  console.log(value)
  console.log('---divider---')
  return value + 1
}, [])

//or

// useCallback
const doCounting = useCallback(value => {
  console.log(value)
  console.log('---divider---')
  return value + 1
}, [])

尽管我仍然不知道函数何时被触发,但至少我们知道这是内存地址问题。

希望有人补充正确代码的运行顺序。谢谢


推荐阅读