我知道为什么会发生这种情况,但是想知道什么是避免这种情况的正确方法。 useEffect被调用两次。一个数据= null,然后是“真实”数据。
const [data, setData] = useState(null);
someServiceToFetchData.then(freshData => setData(freshData))
useEffect(() => {
console.log("useEffect called");
}, [data]);
我应该到处做这样的事情吗?
useEffect(() => {
if (data) {
console.log("useEffect called with real data");
}
}, [data]);
答案 0 :(得分:3)
众所周知,useEffect在初始渲染时以及在依赖数组的值的后续更改中都会被调用一次。
在您的情况下,要跳过useEffect的初始执行(空情况),请编写一个小自定义钩子,例如可以在需要时通用的钩子。
组件
import React, { useState, useEffect } from 'react';
import useEffectSkipInitialRender from "./hook";
const Test = (props) => {
const [data, setData] = useState(null);
new Promise((res, rej) => res('my data')).then(freshData => setData(freshData));
useEffectSkipInitialRender(() => {
console.log("useEffect called");
}, [data]);
return <div>hi</div>
};
export default Test;
自定义钩子
import React, { useState, useEffect, useRef } from 'react';
const useEffectSkipInitialRender = (callback, dataArr) => {
const [data, setData] = useState(null);
const isInitialRender = useRef(true);// in react, when refs are changed component dont re-render
useEffect(() => {
if(isInitialRender.current){// skip initial execution of useEffect
isInitialRender.current = false;// set it to false so subsequent changes of dependency arr will make useEffect to execute
return;
}
return callback();
}, dataArr);
};
export default useEffectSkipInitialRender;
如果您希望效果逻辑仅在数据不为null且数据发生更改时才运行,则可以这样编写自定义钩子:
import React, { useEffect } from 'react';
const useEffectOnDataChange = (callback, dataArr) => {
const someIsNull = dataArr.some(data => data == null);
useEffect(() => {
if (someIsNull) return;
return callback();
}, dataArr);
}
答案 1 :(得分:0)
如果要跳过第一个渲染,可以使用这样的状态标志。我发现下面的方法不太复杂。
import React, { useState } from 'react';
const Comp = ({dep}) => {
const [rendered, setRendered] = useState(false);
useEffect(() => {
if(rendered){
// do stuff
}
if( ! rendered ) {
setRendered(true);
}
}, [dep]);
// rest of the component code
return <></>
}