redux 确定形实转换程序请求是否挂起

qyswt5oh  于 2023-03-30  发布在  其他
关注(0)|答案(1)|浏览(76)

我有一个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
        }
      })
    })
  }
})

谢谢!

相关问题