Not every variable has to be a state entry in your component. Sometimes we have derived or dependent variables on one state variable. (derived state).
For better performance and to avoid extra calculations and bugs, you need to use "derived state."
Lets have an example of fetching items from an API but we need to calculate the number of pages based on the total returned by the response. I have seen many making this mistake β¬οΈβ
const Items =() => {
const rowsPerPage = 10;
const [response, setResponse] = useState<{items: Item[], total: number}>({items: [], total: 0})
const [pages, setPages] = useState<number>(0)
useEffect(() => {
setPages(Math.ceil(response.total/rowsPerPage))
}, [response])
// fetch data and set response logic here
return (
// render items and pagination...
)
}
This lis not good for simple reasons:
- pages is a derived state, it is tightly related to the data we are fetching. pages state variable makes no sense in our component without our fetched data.
- Making it a state variable is an extra calculation for our component.
-
pages can be set manually (
setPages(99)
) which will lead to bugs and inconsistent logic.
β
The right way to do it to use useMemo for React or computed for Angular to calculate the number of pages base on our only state response
const Items =() => {
const rowsPerPage = 10;
const [response, setResponse] = useState<{items: Item[], total: number}>({items: [], total: 0})
const pages = useMemo(() => {
return Math.ceil(response.total/rowsPerPage)
}, [response])
// fetch data and set response logic here
return (
// render items and pagination...
)
}
β Now it is clean, performant and it will allow reusability if you want to abstracting the calculation logic of the derived state.
Good to watch π Don't use effects
Top comments (1)
Yes, derived state is crucial for all frameworks (and libraries) and yes,
useMemo()
is the correct equivalent of Angular'scomputed()
, which is very close to Preact'scomputed()
as well as Vue's computed properties.But in React, if the state comes just from a prop, you can simply calculate derived state straight away, there's no need for
useMemo()
.