【发布时间】:2020-01-27 17:57:15
【问题描述】:
我正在使用 react hooks 和 typescript。我使用useReducer() 表示全局状态。 reducer 函数的动作包含两个属性name 和data。 name 表示事件或更改的名称,data 将是该特定名称所需的特定数据。
到目前为止,名称有四个值。如果名称为"setUserData",则data 应为IUserData(接口)。如果名称是setDialog,那么data 应该是DialogNames(包含两个字符串的类型)。如果是其他内容,则不需要数据。
//different names of dialog.
export type DialogNames = "RegisterFormDialog" | "LoginFormDialog" | "";
//type for name property in action object
type GlobalStateActionNames =
| "startLoading"
| "stopLoading"
| "setUserData"
| "setDialog";
//interface for main global state object.
export interface IGlobalState {
loading: boolean;
userData: IUserData;
dialog: DialogNames;
}
interface IUserData {
loggedIn: boolean;
name: string;
}
//The initial global state
export const initialGlobalState: IGlobalState = {
loading: false,
userData: { loggedIn: false, name: "" },
dialog: ""
};
//The reducer function which is used in `App` component.
export const GlobalStateReducer = (
state: IGlobalState,
{ name, data }: IGlobalStateAction
): IGlobalState => {
switch (name) {
case "startLoading":
return { ...state, loading: true };
case "stopLoading":
return { ...state, loading: false };
case "setUserData":
return { ...state, userData: { ...state.userData, ...data } };
case "setDialog":
return { ...state, dialog: data };
default:
return state;
}
};
//The interface object which is passed from GlobalContext.Provider as "value"
export interface GlobalContextState {
globalState: IGlobalState;
dispatchGlobal: React.Dispatch<IGlobalStateAction<GlobalStateActionNames>>;
}
//intital state which is passed to `createContext`
export const initialGlobalContextState: GlobalContextState = {
globalState: initialGlobalState,
dispatchGlobal: function(){}
};
//The main function which set the type of data based on the generic type passed.
export interface IGlobalStateAction<
N extends GlobalStateActionNames = GlobalStateActionNames
> {
data?: N extends "setUserData"
? IUserData
: N extends "setDialog"
? DialogNames
: any;
name: N;
}
export const GlobalContext = React.createContext(initialGlobalContextState);
我的<App> 组件看起来像。
const App: React.SFC = () => {
const [globalState, dispatch] = React.useReducer(
GlobalStateReducer,
initialGlobalState
);
return (
<GlobalContext.Provider
value={{
globalState,
dispatchGlobal: dispatch
}}
>
<Child></Child>
</GlobalContext.Provider>
);
};
上述方法很好。我必须像下面在<Child>中使用它
dispatchGlobal({
name: "setUserData",
data: { loggedIn: false }
} as IGlobalStateAction<"setUserData">);
上述方法的问题是它使代码更长一些。第二个问题是我必须导入IGlobalStateAction,因为我必须在哪里使用dispatchGlobal
有没有一种方法我只能告诉name 和data 被自动分配给正确的类型或任何其他更好的方法。请引导到正确的路径。
【问题讨论】:
标签: javascript typescript react-hooks