Redux 新手尝试制作使用 Redux Store 的纯数据 Class

Redux Newbie Trying to Make Pure-Data Class That Uses Redux Store

基本问题

我有一个包含以下数据的 Redux 存储:

foo: {
    currentId: 1,
    things: [{id: 1}, {id: 2}),
}

我想在某处(例如,在Foo单例对象上)制作一个实用方法,这样我代码中的任何模块都可以:

import Foo from 'foo';
foo.getCurrentFoo(); // returns foo.thins[foo.currentId];

但我不知道把它放在哪里。

尝试失败

我最初的尝试是创建一个 Foo 组件单例:

// Foo.js
class FooBase extends React.Component {
    getCurrentFoo() {
        return this.state.foo.things[this.state.foo.currentId];
    }
}
const Foor = connect((state) => state.foo)(FooBase);
export default new FooWrapper();

但这不起作用。 Redux 抱怨 属性 store 不存在(当我这样做时 new FooWrapper())。这是有道理的,因为我的组件不在 <Provider /> 中。但是,我只想要一个独立的实用程序 class/object,而不是 DOM 中实际存在的东西,这排除了 <Provider/>.

我怎样才能像上面描述的那样创建一个实际有效的方法,而不涉及 <Provider /> ...我应该把它放在哪里?

react-redux 助手的好处在于它们允许您使用 connect()<Provider /> 通过 React 的 context 自动将存储传递给子组件。但是,这并不一定意味着您必须 使用这些助手,尤其是在不使用 React 的代码库区域。

所以问题就在这里:connect()<Provider /> 通过让我们的 React 组件访问商店的单例实例来帮助我们,但是我们如何才能在 [=15] 的某个地方访问这个商店=]和<Provider />不能用?

我认为这里最简单的解决方案是创建一个保持存储的单例 class,因此任何非 React 模块仍然可以使用该存储。

假设您正在创建这样的商店:

init.js

import {createStore} from 'redux';

const initialState = {
    currentId: 1,
    things: ['foo', 'bar']
};

const reducer = (state = initialState, action) => {
    if (action.type === 'SET_CURRENT_ID') {
        return Object.assign({}, state, {
            currentId: action.id
        });
    }

    return state;
};

const store = createStore(reducer);

这家商店采取类型 SET_CURRENT_ID 的操作,它只是 returns 一个新状态,其中 currentId 属性 更改为传递给它的任何状态。然后,您可以通过执行 store.getState().things[store.getState().currentId] 之类的操作来获取当前的 "thing"。因此,让我们创建一个 Singleton class,它可以保留 store 并围绕此功能提供包装。

store.js

class Store {
    constructor() {
        this._store = undefined;
    }

    setStore(store) {
        this._store = store;
    }

    getCurrentThing() {
        if (this._store) {
            const {things, currentId} = this._store.getState();

            return things[currentId];
        }
    }

    setCurrentThing(id) {
        if (this._store) {
            const action = {
                type: 'SET_CURRENT_ID',
                id
            };

            this._store.dispatch(action);
        }
    }
}

export let singletonStore = new Store();

此 class 在第一次使用时创建一个实例,并在以后每次使用该实例。因此,当您最初创建商店时,只需导入此 class 并调用 setStore().

init.js

import {singletonStore} from './store';

singletonStore.setStore(store);

然后,每个使用 singletonStore 的后续文件都将具有相同的状态。

test.js

import {singletonStore} from './store';

console.log(singletonStore.getCurrentThing()); // 'bar'

singletonStore.setCurrentThing(0);

console.log(singletonStore.getCurrentThing()); // 'foo'

这应该可以很好地满足您在模块中使用商店的需要,这些模块没有使用 connect()<Provider />.

神奇地传递商店的好处。