She*_* GE 7 reactjs redux react-redux redux-toolkit
我是 React 的新手,我正在学习使用 React 来构建 Web 应用程序。我发现 Redux Toolkit 很有用,并使用它的createSlice()
功能来实现基本功能。但是,我遇到了与“最佳实践”相关的问题,我不确定我是否正确构建了应用程序的架构。
假设我user
在 Redux 中存储了一个对象。我创建了一个异步 thunk 函数来获取相关信息:
export const getUserInfo = createAsyncThunk('user/get', async (userId, thunkApi) => {
// fetching information using api
}
Run Code Online (Sandbox Code Playgroud)
相应地,我处理pending/fulfilled/rejected
回调如下:
const userSlice = createSlice({
name: 'user',
initialState,
reducers: {
setShowProgress(state, action: PayloadAction<boolean>) {
state.showProgress = action.payload;
},
clearError(state) {
state.error = null;
state.errorMessage = null;
}
},
extraReducers: builder => {
builder.addCase(getUserInfo.pending, (state, action) => {
// My question is here >_<
}
builder.addCase(getUserInfo.fulfilled, (state, action) => {
// handle data assignments
})
builder.addCase(getUserInfo.rejected, (state, action) => {
// handle error messages
})
}
})
Run Code Online (Sandbox Code Playgroud)
考虑到修改显示状态标志在其他功能 api 实现中很常见,我将两个函数 (setShowProgress()
和clearError()
)包装在reducers
. 我的问题来了:如何在getUserInfo.pending
函数中引用这两个函数?
虽然我可以只分配showProgress
和error
状态变量getUserInfo.pending
而不是尝试调用reducer函数,但是当我将来实现其他获取操作时肯定会引入重复的代码。如果它不是推荐的模式,那么这种场景的最佳实践是什么?
如果你的目标只是设置一个loading
布尔值或error
基于财产pending
/ fulfilled
/ rejected
,你可以只使用addMatcher
这是在1.4版本中引入的。
这是一个非常基本的示例,它使用通用帮助程序在多个切片中简化此操作。
// First, we'll just create some helpers in the event you do this in other slices. I'd export these from a util.
const hasPrefix = (action: AnyAction, prefix: string) =>
action.type.startsWith(prefix);
const isPending = (action: AnyAction) => action.type.endsWith("/pending");
const isFulfilled = (action: AnyAction) => action.type.endsWith("/fulfilled");
const isRejected = (action: AnyAction) => action.type.endsWith("/rejected");
const isPendingAction = (prefix: string) => (
action: AnyAction
): action is AnyAction => { // Note: this cast to AnyAction could also be `any` or whatever fits your case best
return hasPrefix(action, prefix) && isPending(action);
};
const isRejectedAction = (prefix: string) => (
action: AnyAction
): action is AnyAction => { // Note: this cast to AnyAction could also be `any` or whatever fits your case best - like if you had standardized errors and used `rejectWithValue`
return hasPrefix(action, prefix) && isRejected(action);
};
const isFulfilledAction = (prefix: string) => (
action: AnyAction
): action is AnyAction => {
return hasPrefix(action, prefix) && isFulfilled(action);
};
const userSlice = createSlice({
name: 'user',
initialState,
reducers: {},
extraReducers: builder => {
builder.addCase(getUserInfo.fulfilled, (state, action) => {
// handle data assignments
})
// use scoped matchers to handle generic loading / error setting behavior for async thunks this slice cares about
.addMatcher(isPendingAction("user/"), state => {
state.loading = true;
state.error = '';
})
.addMatcher(isRejectedAction("user/"), (state, action) => {
state.loading = false;
state.error = action.error; // or you could use `rejectWithValue` and pull it from the payload.
})
.addMatcher(isFulfilledAction("user/"), state => {
state.loading = false;
state.error = '';
});
}
})
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3067 次 |
最近记录: |