继续我的冒险,用Zod和Redux围绕axios创建一个客户端/ Package 器,这样客户端就可以在获取和分发所需的状态更新到Redux期间处理错误。
到目前为止,我已经成功地将Zod和验证部分实现到客户机中。现在我想以某种方式将可能的错误状态或成功状态存储到redux中。问题是,无论我如何尝试将dispatch
包含到类中,它似乎都没有做任何事情。
目前我的 Package 器客户端是this(在这个示例中没有redux)
interface RequestConfig<T extends z.ZodTypeAny> extends AxiosRequestConfig {
responseSchema: T;
}
export class ValidatedAxiosClient {
delete = this.createValidatedAxiosRequest('DELETE');
get = this.createValidatedAxiosRequest('GET');
patch = this.createValidatedAxiosRequest('PATCH');
put = this.createValidatedAxiosRequest('PUT');
post = this.createValidatedAxiosRequest('POST');
private unableToFetch = 'error:unableToFetch';
constructor(private service: string, private baseUrl: string) {}
private handleNetworkError<T extends z.ZodTypeAny>(
error: HttpError,
url: string,
config: RequestConfig<T>
) {
/**
* Handle error...
*/
}
private handleZodError<T extends z.ZodTypeAny>(
error: z.ZodError,
url: string,
config: RequestConfig<T>
) {
/**
* Parse and handle ZodError...
*/
}
private createValidatedAxiosRequest(method: HTTPMethod) {
return async <T extends z.ZodTypeAny>(
url: string,
config: RequestConfig<T>
): Promise<z.infer<T>> => {
try {
const response = await axios({ ...config, method, url, baseURL: this.baseUrl });
return config.responseSchema.parse(response);
} catch (error: any) {
if (error instanceof z.ZodError) {
console.log(JSON.stringify({ error }, undefined, 4));
this.handleZodError<T>(error, url, config);
}
if (error instanceof HttpError) {
this.handleNetworkError<T>(error, url, config);
}
}
};
}
}
我使用redux-thunk
中的ThunkAction
,如下所示
const WrappedClient = new ValidatedAxiosClient('UserService', 'http://localhost:3000')
export fetchUser =
(userId: string): ThunkAction<void, RootState, unknown, Action<string>> =>
async (dispatch, getState) => {
if (getState().users.status === 'pending') return;
dispatch(startedUsersLoading());
const { name, age } = await WrappedClient.get('/user', {
params: { userId },
responseSchema: z.object({
name: z.string(),
age: z.number()
})
});
dispatch(getUsersSuccess);
}
以前我是在客户机外部和fetchUser
函数中设置加载和错误状态的。然而,由于我有几个服务,因此客户端,这将是非常重复和相当烦人的管理。我想把州派遣转移到客户端本身。这可能吗
我试图将分派传递到客户机中的createValidatedAxiosRequest
中,但分派从未在那里被调用。
private createValidatedAxiosRequest(method: HTTPMethod) {
return async <T extends z.ZodTypeAny>(
url: string,
dispatch: any,
config: RequestConfig<T>
): Promise<z.infer<T>> => {
try {
dispatch(LoadingStateForThisService)
const response = await axios({ ...config, method, url, baseURL: this.baseUrl });
const parsedResponse = config.responseSchema.parse(response);
dispatch(LoadingSuccess);
return parsedResponse;
} catch (error: any) {
dispatch(someErrorStateSettingAction); // This is never called
if (error instanceof z.ZodError) {
console.log(JSON.stringify({ error }, undefined, 4));
this.handleZodError<T>(error, url, config);
}
if (error instanceof HttpError) {
this.handleNetworkError<T>(error, url, config);
}
}
};
}
我想知道我是否应该将分派传递给构造函数,但这也变得很奇怪,因为这样我就需要在每次调用fetch函数时创建一个新的客户端示例
export fetchUser =
(userId: string): ThunkAction<void, RootState, unknown, Action<string>> =>
async (dispatch, getState) => {
if (getState().users.status === 'pending') return;
const WrappedClient = new ValidatedAxiosClient('UserService', dispatch, 'http://localhost:3000') // NOPE!! Don't want to instantiate this every time the function is called
dispatch(startedUsersLoading());
const { name, age } = await WrappedClient.get('/user', {
params: { userId },
responseSchema: z.object({
name: z.string(),
age: z.number()
})
});
dispatch(getUsersSuccess);
}
有没有一种方法可以实现我正在尝试做的事情,或者我应该尝试一些不同的方法?
1条答案
按热度按时间ctzwtxfj1#
我的建议是在这个
ValidatedAxiosClient
类对象示例中传递并存储应用程序的Redux存储的示例。这将允许ValidatedAxiosClient
不仅在必要时访问任何当前状态值,而且还可以将操作分派到存储。示例:
如果你正在寻找一个替代方案,或建议/推荐,那么我也强烈建议你看看Redux-Toolkit Query。您没有定义一个带有通用HTTP方法的类并微观管理所有加载/获取状态/状态,而是定义了一个API切片来定义应用程序使用的端点,Redux-Toolkit * 自动 * 处理加载/获取状态并生成应用程序将使用的查询钩子,并且它集成到应用程序使用的Redux商店中。