我正在使用Context API
和React Hooks
构建一个React应用。我正在尝试遵循最佳做法。为此,我正在使用Flow
并尝试遵守其警告。
我有一种情况,一旦用户登录,我想在我构建的SessionContext
中存储有关该用户的一些数据。鉴于目前只有3条数据并且它们都是原始数据,我认为只有一个Reducer Action是合理的:
export const sessionReducer = (state: SessionState, action: SessionAction) => {
switch (action.type) {
case UPDATE_SESSION_PROP: {
return {
...state,
[action.propName]: action.payload
};
}
default: {
return state;
}
}
}
以下是我为说明3种数据类型而创建的操作类型:
export type UserEmailAction = {type: 'UPDATE_SESSION_PROP',
propName: 'currentUserEmail',
payload: string};
export type UserAccessLevelAction = {type: 'UPDATE_SESSION_PROP',
propName: 'currentUserAccessLevel',
payload: number};
export type CurrentCompanyNameAction = {type: 'UPDATE_SESSION_PROP',
propName: 'currentCompanyName',
payload: string};
在我的SessionContext
中,我将这3种动作类型组合如下,然后从中定义一个Dispatch类型:
export type SessionAction =
| UserEmailAction
| UserAccessLevelAction
| CurrentCompanyNameAction;
type Dispatch = (action: SessionAction) => void;
此代码中sessionReducer
上方有4条警告消息:
const [state: SessionState, dispatch: Dispatch] = useReducer(sessionReducer, defaultState);
消息类似于此:“由于数字[1]与返回值的属性useReducer
中的字符串[2]不兼容,因此无法将sessionReducer
绑定到reducer
来调用currentCompanyName
。”
我是否定义了错误的动作类型,或者Flow是否不够智能,无法区分这三种模式?顺便说一下,这种方法在运行时似乎可以正常工作。
流量不够智能。但是您可以使用流程可以理解的其他方法:
type SessionState = {
currentUserEmail: string,
currentUserAccessLevel: number,
currentCompanyName: string,
};
type SessionAction = {
type: 'UPDATE_SESSION_PROP',
payload: $Shape<SessionState>,
};
const sessionReducer = (state: SessionState, action: SessionAction) => {
switch (action.type) {
case UPDATE_SESSION_PROP: {
return {
...state,
...action.payload
};
}
default: {
return state;
}
}
}
这也将减少总代码量,所以我认为它不太糟糕。