pht*_*ier 7 javascript redux reselect
假设我有一个具有此状态结构的redux存储:
{
items: {
"id1" : {
foo: "foo1",
bar: "bar1"
},
"id2": {
foo: "foo2",
bar: "bar2"
}
}
}
Run Code Online (Sandbox Code Playgroud)
这个商店通过接收物品的全新价值而发展:
const reduceItems = function(items = {}, action) {
if (action.type === 'RECEIVE_ITEM') {
return {
...items,
[action.payload.id]: action.payload,
};
}
return items;
};
Run Code Online (Sandbox Code Playgroud)
我想显示一个Root视图,它呈现一个SubItem视图列表,它只提取状态的一部分.例如,SubItem视图只关心foos,应该得到它:
function SubItem({ id, foo }) {
return <div key={id}>{foo}</div>
}
Run Code Online (Sandbox Code Playgroud)
因为我只关心状态的"子部分",这就是我想要传递给"哑"的Root视图:
const Root = function({ subitems }) {
// subitems[0] => { id: 'id1', foo: "foo1" }
// subitems[1] => { id; 'id2', foo : "foo2" }
const children = subitems.map(SubItem);
return <div>{children}</div>;
};
Run Code Online (Sandbox Code Playgroud)
我可以轻松连接此组件以订阅状态中的更改:
function mapStatesToProps(state) {
return {
subitems: xxxSelectSubItems(state)
}
}
return connect(mapStatesToProps)(Root)
Run Code Online (Sandbox Code Playgroud)
我的根本问题是当我不关心的状态部分(bar)发生变化时会发生什么.或者甚至,当我收到一个项目的新值时,既foo没有bar改变也没有改变:
setInterval(() => {
store.dispatch({
type: 'RECEIVE_ITEM',
payload: {
id: 'id1',
foo: 'foo1',
bar: 'bar1',
},
});
}, 1000);
Run Code Online (Sandbox Code Playgroud)
如果我使用"天真"选择器实现:
// naive version
function toSubItem(id, item) {
const foo = item.foo;
return { id, foo };
}
function dumbSelectSubItems(state) {
const ids = Object.keys(state.items);
return ids.map(id => {
const item = state.items[id];
return toSubItem(id, item);
});
}
Run Code Online (Sandbox Code Playgroud)
然后列表是每个被调用的一个全新的对象,我的组件每次都被渲染,什么也没有.
当然,如果我使用'常量'选择器,它总是返回相同的列表,因为连接的组件是纯的,它被重新渲染(但这只是为了说明连接的组件是纯的):
// fully pure implementation
const SUBITEMS = [
{
id: 'id0',
foo: 'foo0',
},
];
function constSelectSubItems(state) {
return SUBITEMS;
}
Run Code Online (Sandbox Code Playgroud)
现在,如果我使用List更改的"almostConst"版本,但包含相同的元素,这会有点棘手.
const SUBITEM = {
id: 'id0',
foo: 'foo0',
};
function almostConstSelectSubItems(state) {
return [SUBITEM];
}
Run Code Online (Sandbox Code Playgroud)
现在,可以预见,由于列表不同,即使内部的项目相同,组件也会每秒重新呈现.
这是我虽然'重新选择'可以帮助的地方,但我想知道我是否完全没有错过这一点.我可以reselect使用这个来表现:
const reselectSelectIds = (state, props) => Object.keys(state.items);
const reselectSelectItems = (state, props) => state.items;
const reselectSelectSubItems = createSelector([reSelectIds, reSelectItems], (ids, items) => {
return ids.map(id => toSubItem(id, items));
});
Run Code Online (Sandbox Code Playgroud)
但它的行为与天真的版本完全一样.
所以:
这可能是我试图做他毫无意义的事情,并在我的redux商店中隐藏了一个问题,所以请随意说出明显的错误.
mar*_*son 12
你对新的数组引用肯定是正确的,导致重新渲染,并与你的选择器在正确的轨道上排序,但你需要改变你的方法.
Object.keys(state.item)您需要处理对象本身,而不是让选择器立即返回:
const selectItems = state => state.items;
const selectSubItems = createSelector(
selectItems,
(items) => {
const ids = Object.keys(items);
return ids.map(id => toSubItem(id, items));
}
);
Run Code Online (Sandbox Code Playgroud)
这样,只有在state.items替换对象时才会重新计算数组.
除此之外,是的,您可能还想查看连接各个列表项组件,以便每个组件按ID查找自己的数据.有关示例,请参阅我的博客文章Practical Redux,第6部分:连接列表,表单和性能.我还在React/Redux链接列表的Redux Techniques #Selectors和Normalization and Performance#Redux Performance部分中有很多相关文章.
| 归档时间: |
|
| 查看次数: |
4255 次 |
| 最近记录: |