What is a derived state?
A derived state is a value that is computed from a state value. For example:
import React from 'react'
const Example: React.FC = () => {
const [counter, setCounter] = useState(0)
const doubleCounter = counter * 2
return <p>{doubleCounter}</p>
}
This might be a trivial example, but I've seen it used in a totally wrong way many times in React codebases.
import React, { useEffect } from 'react'
const Example: React.FC = () => {
const [counter, setCounter] = useState(0)
const [doubleCounter, setDoubleCounter] = useState(0)
useEffect(() => {
setDoubleCounter(counter * 2)
}, [counter])
return <p>{doubleCounter}</p>
}
Why is this wrong? Because we are forcing React to update twice without any reason. The first time it updates when the counter
changes, and the second time when the doubleCounter
changes.
Another very common use case is computing a state from the prop:
// with `useEffect`
import React, { useEffect } from 'react'
const Example: React.FC<{ property: string[] }> = ({ property }) => {
const [counter, setCounter] = useState(0)
const [transformedProperty, setTransformedProperty] = useState<string[]>([])
useEffect(() => {
const filtered = property.filter(p => p === 'derived')
setTransformedProperty(filtered)
}, [property])
return <p>{doubleCounter}</p>
}
// without `useEffect`
import React, { useEffect } from 'react'
const Example: React.FC<{ property: string[] }> = ({ property }) => {
const [counter, setCounter] = useState(0
const transformedProperty = property.filter(p => p === 'derived') // can be wrapped in `useMemo` for performance reason
return <p>{doubleCounter}</p>
}
Now, how many times have you seen data fetched from the API, and then in useEffect
it gets transformed and stored in a state? Transformed data shouldn't be stored in a state variable, it should be stored in a regular JS variable to avoid unnecessary reconciliations like in the first code example.