React-redux connect() 的 mapStateToProps 在 react-router 导航中被多次调用
React-redux connect()'s mapStateToProps being called multiple times on react-router navigation
我有一个简单的路由器(从redux-router
开始,切换到react-router
以消除变量)。
<Router history={history}>
<Route component={Admin} path='/admin'>
<Route component={Pages} path='pages'/>
<Route component={Posts} path='posts'/>
</Route>
</Router>
管理组件基本上只是 {this.props.children}
和一些导航;它不是 connect
ed 组件。
Pages 组件是 connect
ed 组件,mapStateToProps()
如下所示:
function mapStateToProps (state) {
return {
pages: state.entities.pages
};
}
帖子更有趣:
function mapStateToProps (state) {
let posts = map(state.entities.posts, post => {
return {
...post,
author: findWhere(state.entities.users, {_id: post.author})
};
}
return {
posts
};
}
然后当我加载页面或在 Posts/Pages 路由之间切换时,我在 console.log() 中得到以下信息。
// react-router navigate to /posts
Admin render()
posts: map state to props
Posts render()
posts: map state to props
Posts render()
posts: map state to props
// react-router navigate to /pages
Admin render()
pages: map state to props
Pages render()
pages: map state to props
所以我的问题是:为什么 mapStateToProps
在路线更改时被多次调用?
此外,为什么 mapStateToProps
中的一个简单 map
函数导致它在 Posts 容器中被第三次调用?
我正在使用 Redux 文档中的基本 logger
和 crashReporter
中间件,它没有报告任何状态更改或崩溃。如果状态没有改变,为什么组件要渲染多次?
根据 react-redux
的经验,您不应在 mapStateToProps
中处理存储属性,因为 connect
uses shallow checking of bound store attributes to check for diff.
要检查您的组件是否需要更新,react-redux
调用 mapStateToProps
并检查结果的第一级属性。如果其中一个更改(===
相等性检查),组件将更新为新的道具。在您的情况下,每次调用 mapStateToProps
时 posts
更改(map
转换),因此您的组件会在每次商店更改时更新!
您的解决方案是 return 仅直接引用您商店的属性:
function mapStateToProps (state) {
return {
posts: state.entities.posts,
users: state.entities.users
};
}
然后在您的组件中,您可以定义一个函数来按需处理您的数据:
getPostsWithAuthor() {
const { posts, users } = this.props;
return map(posts, post => {
return {
...post,
author: findWhere(users, {_id: post.author})
};
});
}
Reselect 允许您为派生状态处理创建记忆选择器函数。
Redux's documentation 举例说明如何使用它。回购的自述文件也有一个简单的例子。
我有一个简单的路由器(从redux-router
开始,切换到react-router
以消除变量)。
<Router history={history}>
<Route component={Admin} path='/admin'>
<Route component={Pages} path='pages'/>
<Route component={Posts} path='posts'/>
</Route>
</Router>
管理组件基本上只是 {this.props.children}
和一些导航;它不是 connect
ed 组件。
Pages 组件是 connect
ed 组件,mapStateToProps()
如下所示:
function mapStateToProps (state) {
return {
pages: state.entities.pages
};
}
帖子更有趣:
function mapStateToProps (state) {
let posts = map(state.entities.posts, post => {
return {
...post,
author: findWhere(state.entities.users, {_id: post.author})
};
}
return {
posts
};
}
然后当我加载页面或在 Posts/Pages 路由之间切换时,我在 console.log() 中得到以下信息。
// react-router navigate to /posts
Admin render()
posts: map state to props
Posts render()
posts: map state to props
Posts render()
posts: map state to props
// react-router navigate to /pages
Admin render()
pages: map state to props
Pages render()
pages: map state to props
所以我的问题是:为什么 mapStateToProps
在路线更改时被多次调用?
此外,为什么 mapStateToProps
中的一个简单 map
函数导致它在 Posts 容器中被第三次调用?
我正在使用 Redux 文档中的基本 logger
和 crashReporter
中间件,它没有报告任何状态更改或崩溃。如果状态没有改变,为什么组件要渲染多次?
根据 react-redux
的经验,您不应在 mapStateToProps
中处理存储属性,因为 connect
uses shallow checking of bound store attributes to check for diff.
要检查您的组件是否需要更新,react-redux
调用 mapStateToProps
并检查结果的第一级属性。如果其中一个更改(===
相等性检查),组件将更新为新的道具。在您的情况下,每次调用 mapStateToProps
时 posts
更改(map
转换),因此您的组件会在每次商店更改时更新!
您的解决方案是 return 仅直接引用您商店的属性:
function mapStateToProps (state) {
return {
posts: state.entities.posts,
users: state.entities.users
};
}
然后在您的组件中,您可以定义一个函数来按需处理您的数据:
getPostsWithAuthor() {
const { posts, users } = this.props;
return map(posts, post => {
return {
...post,
author: findWhere(users, {_id: post.author})
};
});
}
Reselect 允许您为派生状态处理创建记忆选择器函数。
Redux's documentation 举例说明如何使用它。回购的自述文件也有一个简单的例子。