Redux and useReducer
A quick run through
Current architecture
-
Redux + toolkit (or something like that)
- middleware (choose your flavour)
- action builder (maybe)
- ...
Positive sides
- well known technology/stack
- scalability
- proven dependability
- community
- documentation
What should I put into my store?
Negative sides
- inherited file structure
- "hard" to maintain/change something
- easy to over use
- black-box feeling (sometimes)
The proposal
- Redux + toolkit (yeah, we still like it...)
- axios
- useReducer
How to use
- Use Redux only when it actually make sense like (actual) global state or highly dynamic state that's used horizontally or by multiple components.
- use Axios as middleware for AJAX using the cancelable promise token and Promisse.All (when necessary).
- use useReducer for component-level (vertical) shared state.
Structure example
App-level state (example: session info)
component
component
component
component
component
component
component-level state
component-level state
export const componentReducer = (
state: ComponentState = initialState,
action: ActionsType
): ComponentState => {
switch (action.type) {
case 'TYPE-1':
return {
...state,
[some_piece_of_state]: action.payload,
};
// ...
default:
return state;
}
};
The Reducer
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
const axiosInstance = axios.create({
baseURL: 'https://url.com',
headers: ...,
cancelToken: source.token,
});
const MyComponent: FC<Props> = props => {
const [state, dispatch] = useReducer(componentReducer, initialState);
const fetchStuff = (data) => {
axiosInstance.post('some_url', data)
.then(...)
}
const handleCancelFetch = () => {
source.cancel();
}
const handleSomeDispatch = data => {
dipatch(({ type: 'TYPE_!', payload: data }));
}
useEffect(() => {
return () => {
// some logic here...
source.cancel();
};
}, [your_dependencies]);
return (
...
);
};
import { useEffect, useCallback, useRef } from 'react';
import axios from 'axios';
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
const axiosInstance = axios.create({
baseURL: 'https://url.com',
headers: ...,
cancelToken: source.token,
});
export const usePostData = <T>(url: string, data: <your_type_here>) => {
const promise = useRef<Promise<T>>();
const handler = useCallback(() => {
promise.current = axiosInstance.post(url, data);
return promise.current
},
[url, data]
);
useEffect(() => {
// some logic
if (promise.current) source.cancel();
}, []);
return handler;
};
Custom hook example
export type TReducerDict = { [k: string]: Reducer};
export const combineReducers = (slices: ReducerDict) => (state: AppState, action: Action) =>
Object.keys(slices).reduce(
(acc, prop) => ({
...acc,
[prop]: slices[prop](acc, action)[prop],
}),
state
);
Combine reducers example
Redux and usereducer
By Thiago Dallacqua
Redux and usereducer
- 17