基于我刚刚阅读并重新阅读的所有Redux和Reselect文档,如果thing.toJS()
返回的不可变映射不等于前一个,则只应执行getThing()
处理
...
// Selector
import { createSelector } from 'reselect'
const getThing = (state, thingId) => {
return state.entities.getIn(['things', thingId])
}
const makeThingSelector = () => {
return createSelector(
[getThing],
(thing) => {
return thing.toJS()
}
)
}
export default makeThingSelector
...
// Container
const makeMapStateToProps = () => {
return (state, ownProps) => {
const { thingId } = ownProps
const things = select.makeThingsSelector()(state, thingId)
return {
hasNoThings: things.length === 0,
things
}
}
}
const Container = connect(
makeMapStateToProps,
mapDispatchToProps
)(Component)
...
除非我有一个孩子'智能'组件,否则这是正确的。在这种情况下,当父级触发渲染时,子组件容器中调用的选择器始终处理该值,无论结果是否为新。
我一直在尝试将ImmutableJS API封装在我的选择器中,但这意味着每次父母更新时都要避免在这些嵌套组件上重新渲染我必须在shouldComponentUpdate
函数中进行深度相等检查。这很昂贵,似乎不是一个合适的解决方案。
应用程序状态已规范化,因此状态树的更新部分不是子组件所依赖的状态部分的分层父级。
我在这里错过了什么关键吗?
答案 0 :(得分:3)
每store
次更新react-redux
执行以下步骤(将所有内部复杂性放在一边):
mapStateToProps
和mapDispatchToProps
。props
Component
以防新props
与之前的mapStateToProps
不同。这种方式{/ 1}}将在每个store
更新时通过设计调用。下面的代码行也是如此:
...
const things = select.makeThingsSelector()(state, visitId)
...
正如您所见,每次有效阻止任何记忆时都会创建新的reselect
选择器(reselect
中没有全局状态,每个选择器都会发生记忆)。
您需要做的是更改您的代码,以便在mapStateToProps
的每次调用时使用同一个选择器:
const thingSelector = select.makeThingsSelector();
...
const makeMapStateToProps = () => {
return (state, ownProps) => {
const { visitId } = ownProps
const things = thingSelector(state, visitId)
return {
hasNoThings: things.length === 0,
things
}
}
}
更新:我也认为没有理由使用工厂风格的makeThingsSelector
和makeMapStateToProps
。为什么不这样做:
...
// Selector
export default createSelector(
[getThing],
(thing) => thing.toJS()
);
...
// Container
const mapStateToProps = (state, ownProps) => {
const { visitId } = ownProps
const things = select.thingsSelector(state, visitId)
return {
hasNoThings: things.length === 0,
things
}
}
const Container = connect(
mapStateToProps,
mapDispatchToProps
)(Component)
...
答案 1 :(得分:1)
由于此应用程序中的redux状态使用ImmutableJS
数据结构,因此Reselect
可能不是必需的。
首先,ImmutableJS
仅操作受更改操作影响的数据结构的切片,因此对较大状态的所有更改可能不会影响将切片传递给容器。
第二,redux connect函数默认情况下会返回一个纯容器,并且遇到相同的分片时将不会重新渲染。但是,mapStateToProps
会被调用,因为整个状态以及自己的属性可能都已更改。
为了更好地进行控制,可以通过向第四个参数添加ownProps
和areStatesEqual
谓词属性,将同一容器的呈现直接链接到对状态的特定切片和areOwnPropsEqual
的更改。连接功能(最好称为options
对象)。
const mapStateToProps = ({ entities }, { thingId }) => {
const things = entities.getIn(['things', thingId]).toJS();
return {
hasNoThings: things.length === 0,
things
};
};
const Container = connect(
mapStateToProps,
mapDispatchToProps,
undefined, {
areOwnPropsEqual: (np, pp) => np.thingId === pp.thingId,
areStatesEqual: (ns, ps) => ns.entities.get(‘things’).equals(
ps.entities.get(‘things’)
)
}
)(Component);
如果这两个谓词都是正确的,那么不仅容器及其子级都不会重新呈现,mapStateToProps
甚至都不会被调用!