提问人:Coding Ninja123211 提问时间:11/3/2023 最后编辑:Coding Ninja123211 更新时间:11/3/2023 访问量:66
React - 使用 Memo 不阻止组件的重新渲染
React - Use Memo not preventing re-render of component
问:
在我的应用程序中,我有一个存储在 state 中的对象,它存储了一堆消息对象。我使用钩子来检索组件中的数据。我映射数据,并按如下方式显示:Chat
{Object.keys(storedUsers).length !== 0 && chatId && Object.keys(chatMessages).length !== 0 && Object.values(chatMessages).map((messageObj, index) => {
return <ChatMessage key={index} messageObj={messageObj} />
})}
在 ChatMessage 中,我有一个消息对象,我显示其数据。这是 ChatMessageComponent:
const ChatMessage = ({messageObj}) => {
// MEMOIZED VALUE
const newMessageObj = useMemo(() => {return messageObj})
if (messageObj.admin === true) return
const sentById = newMessageObj.sentBy
let sentByUser
let isOwn
if (sentById === userData.userId) {
sentByUser = userData
isOwn = true
}
else {
sentByUser = storedUsers && storedUsers[sentById] || newChatData && newChatData.otherUsersData
}
return (
<div className='d-flex flex-row' style={{marginTop: 50}}>
// VIDEO COMPONENT
<Video messageObject={newMessageObj} />
</div>
)
我在这个组件中有一个组件,我只想在装载时或消息 URL 更改时呈现它。<Video />
视频组件:
import React, { memo, useEffect } from 'react'
const Video = memo(({messageObject}) => {
useEffect(() => {
console.log('RE-RENDERED');
}, [])
return (
<video>
<source src={messageObject.url} />
</video>
)
},)
export default Video
但是,当组件中的不相关状态发生更改时,将重新呈现子项。我正在记住作为道具传递到组件中的消息对象。如何确保除非必要,否则 Video 组件不会重新渲染?是否缺少任何导致组件重新渲染的内容?谢谢。ChatMessages
Video component
Video
更新:
用于检索 ChatMessages 的选择器:
const chatMessages = useSelector((state) => state.messages.messagesData[chatId]) || {}
答:
React 组件需要稳定。用作密钥是一种常见的反模式,但它实际上是创建密钥的几个选项中最糟糕的。这可能是记忆问题的根本原因。key
Math.random
提示是您的控制台日志:
useEffect(() => {
console.log('RE-RENDERED');
}, [])
此控制台日志不会像消息所暗示的那样在重新渲染时触发,而只会在首次挂载组件时触发。由于您在“渲染”上看到这种触发,因此它实际上意味着每次父渲染时都会卸载并重新装载组件。
这正是组件更改时将发生的情况。告诉 react 你指的是组件的哪个实例。如果它看到相同的键,它就知道它是同一个实例 - 所以重新渲染它。如果它看到一个不同的键,它就知道这是一个新组件 - 所以它会销毁旧组件并创建一个新实例。key
key
要解决您的问题,请找到一个合适的唯一稳定值。这可能是数组项中的内容,或者在最坏的情况下是数组项的内容。messageObj
index
.map((messageObj, index) => {
// Ideally use something from the messageObj, but the index works in a pinch
return <ChatMessage key={index} messageObj={messageObj} />
})}
这里最大的收获是永远不要用作 .我经常在这里和其他地方的代码中看到它,因为它很快就摆脱了控制台中的警告,但它比仅仅使用数组索引要糟糕得多。Math.random
key
评论
key={message.id}
key
useMemo
评论
newMessageObj