React hooks
ti# React Hooks
Date: 2021-12-26
- Why React Hooks?
- useState
- useEffect
- useReducer
- useCallback and useMemo
useContext
useEffect
vsuseLayoutEffect
useImperativeHandle
React.forwardRef
Why React Hooks?¶
- Always use functional components No need to switch to class component to get state
1 .Classes: duplicate code in lifecycle methods¶
custom hooks too!
componentDidMount() {
this.updateRepos(this.props.id)
}
componentDidUpdate (prevProps) {
if (prevProps.id !== this.props.id) {
this.updateRepos(this.props.id)
}
}
becomes
Historical Context¶
uidotdev: Why React Hooks? (history)
React.createClass
ES6 class
- now: just functions!
2. Sharing non-visual logic¶
- Higher Order Components (HOC)
withRouter
- injects extra props that's shared between components
- Render prop
<Route path="/home" render={() => <p>Home</p>} />
Custom Hooks¶
Custom hooks are just regular functions that happen to use other hooks
They can return anything, do anything
Before: HOCs
After: custom hooks
2 Rules of Hooks¶
- Hooks must be used in a React component
- Hooks must be declared at the top of the function 3. must be called in the same order every time 3. can't be in an
if
statement 5. see implementation of useState
useState¶
- accepts a function which is a lazy initializer!
useState
ignores 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
type
prop
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)
useMemo
can 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
, theonItemClick
would be redefined whenever auseState
or a parent's state changes- which means
<MyBigList />
would be re-rendered every timeuseState
or 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
fetch
in auseCallback
- the
useEffect
inuseAsync
becomesrun
which is memoized withuseCallback
- they can put it in a
useEffect
andrun(result)
safeDispatch
(safe fetch) and useEffect
cleanup¶
- Memory leak when unmounting before the
fetch
finishes - it's not a class component so we can't just have a
componentWillMount
and 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
ref
as 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-03-30