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 />
.
神奇地传递商店的好处。
基本问题
我有一个包含以下数据的 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 />
.