【问题标题】:Redux Toolkit: Dispatch an action from an extraReducers listener?Redux 工具包:从 extraReducers 侦听器调度操作?
【发布时间】:2021-03-14 07:54:41
【问题描述】:

我想知道是否可以(或一个好的做法)从 extraReducer 调用 dispatch(someDumbAction())

例如,我在来自createSlicereducers 对象中有一个setData() 操作。 我想直接在我的组件中调用setData()。但我也想在 extraReducer 监听器中调用它,以便重用减速器逻辑,如下所示:

// Thunk Action
export const getData = createAsyncThunk('data/getData', async (params) => {
  return await api.get({ params })
})

// Slice creation
const slice = createSlice({
  name: 'data',
  initialState: [],
  reducers: {
    setData: (state, { payload }) => {
       state.push(payload);
    })
  },
  extraReducers: (builder: any) => {
    builder.addCase(getData.pending, (state) => {
      //...
    })
    builder.addCase(getData.rejected, (state) => {
      //...
    })
    builder.addCase(getData.fulfilled, (state, { payload }) => {
      // Here I want to dispatch `setData` action, in order to reuse that logic
      // dispatch(setData(payload));
      
    })
  },
})

// In any component: dispatch(setData([...]);

【问题讨论】:

    标签: reactjs redux react-redux redux-toolkit


    【解决方案1】:

    没有。 Reducer 可以永远调度操作

    https://redux.js.org/style-guide/style-guide#reducers-must-not-have-side-effects

    但是,您在这里真正需要的是能够在多种情况下运行相同的状态更新逻辑步骤。

    您可以将逻辑定义为独立的 reducer 函数,并在两种情况下重用它:

    function addItem(state, action) {
      state.push(action.payload);
    }
    
    const slice = createSlice({
      name: 'data',
      initialState: [],
      reducers: {
        setData: addItem
      },
      extraReducers: (builder: any) => {
        builder.addCase(getData.pending, (state) => {
          //...
        })
        builder.addCase(getData.rejected, (state) => {
          //...
        })
        builder.addCase(getData.fulfilled, addItem)
      },
    })
    

    您还可以将函数定义为reducers 的一部分,然后在extraReducers 处理程序中引用它:

    const slice = createSlice({
      name: 'data',
      initialState: [],
      reducers: {
        setData: (state, { payload }) => {
           state.push(payload);
        })
      },
      extraReducers: (builder: any) => {
        builder.addCase(getData.pending, (state) => {
          //...
        })
        builder.addCase(getData.rejected, (state) => {
          //...
        })
        builder.addCase(getData.fulfilled, (state, action) => {
          slice.caseReducers.setData(state, action);
        })
      },
    })
    

    【讨论】:

    • 是的,只是想避免在同一个文件中重复同一行代码。第一个解决方案有道理,但第二个解决方案有点奇怪。甚至可以在其内部引用您正在创建(切片)的同一对象吗? :思考:
    • 是的!这个 reducer 中的那行代码在切片对象被定义之前不会运行。这就是为什么我没有builder.addCase(getData.fulfilled, slice.caseReducers.setData) - 因为该行将运行 切片正在创建,因此可能无法正常工作。
    • 哦,谢谢伙计!现在有道理了^^ 仅出于好奇,您是否建议使用extraReducers 和诸如挂起、拒绝之类的听众.. 或者您会使用旧的dispatch(someActionSuccess())dispatch(someActionError()) ?因为,在 RTK 文档中,似乎推荐了最后一种方法。再次感谢马克。
    • RTK 教程是在我们添加createAsyncThunk API 之前编写的。 createAsyncThunk 完全符合您的描述,它只是为您自动生成动作创建者。核心文档中的新 "Redux Essentials""Redux Fundamentals" 教程是最新的 - 请参阅那些。另外,仅供参考,我们刚刚发布了一个新的 "RTK Query" lib 作为简化数据获取的 alpha 版本 - 看看吧!
    • 选择器是独立的 JS 函数。对于 Redux,它们通常将 state 作为第一个参数,并返回一些提取/派生的值。 “Memoized”选择器通常使用 Reselect 库创建。见Using Reselect Selectors for Encapsulation and Performance。选择器可以在任何可以访问整个 Redux 状态的地方使用,包括 useSelectormapState,以及在 thunk 和 sagas 内部:const value = selector(state)
    猜你喜欢
    • 2022-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-17
    相关资源
    最近更新 更多