gpt4 book ai didi

javascript - 使用 react 钩子(Hook)和 typescript 为操作对象创建接口(interface)的正确方法是什么

转载 作者:行者123 更新时间:2023-12-02 22:04:50 25 4
gpt4 key购买 nike

我正在使用 react 钩子(Hook)和 typescript 。我用过useReducer()对于全局状态。减速函数的 Action 包含两个属性 namedataname表示事件或更改的名称,data将是该特定名称所需的特定数据。

到目前为止,name 有四个值。如果名字"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

有没有一种方法我只能告诉namedata自动分配给正确的类型或任何其他更好的方式。请引导到正确的道路。

最佳答案

useReducer 与 typescript 一起使用有点棘手,因为正如您所提到的,reducer 的参数会根据您采取的操作而有所不同。

我想出了一种使用类来实现操作的模式。这允许您将类型安全参数传递到类的构造函数中,并且仍然使用类的父类(super class)作为化简器参数的类型。听起来可能比实际更复杂,下面是一个例子:

interface Action<StateType> {
execute(state: StateType): StateType;
}

// Your global state
type MyState = {
loading: boolean;
message: string;
};

class SetLoadingAction implements Action<MyState> {
// this is where you define the parameter types of the action
constructor(private loading: boolean) {}
execute(currentState: MyState) {
return {
...currentState,
// this is how you use the parameters
loading: this.loading
};
}
}

因为状态更新逻辑现在被封装到类的 execute 方法中,所以 reducer 现在只有这么小:

const myStateReducer = (state: MyState, action: Action<MyState>) => action.execute(state);

使用此 reducer 的组件可能如下所示:

const Test: FunctionComponent = () => {
const [state, dispatch] = useReducer(myStateReducer, initialState);

return (
<div>
Loading: {state.loading}
<button onClick={() => dispatch(new SetLoadingAction(true))}>Set Loading to true</button>
<button onClick={() => dispatch(new SetLoadingAction(false))}>Set Loading to false</button>
</div>
);
}

如果您使用此模式,您的操作将状态更新逻辑封装在其执行方法中,(在我看来)可以更好地扩展,因为您不会获得带有巨大 switch-case 的 reducer 。您也是完全类型安全的,因为输入参数的类型由操作的构造函数定义,并且化简器可以简单地采用 Action 接口(interface)的任何实现。

关于javascript - 使用 react 钩子(Hook)和 typescript 为操作对象创建接口(interface)的正确方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59751983/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com