Redux / RTK:为一个切片创建增强器?

IT技术 reactjs redux react-redux redux-toolkit
2021-05-09 05:32:50

在我的 Redux/RTK 存储中的一个切片中,我需要做的就是让切片完成它的工作,就是使用createEntityAdapter()和导出setAllCRUD 函数创建一个实体适配器到目前为止,如此简单 - 感谢 RTK :-)

但是,当该切片的数据进入时,我需要“增强”它(或“增强”它,正如Redux 文档所称的那样),即添加从进入的数据派生的更多信息,例如在 UI 中显示的格式化数据(人为的例子)。

我为此目的创建了一个增强器,目标是应用程序可以依赖该切片中的数据在添加后立即完成,即从一开始就包含应用程序组件所需的任何数据。(这来自之前使用非 UI 组件的不成功方法,该组件监听存储更新并随后增强切片数据 - 这会导致更新/计时问题。)

在增强器中,我拦截感兴趣的操作并在将其添加到商店之前修改有效负载(在下面的示例代码中,我只记录操作,但您明白了......):

export const mySliceEnhancer = (createStore) => {
  return (rootReducer, preloadedState, enhancers) => {
    const store = createStore(rootReducer, preloadedState, enhancers)

    function newDispatch(action) {
      // intercept only actions related to my slice
      if (action.type === 'mySlice/setAll') {
        console.debug('mySliceEnhancer > newDispatch > action.payload:\n' +
                        JSON.stringify(action.payload, null, 2));
      }

      const result = store.dispatch(action);
      return result;
    }

    return { ...store, dispatch: newDispatch }
  }
}

这有效,但在全局范围内应用于整个商店,即被dispatch我的自定义版本“覆盖”以发送到商店的任何内容这让我很担心,因为例如我在 Redux Dev Extension 中丢失了跟踪功能:对于 any dispatch,我的增强器中的一个被显示,无论它是否真的改变了任何东西。

问:有没有什么办法可以只对 redux 存储的一个切片应用增强器?

或者 - 更一般地询问 - 我的方法是否是一个好主意?

1个回答

我认为这是对增强剂的用途的误解。

首先,增强器总是包装整个 store 对象,并且有能力提供他们自己版本的 store 方法,比如dispatch.

其次,“切片缩减器”是一个与商店级代码本身无关的概念。请记住,您实际上只有一个减速器 - 您传递给的根减速器configureStore根reducer如何选择在内部拆分工作对商店的其余部分无关紧要 - 它可能是一个巨大的函数,具有大量的if语句,一次处理整个状态树,或者用于combineReducers拆分通过顶级键的工作。

第三,如果您已正确配置存储,则使用增强器不应消除跟踪功能。根据文档,您可以使用compose()组合多个增强器。如果您使用 RTK 的configureStore,您可以传递一个enhancers数组,它会负责将它们与 DevTools 增强器正确组合在一起。

最后,由于您真正要做的只是查找特定操作并修改其内容,因此您不需要增强器。中间件可以很好地做到这一点:

const myCustomMiddleware = storeAPI => next => action => {
  if (action.type === 'mySlice/setAll') {
    const state = storeAPI.getState();
    action.payload.someField = state.someValue;
  }

  return next(action);
}

const store = configureStore({
  reducer: rootReducer,
  middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(myCustomMiddleware);
})