Current architecture
Redux + toolkit (or something like that)
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