一段很普通的代碼,出發了兩次render
import React, { useState, useEffect } from 'react'
const MouseTracker: React.FC = () => {
const [ positions, setPositions ] = useState({x: 0, y: 0})
useEffect(() => {
console.log('add effect', positions.x)
const updateMouse= (e: MouseEvent) => {
console.log('inner')
setPositions({ x: e.clientX, y: e.clientY })
}
document.addEventListener('click', updateMouse)
return () => {
console.log('remove effect', positions.x)
document.removeEventListener('click', updateMouse)
}
},[])
console.log('before render', positions.x) // 執行了兩次
return (
<>
<p>X: {positions.x}, Y : {positions.y}</p>
</>
)
}
export default MouseTracker
原因:
最近的react版本,dev模式下render使用的是strict mode,strict mode的通過兩次調用constructor和render函數來更好的檢測不符合預期的side effects
文檔中有表明
Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking the following functions:
- Class component constructor, render, and shouldComponentUpdate methods
- Class component static getDerivedStateFromProps method
- Function component bodies
- State updater functions (the first argument to setState)
- Functions passed to useState, useMemo, or useReducer
下列函數會執行兩次
- 類組件的constructor,render和shouldComponentUpdate方法
- 類組建的靜態方法getDerivedStateFromProps
- 函數組件方法體
- 狀態更新函數(setState的第一個參數)
- 傳入useState,useMemo或useReducer的函數
在production環境下不會這樣,所以不用擔心