As we all know the useEffect is called once on initial render and also on subsequent change of values of dependency array.
In your case, to skip initial execution of useEffect (null case), write a little custom hook like which can be used generically when needed.
Component
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;
Custom hook
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;
If you want effect logic to run only when data is not null and data changes, you can write your custom hook like this:
import React, { useEffect } from 'react';
const useEffectOnDataChange = (callback, dataArr) => {
const someIsNull = dataArr.some(data => data == null);
useEffect(() => {
if (someIsNull) return;
return callback();
}, dataArr);
}
useEffectis called once per render, is there a specific issue with that? If you just don't want to see two console logs I wouldn't worry about it and the former is ok, if the effect is doing a meaningful side-effect withdataand it needs to be defined, then the latter.someServiceToFetchDatasounds very effect-y to me. This should likely be within this or another effect depending on your requirements.