Skip to content

useState Dispatch updaters for State That Depends on Current Value

Use Dispatch Updaters for State That Depends on Current Value

Section titled “Use Dispatch Updaters for State That Depends on Current Value”

When the next state depends on the current state, use a dispatch updater (setState(prev => ...)) instead of reading the state variable directly in a callback. This avoids stale closures and ensures you’re comparing against the latest value.

Incorrect (reads state directly):

const [size, setSize] = useState<Size | undefined>(undefined)
const onLayout = (e: LayoutChangeEvent) => {
const { width, height } = e.nativeEvent.layout
// size may be stale in this closure
if (size?.width !== width || size?.height !== height) {
setSize({ width, height })
}
}

Correct (dispatch updater):

const [size, setSize] = useState<Size | undefined>(undefined)
const onLayout = (e: LayoutChangeEvent) => {
const { width, height } = e.nativeEvent.layout
setSize((prev) => {
if (prev?.width === width && prev?.height === height) return prev
return { width, height }
})
}

Returning the previous value from the updater skips the re-render.

For primitive states, you don’t need to compare values before firing a re-render.

Incorrect (unnecessary comparison for primitive state):

const [size, setSize] = useState<Size | undefined>(undefined)
const onLayout = (e: LayoutChangeEvent) => {
const { width, height } = e.nativeEvent.layout
setSize((prev) => (prev === width ? prev : width))
}

Correct (sets primitive state directly):

const [size, setSize] = useState<Size | undefined>(undefined)
const onLayout = (e: LayoutChangeEvent) => {
const { width, height } = e.nativeEvent.layout
setSize(width)
}

However, if the next state depends on the current state, you should still use a dispatch updater.

Incorrect (reads state directly from the callback):

const [count, setCount] = useState(0)
const onTap = () => {
setCount(count + 1)
}

Correct (dispatch updater):

const [count, setCount] = useState(0)
const onTap = () => {
setCount((prev) => prev + 1)
}