如何使 thunks 独立于状态形状以使其可移植

How to make thunks independent from state shape to make them portable?

本文关键字:可移植 状态 thunks 何使 独立 于状态      更新时间:2023-09-26

我开发了一个带有React和Redux的小型独立Web应用程序,该应用程序托管在自己的Web服务器上。我们现在希望将这个应用程序的大部分内容重用/集成到另一个 React/Redux Web 应用程序中。

从理论上讲,这应该可以很好地工作,因为我所有的 React 组件、化简器和大多数动作创建者都是纯粹的。但是我有一些动作创建者,它们返回取决于应用程序状态的 thunk。他们可能会调度异步或同步操作,但这不是这里的问题。

假设我的根化简器看起来像这样:

const myAppReducer = combineReducers({
    foo: fooReducer,
    bar: barReducer,
    baz: bazReducer
});

我最复杂的动作创作者依赖于许多状态切片(幸运的是

,只有少数(:
const someAction = function () {
    return (dispatch, getState) => {
        const state = getState();
        if (state.foo.someProp && !state.bar.anotherProp) {
            dispatch(fetchSomething(state.baz.currentId);
        } else {
            dispatch(doSomethingSynchronous());
        }
    };
}

现在的问题是,我的操作创建者希望所有内容都位于状态对象的根目录中。但是,如果我们想将此应用程序集成到另一个 redux 应用程序中,则必须使用自己的密钥挂载我的 appReducer:

// The otherAppReducer that wants to integrate my appReducer
const otherAppReducer = combineReducers({
    ....
    myApp: myAppReducer
});

这显然破坏了我的动作创建者返回 thunks 并需要读取应用程序状态,因为现在所有内容都包含在"myApp"状态切片中。

在过去的几天里,我做了很多研究并思考如何正确解决这个问题,但似乎我是第一个尝试将基于 Redux 的应用程序集成到另一个基于 Redux 的应用程序中的人。

到目前为止想到的一些技巧/想法:

  • 创建我自己的 thunk 类型,以便我可以在自定义 thunk 中间件中执行instanceof检查,并让它向我的 thunks 传递自定义 getState 函数,然后返回正确的状态片。
  • 用它自己的键安装我的根减速器,让我的笨蛋依赖那个键。

到目前为止,我认为最好的方法是创建我自己的自定义中间件,但我对其他应用程序现在将依赖于我的中间件和自定义 thunk 类型这一事实并不满意。我认为必须有一种更通用的方法。

有什么想法/建议吗?你会如何解决这类问题?

你有没有考虑过不依赖store.getState()?我会将操作与应用程序状态完全分离,并从调用操作的位置获取所需的数据。

所以例如:

const someAction = function (someProp, anotherProp, currentId) {
    return dispatch => {
        if (someProp && !anotherProp) {
            dispatch(fetchSomething(currentId);
        } else {
            dispatch(doSomethingSynchronous());
        }
    };
}

这使得这些操作完全可重用,缺点是你现在必须在其他地方拥有这些信息。还有什么地方?如果方便,可以在组件内部使用 this.context.store ,或者通过带有 connectprops,或者更好的是,通过为您的特定应用程序提供包装器操作,因此:

const someApplicationAction = () => {
  return (dispatch, getState) => {
    const { foo, bar, baz } = getState();
    dispatch(someGenericAction(foo.someProp, bar.anotherProp, baz.currentID));
  };
}