React useEffect
Provides us an opportunity to write code that may have side effects on the application.
Examples use cases
- Fetching Data
- Logging
- Subscriptions
- Mutations
warning
Most common cause of confusion
Double Call Explanation
React Strict Mode
- Always specifify a dependency array
- Check that items in the dependency array are primitive values
- If dependency items is an array, function, or object, will need to memoize the value
See taming useEffect
useLayoutEffect
- useEffect is async and runs after the browser has painted
- useLayoutEffect is sync and runs before the browser has painted
If a component seems to flicker when the state is updated you should use useLayoutEffect.
- Render computing the styles for each DOM node
- Paint content to be displayed/updated on the screen
The reason for the flicker is because the callback is making visual changes to the DOM right after the component is painted.
If you need to update a ref value before any other code runs, use useLayoutEffect.
const ref = React.useRef();
React.useEffect(() => {
ref.value = 'some value';
});
// then, later in another hook or something
React.useLayoutEffect(() => {
console.log(ref.value); // logs old value as this runs first!
});
Snippets
useFetch
import React, { useState, useEffect, useRef, useLayoutEffect } from 'react';
const useCallbackRef = (callback) => {
const callbackRef = useRef(callback);
useLayoutEffect(() => {
callbackRef.current = callback;
}, [callback]);
return callbackRef;
};
export const useFetch = (options) => {
const [data, setData] = useState(null);
const savedOnSuccess = useCallbackRef(options.onSuccess);
useEffect(() => {
console.log('useFetch useEffect ');
if (options.url) {
let isCancelled = false;
fetch(options.url)
.then((response) => response.json())
.then((json) => {
if (!isCancelled) {
savedOnSuccess.current?.(json);
setData(json);
}
});
return () => {
isCancelled = true;
};
}
}, [options.url]);
return {
data,
};
};