Create Your Own Redux (Typescript)
2020-10-26
Prepare Initial States + State Type
export const initialState = {
attributeA: {
propertyA1: ``,
},
attributeB: {
propertyB1: 0,
},
num: 0,
};
export type StateType = {
attributeA: {
propertyA1: string;
};
attributeB: {
propertyB1: number;
};
num: number;
};
Prepare actions
type ActionMap<M extends { [index: string]: any }> = {
[Key in keyof M]: M[Key] extends undefined
? {
type: Key;
}
: {
type: Key;
payload: M[Key];
};
};
// eslint-disable-next-line no-shadow
export enum ActionType {
setAttrA = `SET_ATTR_A`,
setAttrB = `SET_ATTR_B`,
add = `ADD`,
reduce = `REDUCE`,
}
/**
* @name ActionPayload
* @description Type def for action payloads,
*/
type ActionPayload = {
[ActionType.setAttrA]: {
propertyA1: string;
};
[ActionType.setAttrB]: {
propertyB1: number;
};
/* Not payloads required for below 2 actions */
[ActionType.add]: undefined;
[ActionType.reduce]: undefined;
};
/**
* @name ActionPayloadDataType
* @description The type def of the Action Payload Data
*/
export type ActionPayloadDataType = ActionMap<ActionPayload>[keyof ActionMap<ActionPayload>];
Prepare the reducer details, NO EDIT STATE DIRECTLY
export const reducers = (
state: StateType,
actionData: ActionPayloadDataType,
): StateType => {
switch (actionData.type) {
case ActionType.setAttrA:
return {
...state,
attributeA: {
...state.attributeA,
...actionData.payload,
},
};
case ActionType.setAttrB:
return {
...state,
attributeB: {
...state.attributeB,
...actionData.payload,
},
};
case ActionType.add:
return {
...state,
num: state.num + 1,
};
case ActionType.reduce:
return {
...state,
num: state.num - 1,
};
default:
return state;
}
};
Create a HOC for state provider
export const AppContext = createContext<{
state: StateType;
dispatch: React.Dispatch<ActionPayloadDataType>;
}>({
state: initialState,
dispatch: () => null,
});
/**
* @name StateProvider
* @description A HOC to wrap root components for global state manage
*/
export const StateProvider: React.FC = ({ children }) => {
const [state, dispatch] = useReducer(reducers, initialState);
return (
<AppContext.Provider value={{ state, dispatch }}>
{children}
</AppContext.Provider>
);
};
const App: React.FC = () => (
<StateProvider>
<RootComponent/>
</StateProvider>
);
Now you can use it
const Camera: React.FC = () => {
const { state, dispatch } = useContext(AppContext);
return (
<div>
{state.num}
<button onClick={dispatch({
type: ActionType.add
})}/>
<button onClick={dispatch({
type: ActionType.setAttrB,
payload: {
propertyB1: 'dispatch this action to set property B1'
},
})}/>
</div>
);
};
export default Camera;
关于本文
文章标题 | Create Your Own Redux (Typescript) |
发布日期 | 2020-10-26 |
文章分类 | Tech |
相关标签 | #Typescript #React |