【发布时间】:2020-08-01 17:51:27
【问题描述】:
我在 ReactJS 16.8.5 和 React-Redux 3.7.2 上构建了一个应用程序。当应用加载应用装载时,会设置初始存储并针对 Firebase 实时数据库设置数据库订阅。该应用程序包含侧边栏、标题和内容部分。通过使用 React Developer Tools 分析应用程序,我可以看到 Sidebar 被渲染了多次 - 触发了子组件的重新渲染。我已经实现了React.memo 以避免在道具更改时重新渲染。
据我所知,道具没有改变,但Sidebar 仍然重新渲染,这让我感到困惑。
app.js
//Imports etc...
const jsx = (
<React.StrictMode>
<Provider store={store}>
<AppRouter />
</Provider>
</React.StrictMode>
)
let hasRendered = false
const renderApp = () => {
if (!hasRendered) { //make sure app only renders one time
ReactDOM.render(jsx, document.getElementById('app'))
hasRendered = true
}
}
firebase.auth().onAuthStateChanged((user) => {
if (user) {
// Set initial store and db subscriptions
renderApp()
}
})
AppRouter.js
//Imports etc...
const AppRouter = ({}) => {
//...
return (
<React.Fragment>
//uses Router instead of BrowserRouter to use our own history and not the built in one
<Router history={history}>
<div className="myApp">
<Route path="">
<Sidebar />
</Route>
//More routes here...
</div>
</Router>
</React.Fragment>
)
}
//...
export default connect(mapStateToProps, mapDispatchToProps)(AppRouter)
Sidebar.js
//Imports etc...
export const Sidebar = (props) => {
const onRender = (id, phase, actualDuration, baseDuration, startTime, commitTime) => {
if (id !== 'Sidebar') { return }
console.log('Profile', phase, actualDuration)
}
return (
<Profiler id="Sidebar" onRender={onRender}>
<React.Fragment>
{/* Contents of Sidebar */}
</React.Fragment>
</Profiler>
}
const mapStateToProps = (state) => {
console.log('Sidebar mapStateToProps')
return {
//...
}
}
const areEqual = (prevProps, nextProps) => {
const areStatesEqual = _.isEqual(prevProps, nextProps)
console.log('Profile Sidebar isEqual', areStatesEqual)
return areStatesEqual
}
export default React.memo(connect(mapStateToProps, mapDispatchToProps)(Sidebar),areEqual)
Console output
Sidebar mapStateToProps 2
Profile Sidebar mount 225
Sidebar mapStateToProps
Profile Sidebar isEqual true
Sidebar mapStateToProps
Profile Sidebar update 123
Sidebar mapStateToProps 2
Profile Sidebar update 21
Sidebar mapStateToProps
Profile Sidebar update 126
Sidebar mapStateToProps
Profile Sidebar update 166
Sidebar mapStateToProps
Profile Sidebar update 99
Sidebar mapStateToProps
Sidebar mapStateToProps
Sidebar mapStateToProps
Sidebar mapStateToProps
Sidebar mapStateToProps
Sidebar mapStateToProps
Profile Sidebar update 110
Sidebar mapStateToProps
Sidebar mapStateToProps
Sidebar mapStateToProps
Profile Sidebar update 4
为什么 Sidebar 在 props 没有变化的情况下会重新渲染 八次?预计会重新渲染一次?
亲切的问候 /K
【问题讨论】:
-
您的
React.memo的第二个参数返回相反的值。它应该返回重新渲染是否会产生相同的结果 -
感谢@GalAbra 指出逻辑错误!在更改 React.memo 函数的返回值后,我已经用结果更新了上面的代码示例! /K
-
它没有解决问题吗? :(
-
不,抱歉! :( 结果完全一样。这让我有点困惑。是的 - 我已经仔细检查了我的代码。;) /K
-
在 mapStateToProps 中放置一个控制台日志,我怀疑有一个状态变化导致 mapStateToProps 返回一个新的引用,因为你没有记住它(比如使用重新选择)。因此,如果 redux 状态中的任何内容发生更改并且您拥有
const mapStateToProps=state=>({new:'reference'}),它将导致连接的组件重新渲染。