I discovered that my reducer
was being called twice for each dispatch
after noticing that some of my code's functionality was broken. Now I found out that it is due to the <StrictMode>
. I would hate to remove this. If I turn on my debugger (StrictMode still there), I get this error
Cannot update a component (`ForwardRef(TouchRipple)`) while rendering a different component
As you can see, I build my provider according to the reducer-dispatch pattern
I'm posting the code, with very simple naming.
types
export type ValueState = {
value: string | null;
};
export enum AcionType {
SetValue,
}
export interface SetValue {
type: AcionType.SetValue;
value: string | null;
}
export type ValueActions = SetValue;
export type ValueDispatch = Dispatch<ValueActions>;
export type ValueContextState = {
state: ValueState;
dispatch: ValueDispatch;
};
reducer
export const valueReducer = (state: ValueState, action: ValueActions): ValueState => {
console.log("reducer") // getting called two times!!;
switch (action.type) {
case AcionType.SetValue:
return {
...state,
value: test(action.value),
};
default:
return state;
}
};
const test = (value: string | null) => {
debugger;
return value;
};
Context
export const ValueContext = createContext<ValueContextState>({
state: getDefaultState(),
dispatch: () => {},
});
export const ValueProvider = ({ children }: Props) => {
const [state, dispatch] = useReducer<React.Reducer<ValueState, ValueActions>>(valueReducer, getDefaultState());
const [contextValue, setContextValue] = useState<ValueContextState>({
state,
dispatch,
});
useEffect(() => {
setContextValue((contextValue: ValueContextState) => ({
...contextValue,
state,
}));
}, [state]);
return <ValueContext.Provider value={contextValue}>{children}</ValueContext.Provider>;
};
function getDefaultState(): ValueState {
return {
value: null,
};
}
type Props = {
children: React.ReactNode;
};
customHook
export const useValues = () => {
const { state, dispatch } = useContext(ValueContext);
const setValue = useCallback(
(value: string | null) => {
console.log("dispatch") // getting called once!
dispatch({
type: AcionType.SetValue,
value: value,
});
},
[dispatch],
);
return {
value: state.value,
setValue: setValue,
};
};
Using Provider
<Routes>
<Route
index
element={
<ValueProvider>
<Values />
</ValueProvider>
}
/>
</Routes>
making dispatch
export const Value = () => {
const { setValue } = useValues();
return <InputComponent onChange={(e) => setValue(e.target.value)} />;
};