示例代码:
import { StrictMode } from "react"
import ReactDOM from "react-dom"
function Test(): React.ReactElement {
console.log('render')
Promise.resolve()
.then(() => console.log('then ' + Math.random()))
return <></>
}
ReactDOM.render(
<StrictMode>
<Test />
</StrictMode>,
document.getElementById("root")
)
输出信息:
20:44:20.264 render
20:44:30.267 then 0.5430662800781927
40:44:30.267 then 0.9662426372351125
原因:
在React strict模式下,React可以多次运行render,这可以部分解释你所看到的内容。
在某些情况下,React会修改console.log()
等控制台方法以使日志静默。
从React 17开始,React会自动修改console.log()等控制台方法,在对生命周期函数的第二次调用中关闭日志。但是,在可以使用解决方案的某些情况下,它可能会导致不希望的行为。
显然,当从Promise回调调用console.log时,它不会这样做。但当从render调用时,它会这样做。
当启用了严格模式(仅在开发模式下)时,会有第二次运行渲染函数,在第二次(同步)运行期间,React 会在第二次(同步)运行期间对console
方法(调用disableLogs();
)进行monkey patch,因此它不会输出。修改日志输出,这段代码被插入到packages/react-reconciler/src/ReactFiberBeginWork.js
中,如下,
if (__DEV__) {
ReactCurrentOwner.current = workInProgress;
setIsRendering(true);
nextChildren = renderWithHooks(
current,
workInProgress,
render,
nextProps,
ref,
renderExpirationTime,
);
if (
debugRenderPhaseSideEffectsForStrictMode &&
workInProgress.mode & StrictMode
) {
disableLogs(); // <--
try { // <--
nextChildren = renderWithHooks(
current,
workInProgress,
render,
nextProps,
ref,
renderExpirationTime,
);
} finally { // <--
reenableLogs(); // <--
}