跨多个组合重新选择仅适用于深度相等检查



我已经以各种方式进行了测试...不过,它不起作用。 我似乎没有做错任何事

  • 与重新选择文档完全相同的代码
  • Redux 存储已全部规范化
  • 减速器都是不可变的

从父组件,我只是传递一个带有 id 的 prop 和子组件,与 redux 连接并使用选择器通过 id(从父组件)获取确切的项目

### This is what Parent components render looks like
render() {
return (
<div>
<h4>Parent component</h4>
{this.props.sessionWindow.tabs.map(tabId => 
<ChildComponentHere key={tabId} tabId={tabId} />  
)}
</div>
);
}
### This is what Child component looks like
render() {
const { sessionTab } = this.props  (this props is from connect() )
<div>
<Tab key={sessionTab.id} tab={sessionTab} />
</div>
))
}
### Selectors for across multiple components
const getTheTab = (state: any, ownProps: IOwnProps) => state.sessionWindows.sessionTab[ownProps.tabId];
const makeTheTabSelector = () =>
createSelector(
[getTheTab],
(tab: object) => tab
)
export const makeMapState = () => {
const theTabSelector = makeTheTabSelector();
const mapStateToProps = (state: any, props: IOwnProps) => {
return {
sessionTab: theTabSelector(state, props)
}
}
return mapStateToProps
}

奇怪的工作解决方案:只需更改为深度相等检查。(从任何地方)

  • 使用具有深度相等的选择器按预期工作。
  • 使用 _.isEqual 也起作用了。

.

1. const createDeepEqualSelector = createSelectorCreator(
defaultMemoize,
isEqual
)
2. if (!_isEqual(this.props, nextProps) || !_isEqual(this.state, nextState)){return true}

根据我的理解,我的 redux 总是不可变的,所以当某些东西发生变化时,它会创建新的引用(对象或数组),这就是 react 重新渲染的原因。但是,当有 100 个项目并且只有 1 个项目发生了更改时,只有具有更改道具的组件才能重新渲染。

为了实现这一点,我只传递id(只是字符串。 浅相等(===)工作对吗?使用此 ID 获取确切的项目。(大多数组件获得相同的值输入,但很少组件获得不同的值输入) 使用重新选择来记忆值。 当某些内容更新并且每个组件获得新的引用输入时,与记忆值进行比较,并在真正更改时重新渲染。

这主要是我现在能想到的...如果我无论如何都必须使用_isEqual,为什么要使用重新选择? 我很确定我在这里错过了一些东西。谁能帮忙?

有关更多说明。(希望..) 首先,我的 redux 数据结构是这样的

sessionWindow: {
byId: {  // window datas byId
"windowId_111": {
id: "windowId_111",
incognito: false,
tabs: [1,7,3,8,45,468,35,124] // this is for the order of sessionTab datas that this window Item has
},
"windowId_222": {
id: "windowId_222",
incognito: true,
tabs: [2, 8, 333, 111]
},{
... keep same data structure as above
}
},
allIds: ["windowId_222", "windowId_111"] // this is for the order of sessionWindow datas
}
sessionTab: {  // I put all tab datas here. each sessionTab doesn't know which sessionWindow they are belong to
"1": {
id: 1
title: "google",
url: "www.google.com",
active: false,
...more properties
},
"7": {
id: 7
title: "github",
url: "www.github.com",
active: true
},{
...keep same data structure as above
}
}

问题。 1. 当一小部分数据发生更改时,它会重新渲染所有其他组件。 假设 id 为 7 的 url 和标题的 sessionTab 已更改。在我的会话选项卡缩减器上,已发送"会话选项卡已更新"操作。这是减速器逻辑

const updateSessionTab = (state, action) => {
return {
...state,
[action.tabId]: {
...state[action.tabId],
title: action.payload.title,
url: action.payload.url
}
}
}

什么都没有坏。 仅使用基本重新选择不会阻止重新渲染其他组件。我必须使用深度相等版本来停止重新渲染组件而不更改数据

经过几天的挣扎,我开始认为问题可能来自我的 redux 数据结构? 因为即使我从 sessionTab 更改一个项目,它也总是会做出新的引用,例如 {...state, [changedTab'id]: {....}} 最后,我不知道...

选择器定义和用法的三个方面看起来有点奇怪:

  • getTheTab同时通过多个级别向下挖掘
  • makeTheTabSelector有一个"输出选择器",它只返回给定的值,这意味着它与getTheTab
  • mapState中,您将整个props对象传递给theTabSelector(state, props)

我建议尝试一下,看看会发生什么:

const selectSessionWindows = state => state.sessionWindows;
const selectSessionTabs = createSelector(
[selectSessionWindows],
sessionWindows => sessionWindows.sessionTab
);
const makeTheTabSelector = () => {
const selectTabById = createSelector(
[selectSessionTabs, (state, tabId) => tabId],
(sessionTabs, tabId) => sessionTabs[tabId]
);
return selectTabById;
}
export const makeMapState() => {
const theTabSelector = makeTheTabSelector();
const mapStateToProps = (state: any, props: IOwnProps) => {
return {
sessionTab: theTabSelector(state, props.tabId)
}
}
return mapStateToProps
}

不能保证可以解决问题,但值得一试。

您可能还想尝试使用一些 devtool 实用程序,这些实用程序会告诉您组件重新渲染的原因。 我在Redux插件目录的Devtools#Component Update Monitoring部分中有指向几个此类工具的链接。

希望这会让你弄清楚事情。 无论哪种方式,请发表评论并让我知道。

相关内容

最新更新