React 导致不必要的重新渲染

问题描述 投票:0回答:1

我正在创建一个聊天应用程序,在尝试实现链接预览时遇到一些问题(当您发送链接时,我想从网址加载标题和图像)。从下面的代码中您可以看到我正在映射文本数组中的每个“文本消息”并呈现一个名为 ChatMessage 的组件。每个 ChatMessage 组件代表来自组中用户的一条消息。一旦我打开聊天,消息就会被加载,链接也会被预览。我遇到的问题是,在我从另一个用户发送或接收的每条消息上,所有 ChatMessage 组件都会重新呈现,因此所有链接都会再次预览(再次从 url 获取数据,这会导致链接瞬间显示 url,并且然后是从 useEffect 加载后加载的数据)。

我怎样才能防止这种情况发生?如何只加载一次链接,而不是每次收到新消息或自己发送消息时加载链接?下面是代码。

----- Chat.jsx ---------

{members.length > 0 && text.map((m, index) => { return <ChatMessage key={index} text={text} m={m} index={index} isMessageSending={isMessageSending} /> })}

--------ChatMessage.jsx ---------

export const ChatMessage = memo(({ text, m, index, isMessageSending }) => {
    // "m" prop is a message object containing message and timestamp when it was sent.
    // "text" prop is all messages in a chat
    const { usersRef } = useContext(PageContext);
    const [userMessageData, setUserMessageData] = useState({});
    const isSentByMe = m.sentBy === auth.currentUser.uid;
    const [linkData, setLinkData] = useState({});

    // this useEffect is supposed to be called when the m.message changes. Why does it get called again when i send a new message? Each message represents this component so it shouldn't be "related" to other messages.
    useEffect(() => {
        if(!m.message) return;

        let foo = async () => {

            if (isValidUrl(m.message)) {
                const data = await fetchDataFromLink(m.message);
                setLinkData(data.result);
            } else {
                setLinkData({});
            }
        }
        foo();
    }, [m.message]);

    return (
        <div> ... </div>
    )

我尝试使用 memo 和 useCallback 来加载链接的预览,但一旦我点击发送消息按钮,它仍然不断重新渲染。

reactjs firebase
1个回答
0
投票

A

ChatMessage
的 props 包含
text
属性,它是聊天中所有消息的数组。当您发送消息时,
text
数组会更新以将新消息包含在其列表中,因此该道具的所有依赖项都将重新渲染。在这种情况下,这将是每个单独的
ChatMessage
组件,就像在您的
text.map(..)
中一样,您将实时
text
作为每个组件的支柱传递。

memo
函数的目的是保留计算。但是,当其组件的 props 更改时,它不会记忆,因为从语义上讲,该 prop 可能包含“更新的数据”,可能需要在其组件中反映出来,因此必须重新渲染该组件(重新渲染)计算),然后使用这些新条件进行记忆。如果此后 props 保持不变,
memo
将不会重新渲染。

从提供的代码片段来看,

text
道具似乎在每个
ChatMessage
中都未使用,因此简单的解决方案是将其从道具列表中完全删除而不将其传入。

如果

ChatMessage
确实在代码中未显示的内容中使用了
text
属性中的数据,那么也许看看您需要的数据是否可以在某个记忆点或以恒定的方式与
text
属性分离。核心问题在于,当为每个
ChatMessage
提供
text
属性时,您使它们了解整个聊天的实时数据,而不是成为一个独立的组件。如果
ChatMessage
不需要广播随后的新聊天,甚至不需要广播之前的聊天,那么它应该会自然地跟随,以便您将所需的数据与您可能用于每个
texts
ChatMessage
分开.

© www.soinside.com 2019 - 2024. All rights reserved.