我有一个React应用程序,它使用REST API并将数据存储到redux。我试图在从新端点拉取数据时减少样板文件,所以我正在编写一个封装redux toolkit的createAsyncThunk
方法和一个生成我的extraReducers
组件的方法。另外,我还有一个封装API请求以提供auth的方法。我的一些组件,比如我的OAuth回调,在组件挂载时调度一个动作。
我的问题是因为我不知道什么时候发送了一个请求,所以重复的操作被调度了。我知道我可以使用useState
来跟踪什么时候在组件端发送了一些东西,但是我希望有一个更优雅的解决方案。对于这个用例有一个通用的设计模式吗?
相关代码如下所示:
// wrapper around data returned from API
export interface AsyncState<T> {
status: RequestStatus,
value: T,
error: Error | string
}
// wrapper around API requests to provide an authenticated axios client
export const authRequest =
<ActionReturnType, ActionArgumentType=null>(method: (params: ActionArgumentType & {client: AxiosInstance}) => Promise<ActionReturnType>) =>
async (param: ActionArgumentType, thunkAPI): Promise<ActionReturnType> => {
const state = thunkAPI.getState()
if (!state.##MY_AUTH_PATH##) {
throw new Error(`auth not set`)
}
const token = `Bearer ${state.##MY_AUTH_PATH##}`
const client = axios.create({
headers: {
Authorization: token
},
})
const data = await method({
...param,
client
})
return data
}
// method run in 'extraReducers' part of slice creation
export const makeAsyncReducer = <
ActionReturnType, // type returned from async action
ActionArgumentType, // type of argument passed to async action
SliceState // the type of state of the reducer combiner
>(
builder: ActionReducerMapBuilder<SliceState>,
action: AsyncThunk<ActionReturnType, ActionArgumentType, AsyncThunkConfig>,
formatValue: (state: Draft<SliceState>, v: ActionReturnType) => DeepPartial<Draft<SliceState>>
) => {
builder.addCase(action.fulfilled, (state, action) => {
state = ObjectUtils.mergeDeep(
state,
formatValue(state, action.payload)
)
return state
})
builder.addCase(action.pending, (state, action) => {
// unsure of how to implement
})
builder.addCase(action.rejected, (state, action) => {
state = ObjectUtils.mergeDeep(
state,
_.chain({})
.set(`${action.error.state_key}.status`, RequestStatus.Rejected)
.set(`${action.error.state_key}.value`, null)
.set(`${action.error.state_key}.error`, action.error.error)
.value()
)
return state
})
}
// example action
export const getMe = createAppAsyncThunk(
'profile',
authRequest(API.getMe)
)
const slice = createSlice({
name: 'api',
initialState,
reducers: {},
extraReducers: builder => {
builder.addCase(setChallenge, (state, action) => {
const c = current(state)
const updated = ObjectUtils.mergeDeep(c, {
auth: {
value: {
challenge: action.payload
}
}
})
return updated
})
makeAsyncReducer(builder, exchangeCode, (state, response) => {
return ObjectUtils.mergeDeep(state, {
auth: {
status: RequestStatus.Fulfilled,
value: response
}
})
})
makeAsyncReducer(builder, getMe, (state, response) => {
return ObjectUtils.mergeDeep(state, {
profile: {
value: response
}
})
})
}
})
谢谢!
1条答案
按热度按时间tez616oj1#
RTK的
createApi
最终成为解决方案