React Hooks
[[Why React Hooks]]
- useState
- useEffect
- useReducer
- useCallback and useMemo
useContextuseEffectvsuseLayoutEffectuseImperativeHandleReact.forwardRef
2 Rules of Hooks¶
- Hooks must be used in a React component
- Hooks must be declared at the top of the function
- must be called in the same order every time
- can't be in an
ifstatement - see implementation of useState
useState¶
- accepts a function which is a lazy initializer!
useStateignores the param afterward- for computationally expensive stuff (async, like getFromLocalStorage)
-
so that the expensive function only runs once¶
Problem with this¶
Solution¶
const [count, setCount] = useState(0)
- setCount(count + 1)
+ setCount(currentCount => currentCount + 1)
Implementing useState¶
useEffect¶
- dependency array does a
===comparison- will always re-render if you pass it an array/object
Implementing useEffect¶
useReducer¶
ate range greaterdhttps://beta.reactjs.org/reference/react/useReducer
function reducer(state, action) {
if (action.type === 'increment') {
return {
age: state.age + 1
};
}
throw Error('Unknown action.');
}
- first prop: the old state
- second prop: whatever you pass to
dispatch- usually
action
- usually
- doesn't have to follow the Redux style of having actions with a
typeprop
Implementing useState with useReducer¶
function countReducer(state, newState) {
return newState;
}
const [count, setCount] = useReducer(countReducer, 0);
setCount(1);
useReducer vs useState¶
- useReducer might be good for more complex logic
useRef¶
Why can't we have a direct pointer to a ref?
Why is the API like
The pointer will change
We have an object so that when the ref changes, it just changes the object pointer
Uses of useRef
- pointing to DOM elements
- the pointers to the DOM elements are re-rendered all the time
- Store state where we don't need to rerender when it changes
useRef to access the previous props/state¶
const usePrevious = <ValueType,>(value: ValueType): ValueType | undefined => {
const ref = useRef<ValueType>();
useEffect(() => {
ref.current = value;
});
return ref.current;
};
export default usePrevious;
Usage
useCallback and useMemo¶
Use cases (https://kentcdodds.com/blog/usememo-and-usecallback)
- not have a function re-render every time so that it can be used in a useEffect dep array
- avoiding unnecessary re-renders when re-rendering is super expensive (Graphs, Charts, Animations)
useMemocan be passed a function (just likeuseState) and lazily calculate computationally expensive items
import { useCallback } from 'react';
const MyParent = ({ seardchTerm }) => {
const onItemClick = useCallback(event => {
...
}, [term]);
return (
<MyBigList
searchTerm={searchTerm}
onItemClick={onItemClick}
/>
);
}
- Without
useCallback, theonItemClickwould be redefined whenever auseStateor a parent's state changes- which means
<MyBigList />would be re-rendered every timeuseStateor a parent's state is called
- which means
useAsync custom hook using useCallback¶
advanced-react-hooks/02.md at main · advanced-react-hooks
???
what's the run function that we return in useAsync?¶
- instead of the user putting their
fetchin auseCallback - the
useEffectinuseAsyncbecomesrunwhich is memoized withuseCallback - they can put it in a
useEffectandrun(result)
safeDispatch (safe fetch) and useEffect cleanup¶
- Memory leak when unmounting before the
fetchfinishes - it's not a class component so we can't just have a
componentWillMountand abort thefetch - I have to cancel subscriptions and async tasks in the useEffect cleanup function
How do you know if a component has been unmounted?¶
React.useLayoutEffect(() => {
mountedRef.current = true;
return () => {
mountedRef.current = false;
};
}, []);
useContext¶
useEffect vs useLayoutEffect¶
- same API
- useEffect is run after pixels are painted
- useLayoutEffect is run before so it will delay painting
- can update the DOM before it paints
useImperativeHandle¶
- ????
React.forwardRef¶
- can pass a
refas a second param- instead of the first param with all the other regular props
Could you put ref as a prop? in the first param of the component?
- yeah but that would cause a re-render
- you might not want to always re-render when the ref that's passed down to the component changes
Do you need to always use useImperativeHandle when using React.forwardRef?¶
useDebugValue¶
- feels like
__repr__in Python for custom hooks
Last update:
2023-04-24