Redux Newbie试图制作使用Redux商店的纯数据类

时间:2016-08-15 18:13:59

标签: redux react-redux

基本问题

我有一个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 />内。但是,我只想要一个独立的实用程序类/对象,而不是DOM中的实际内容,它排除了<Provider/>

如何制作一个类似上述方法的方法,实际上有效,不涉及<Provider /> ......我在哪里放?

1 个答案:

答案 0 :(得分:1)

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

所以问题在于:connect()<Provider />通过让我们的React组件访问商店的单例实例来帮助我们,但我们如何在connect()的某个地方访问此商店并且<Provider />无法使用?

我认为这里最简单的解决方案是创建一个保留商店的单例类,因此任何非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的操作,该操作只返回一个新状态,其中currentId属性已更改为传递给它的任何内容。然后,您可以通过执行类似store.getState().things[store.getState().currentId]的操作来获取当前的“事物”。因此,让我们创建一个Singleton类,它可以保留到商店并提供此功能的包装。

<强> 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();

此类在第一次使用时创建实例,并在以后的每个时间使用该实例。因此,当您最初创建商店时,只需导入此类并调用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 />神奇地传递商店。