I have a reducer inside useContext/provider. I need to validate an action using values from another Provider. Is there a way to retrieve those values from a Provider from within the useReducer hook? Or do I have to try to feed them in as function arguments. Ex:
Reducer
export default function reducer(state: State, action: Action): State {
switch(action.type) {
case "set-amount": {
const { amount } = action.state
const { maxAmount } = useFooContext()
if (amount > maxAmount) // do something
return { ...state, amount }
}
}
}
Provider
export function Provider(...) {
const [state, dispatch] = useReducer(reducer, {}, initState)
return ...
}
=== EDIT per @Drew
Wondering if I'm following what you said, does this look right?
// provider
export default function Provider( ... ) {
const foo = useFooContext()
const fooRef = React.useRef(foo)
const reducerFn = useMemo( () => {
fooRef.current = foo
return reducer( fooRef )
}, [foo])
const [state, dispatch] = useReducer( reducerFn, {}, initState)
return ( ... )
}
// reducer
export default function(ref: React.MutableRefObject<Foo>) {
return function(state: State, action: Action): State {
...
fooRef.current.value != value
...
}
}
You can't call React hooks in nested functions, this breaks React's Rules of Hooks, only call hooks at the top-level in React functions and custom hooks.
I suggest re-writing the reducer function to curry the Foo context value when it's instantiated.
Example:
const reducer = (fooContext: FooContext) => (state: State, action: Action) => {
switch(action.type) {
case "set-amount": {
const { amount } = action.state;
const { maxAmount } = fooContext;
if (amount > maxAmount) // do something
return { ...state, amount }
}
...
}
};
export default reducer;
export function Provider(...) {
const fooContext = useFooContext();
const reducerFn = useMemo(() => reducer(fooContext), []);
const [state, dispatch] = useReducer(reducerFn, {}, initState);
return ...
}
If you need to access non-static values then you could return a "getState" method the fooContext
could access, or save fooContext
into a React ref that is passed to the curried reducer function so it can access whatever the current context value is each time.