React Hooks Cheat Sheet: Usestate Usereducer
React Hooks Cheat Sheet: Usestate Usereducer
Used to extract common behavior of components, like async requests: Memoize a value with useMemo
return [value, setAndPersistValue]
}
const useApiResult = (param) => { const value = useMemo(() => {
const [result, setResult] = useState(null) // Will be evalutated only when param1 or param2 change // Usage
return expensiveOperation(param1, param2) const [name, setName] = usePersistedState('name', 'John Doe')
useEffect(() => { }, [param1, param2])
fetch('http://your.api?param=' + param)
Get an element’s size
.then((res) => res.json())
.then((result) => setResult(result))
}, [])
Memoize a callback with useCallback const useElementSize = (elementRef) => {
const [width, setWidth] = useState(undefined)
return { result } // Will return a new function only when param1 or param2 change const [height, setHeight] = useState(undefined)
} const handleClick = useCallback(() => {
// To use it in a component: doSomethingWith(param1, param2) useEffect(() => {
const { result } = useApiResult('some-param') }, [param1, param2]) const resizeObserver = new ResizeObserver((entries) => {
for (let entry of entries) {
if (entry.contentRect) {
Memoize callback for a dynamic list of elemments: setWidth(entry.contentRect.width)
Getting the current state in async code setHeight(entry.contentRect.height)
// The same function for all the buttons created dynamically }
Problem: in a useEffect , you want to get the value of the current state to const handleClick = useCallback((event) => { }
const button = event.target })
update it (e.g. increment a number)
const value = button.getAttribute('data-value') resizeObserver.observe(elementRef.current)
doSomethingWith(value)
const [val, setVal] = useState(0)
}, []) return () => {
useEffect(() => {
setInterval(() => { resizeObserver.disconnect()
<ul> }
setVal(val + 1)
{objects.map((obj) => ( }, [elementRef])
}, 1000)
<li key={obj.id}>
}, [])
<button data-value={obj.value} onClick={handleClick}> return [width, height]
console.log(val) // always logs 0 :(
{obj.value} }
</button>
Solution 1: use the other syntax of setValue : </li> // Usage
))} const div = useRef()
const [val, setVal] = useState(0) </ul> const [width, height] = useElementSize(div)
useEffect(() => { <div style={{ resize: 'both' }} ref={div} />
setInterval(() => {
// val always contain the current value Contexts & provider/consumer with useContext Get the user’s geolocation
setVal((val) => val + 1)
}, 1000)
}, [])
Create the context: const useGeolocation = () => {
console.log(val) // logs 0, 1, 2, 3... :) const [status, setStatus] = useState('pending')
const themeContext = createContext() const [latitude, setLatitude] = useState(undefined)
const [longitude, setLongitude] = useState(undefined)
Solution 2: use a ref containing the current value:
Create a specific provider for the context:
useEffect(() => {
const [val, setVal] = useState(0) navigator.geolocation.getCurrentPosition(
const ThemeProvider = ({ children, initialTheme = 'light' }) => {
(res) => {
const valRef = useRef(val) const [theme, setTheme] = useState(initialTheme)
setStatus('success')
useEffect(() => (valRef.current = val), [val]) return (
setLatitude(res.coords.latitude)
<themeContext.Provider value={[theme, setTheme]}>
setLongitude(res.coords.longitude)
useEffect(() => { {children}
},
setInterval(() => { </themeContext.Provider>
(err) => {
// valRef.current contains the current value )
console.log(err)
setVal(valRef.current + 1) }
setStatus('error')
}, 1000) }
}, []) // Usage
)
console.log(val) // logs 0, 1, 2, 3... :) ;<ThemeProvider initialTheme="dark">
}, [])
<Label>Hello</Label>
</ThemeProvider>
return { status, latitude, longitude }
Solving infinite loops with useEffect }
Create a custom hook to consume the context:
Cause 1: no dependencies array: // Usage
const useTheme = () => { const { status, latitude, longitude } = useGeolocation()
const [theme, setTheme] = useContext(themeContext)
useEffect(() => {
// Add here additional logic if necessary...
asyncFunction().then((res) => setValue(res))
return [theme, setTheme]
})
} Struggling with hooks, or want to be more comfortable with them?
Solution: always pass an array as second parameter to useEffect : // Usage
Learn how to use them and solve the problems they cause:
const [theme, setTheme] = useTheme()
useEffect(() => {
// ...
}, [])
Created by@scastiel