【问题标题】:Calling other actions from createAsyncThunk从 createAsyncThunk 调用其他操作
【发布时间】:2020-05-11 00:15:53
【问题描述】:

通常你会在一个 thunk 中调用其他操作:

const startRecipe = {type: "startRecipe"}

const reducer = (state, action) => {
  if (action.type === "startRecipe") { 
    state.mode = AppMode.CookRecipe
  }
}

const getRecipeFromUrl = () => async dispatch => {
  const res = await Parser.getRecipeFromUrl(url)
  dispatch(startRecipe)
}

使用 redux 工具包中的 createAsyncThunk,这并不是那么简单。实际上,您可以在 extraReducers 中改变结果操作中的状态:

export const getRecipeFromUrl = createAsyncThunk('getRecipeFromUrl',
  async (url: string): Promise<RecipeJSON> => await Parser.getRecipeFromUrl(url)
)

const appStateSlice = createSlice({
  name: 'app',
  initialState: initialAppState,
  reducers: {},
  extraReducers: ({ addCase }) => {
    addCase(getRecipeFromUrl.fulfilled, (state) => {
      state.mode = AppMode.CookRecipe
    })
  }
})

但我也希望有非异步方式来启动配方,这将需要在切片中使用减速器:

  reducers: {
    startRecipe(state): state.mode = AppState.CookRecipe
  },

为了避免在两个地方编写相同的代码,我希望能够从 thunk 处理程序中调用简单的 reducer 函数。我从extraReducers 案例中简单地尝试了startRecipe(state)startRecipe(已经为鸭子导出而解构,所以我相当确定我指的是正确的函数),但它不起作用。

我目前的解决方案是在切片之外定义 _startRecipe 并在两种情况下都引用该函数

  reducers: { startRecipe: _startRecipe },
  extraReducers: builder => {
    builder.addCase(getRecipeFromUrl.fulfilled, _startRecipe)
  }

是否有一种“更好”的方式可以让您在 slice.reducers 中定义简单操作并从 extraReducers 中的 thunk 处理程序中引用它?

【问题讨论】:

    标签: redux redux-toolkit


    【解决方案1】:

    payloadCreator 的第二个参数是 thunkAPI (doc),您可以从那里分派 cookRecipe 操作。

    export const getRecipeFromUrl = createAsyncThunk('getRecipeFromUrl',
      async (url: string, thunkAPI: ThunkApiConfig): Promise<RecipeJSON> => {
        await Parser.getRecipeFromUrl(url)
        return thunkAPI.dispatch(cookRecipeActionCreator())
      }
    )
    

    【讨论】:

      【解决方案2】:

      从概念上讲,“调用reducer”的想法是错误的。 Redux 的部分设计是触发状态更新的唯一方式是通过调度一个动作。

      如果您使用switch 语句编写reducer,您可以有多个动作类型作为所有由同一个块处理的案例:

      switch(action.type) {
        case TypeA:
        case TypeB: {
          // common logic for A and B
        }
        case C: // logic for C
      }
      

      当使用createSlice 时,您可以通过在调用createSlice 之外定义一个“case reducer”函数来模仿这种模式,并将它传递给您想要处理的每个案例:

      const caseReducerAB = (state) => {
        // update logic here
      }
      
      const slice = createSlice({
        name: "mySlice",
        initialState,
        reducers: {
          typeA: caseReducerAB,
          typeB: caseReducerAB,
        }
        extraReducers: builder => {
          builder.addCase(someAction, caseReducerAB)
        }
      })
      

      这听起来像你所说的“当前解决方案”,所以是的,这就是我的建议。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-06-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-17
        • 2020-07-30
        • 2020-12-10
        • 2018-05-07
        相关资源
        最近更新 更多