const [state, dispatch] = useReducer(reducer, initialArg, init);
The third arguement ‘init‘ is a lazy initialization which is a function.
It is useful when you want to reset the state or dynamiclly generate the state.
function init(initialCount) { return {count: initialCount}; } function reducer(state, action) { switch (action.type) { case ‘increment‘: return {count: state.count + 1}; case ‘decrement‘: return {count: state.count - 1}; case ‘reset‘: return init(action.payload); default: throw new Error(); } } function Counter({initialCount}) { const [state, dispatch] = useReducer(reducer, initialCount, init); return ( <> Count: {state.count} <button onClick={() => dispatch({type: ‘reset‘, payload: initialCount})}> Reset </button> <button onClick={() => dispatch({type: ‘decrement‘})}>-</button> <button onClick={() => dispatch({type: ‘increment‘})}>+</button> </> ); }
Or dyanmically generate the init val:
const preferDarkQuery = ‘(prefers-color-scheme: dark)‘
function darkModeReducer(state, action) {
switch (action.type) {
case ‘MEDIA_CHANGE‘: {
return {...state, mode: action.mode}
}
case ‘SET_MODE‘: {
// make sure to spread that state just in case!
return {...state, mode: action.mode}
}
default: {
// helps us avoid typos!
throw new Error(`Unhandled action type: ${action.type}`)
}
}
}
// use the init function to lazily initialize state so we don‘t read into
// localstorage or call matchMedia every render
function init() {
return {
mode:
window.localStorage.getItem(‘colorMode‘) ||
(window.matchMedia(preferDarkQuery).matches ? ‘dark‘ : ‘light‘),
}
}
function useDarkMode() {
const [state, dispatch] = React.useReducer(
darkModeReducer,
{mode: ‘light‘},
init,
)
const {mode} = state
React.useEffect(() => {
const mediaQuery = window.matchMedia(preferDarkQuery)
const handleChange = () =>
dispatch({
type: ‘MEDIA_CHANGE‘,
mode: mediaQuery.matches ? ‘dark‘ : ‘light‘,
})
mediaQuery.addListener(handleChange)
return () => mediaQuery.removeListener(handleChange)
}, [])
React.useEffect(() => {
window.localStorage.setItem(‘colorMode‘, mode)
}, [mode])
// We like the API the way it is, so instead of returning the state object
// and the dispatch function, we‘ll return the `mode` property and we‘ll
// create a setMode helper (which we have to memoize in case someone wants
// to use it in a dependency list):
const setMode = React.useCallback(
newMode => dispatch({type: ‘SET_MODE‘, mode: newMode}),
[],
)
return [mode, setMode]
}
‘init‘ function will override the second arguement.
[React] useReducer with lazy initializtion
原文:https://www.cnblogs.com/Answer1215/p/12456556.html