例如,假设我们有一个称为game
的切片状态。在game
下我们有两个实体,enemies
和items
。每个实体都有x坐标来记录它的位置。状态树如下所示:
{
game: {
enemies: {
allEnemies: [
{
id: 1,
x: 100,
},
{
id: 3,
x: 300,
}
],
allEnemiesById: [1, 3],
},
items: {
allItems: [
{
id: 2,
x: 200,
},
{
id: 7,
x: 500,
}
],
allItemsById: [2, 7],
}
}
}
当然enemy
实体和item
实体将有其他不同的属性。也有其他的逻辑在game
减速器,所以我不能简单地删除它。
现在,在game
减速器中,我们有两个选择器分别获得可见的敌人和道具。它们委托enemies
和items
中的选择器功能,因为我不想让game
知道enemies
和items
的状态树细节:
reducers/game.js
import { enemies, selector1 } from './enemies.js';
import { items, selector2 } from './items.js';
const getVisibleEnemies = (state) => selector1(state.enemies)
const getVisibleItems = (state) => selector2(state.items)
但现在的问题是:selector1
和selector2
的名称应该是什么?我想了一些解决方案,但我不太满意:
(1) getVisibleEntities
:但game
不能有两个相同的函数名;
(2) getVisibleXXX
:但这与game
中的选择器名称相同。
(3)直接在客户端代码中调用enemies
和items
的选择器,例如(mapStateToProps
中的getVisibleEnemies(state.game.enemies)
):但是现在调用者必须知道状态树的深层形状,一旦状态树发生变化,要全部更改将是痛苦的。
(4)在reducer函数中绑定选择器,例如:
reducers/enemies.js
导出const getVisibleEntities(state) => {//为敌人实现getVisibleEntities}
export const enemies = (state = initialState, action) {
// main reducer of enemies
}
enemies.getVisibleEntities = getVisibleEntities
reducers/items.js
导出const getVisibleEntities(state) => {//getVisibleEntities的实现}
export const items = (state = initialState, action) {
// main reducer of items
}
items.getVisibleEntities = getVisibleEntities
reducers/game.js
export const getVisibleEnemies = (state) => enemies.getVisibleEntities(state.enemies)
export const getVisibleItems = (state) => items.getVisibleEntities(state.enemies)
但是我不确定是否将选择器设置为状态减速器上的属性是个好主意。
(5)给它一个稍微不同的名字,例如game.js
中的getVisibleEnemies
和enemies.js
中的getVisibleEnemiesImpl
:这很好,但我想知道应该有更好的方法来处理这个
那么你会怎么做呢?
我认为你应该选择选项(3),但是:
- 选择器应该是整个Redux存储状态的函数
- 这样你的容器(智能组件)就不需要知道你的状态树的深层形状