这是检测react组件中第一次渲染的正确方法



我有一个场景,需要检测组件的第一次渲染。在这里,我构建了一个小示例。有人能向我解释一下什么是正确的方法吗?

为什么大多数人建议使用ref而不是普通状态。

https://codesandbox.io/s/condescending-burnell-0ex3x?file=/src/App.js

import React, { useState, useRef, useEffect } from "react";
import "./styles.css";
export default function App() {
const firstRender = useDetectFirstRender();
const [random, setRandom] = useState("123");
useEffect(() => {
if (firstRender) {
console.log("first");
} else {
console.log("second");
}
}, [random]);
return (
<div className="App">
<h1>Random Number is {random}</h1>
<button onClick={() => setRandom(Math.random())}>Change Name</button>
</div>
);
}
//Approach 1
// export function useDetectFirstRender() {
//   const firstRender = useRef(true);
//   useEffect(() => {
//     firstRender.current = false;
//   }, []);
//   return firstRender.current;
// }
//Approach 2
export function useDetectFirstRender() {
const [firstRender, setFirstRender] = useState(true);
useEffect(() => {
setFirstRender(false);
}, []);
return firstRender;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

您可以基于useRef为其创建一个可重用的自定义挂钩。

function useFirstRender() {
const ref = useRef(true);
const firstRender = ref.current;
ref.current = false;
return firstRender;
}

您可以使用useMemo或useCallback钩子检测并保存它。但这里最可取的是useMemo,因为它可以防止一次又一次的相同渲染。

const firstRender = useMemo(
() =>console.log('first Render'),
[]
);

在这里,它将渲染一次,并在第一次渲染中保存值,因此您可以在任何需要的地方使用它。

const firstRender = useRef(true);
useEffect(() => {
if (firstRender.current) {
firstRender.current = false;
return;
}
doSomething();
});

当使用StrictMode时,执行一些useEffect()重置/清理也很重要(return () => { isFirstRender.current = true };(。否则,isFirstRender.current将不会真正反映您想要的内容,从而导致意外的问题,尽管使用了[]依赖项,该依赖项假定仅在第一次渲染时运行(当组件安装时(。

从如何处理在开发中两次发射的效果?:

React有意在开发中重新安装组件,以查找上一个示例中的错误正确的问题不是"如何运行一次效果">,而是"如何修复我的效果,使其在重新安装后发挥作用"。

const isFirstRender = useRef(true);
useEffect(() => {
if (isFirstRender.current) {
// Do something on first render...
}
isFirstRender.current = false;
// ---> StrictMode: The following is REQUIRED to reset/cleanup:
return () => { isFirstRender.current = true };
}, []); // ---> The `[]` is required, it won't work with `[myDependency]` etc.

useEffect钩子接受第二个参数。第二个参数是一组变量,组件将检查这些变量,以确保它们在重新渲染之前已经更改。但是,如果该数组为空,则钩子在初始渲染期间只调用一次。这与之前发布的useMemo()技巧类似。

useEffect(() => doSomethingOnce(), [])
^^

最新更新