首页 > 解决方案 > React 组件(react-redux props)不断使用 React.memo() 重新渲染

问题描述

我正在使用 react、react-redux 和 socket.io 构建一个聊天应用程序。现在,为了提高应用程序的性能,我添加React.memo()到我的<Message ... />组件中以防止重新渲染。但是,根据 React Profiler,我的所有消息组件都会在我获取更多消息时继续重新渲染。我的代码:

room.jsx(消息容器)

import { useSelector, useDispatch } from "react-redux";
import {
  fetchMessagesRequest,
  fetchMessagesSuccess,
  fetchMessagesFailure,
  fetchPageMessagesSuccess,
  fetchPageMessagesFailure,
} from "../../redux/actions";

const Room = ({ match, history }) => {

  const dispatch = useDispatch();
  const socket = useSelector((state) => state.socket);
  const room = useSelector((state) => state.room);
  const user = useSelector((state) => state.user);

    <section className='room__content'>
                {room.messages.length ? (
                  <React.Fragment>
                    {room.messages.map((msg, idx) =>
                      idx + 1 === room.messages.length ? (
                        <Message
                          key={msg._id}
                          reference={lastMessageRef}
                          msg={msg}
                          text={msg.message}
                          file={msg.file ? msg.file : ""}
                          date={msg.creationDate}
                          state={msg.state}
                          deleteMessage={() => deleteMessage(msg._id)}
                          likeMessage={() =>
                            broadcastLike(msg._id, user.data.userID)
                          }
                        />
                      ) : (
                        <Message
                          key={msg._id}
                          msg={msg}
                          text={msg.message}
                          file={msg.file ? msg.file : ""}
                          date={msg.creationDate}
                          state={msg.state}
                          deleteMessage={() => deleteMessage(msg._id)}
                          likeMessage={() =>
                            broadcastLike(msg._id, user.data.userID)
                          }
                        />
                      )
                    )}
                    {preload && <Preloader type='inline' />}
                  </React.Fragment>
                ) : (
                  <Placeholder
                    text='No messages'
                    icon='icon icon--bubbles'
                    type='full'
                  />
                )}
              </section>  
    
...

export default withRouter(Room);

消息.jsx

import React, { useState, useEffect } from "react";
import "./message.scss";

import { LazyLoadImage } from "react-lazy-load-image-component";

/* REDUX */
import { useSelector, useDispatch } from "react-redux";
import { showGallery, showModal, setMessage } from "../../redux/actions";

const Message = ({
  reference,
  msg,
  text,
  file,
  date,
  state,
  deleteMessage,
  likeMessage,
}) => {
  const [loaded, setLoaded] = useState(false);
  const user = useSelector((state) => state.user);
  const dispatch = useDispatch();

  useEffect(() => {
    let mounted = true;

    axios
      .get(...)
      .then()
      .catch()
      .finally(() => setLoaded(true));

    // CLEANUP
    return () => (mounted = false);
  }, []);

  return (
    <React.Fragment>
      {loaded ? (
        <figure
          ref={reference}
          className={`message${author.tag === user.data.tag ? "--author" : ""}`}
        >
            <div className='message__content'>
              <p className='message__content__text'>{text}</p>
            </div>
        </figure>
      ) : (
        ""
      )}
    </React.Fragment>
  );
};

export default React.memo(Message);

roomReducer.js

...

case "FETCH_PAGE_MESSAGES_SUCCESS":
  const messages = [...action.payload.messages, ...state.messages];

  return {
    ...state,
    messages: messages
      .filter(
        (v, i, a) =>
          a.findIndex((t) => JSON.stringify(t) === JSON.stringify(v)) === i
      )
      .sort((a, b) => new Date(b.creationDate) - new Date(a.creationDate)),
    total: action.payload.total,
    error: [],
  };

...

探查器

在此处输入图像描述

标签: javascriptreactjsreduxreact-reduxreact-memo

解决方案


发生这种情况是因为当您获取消息时,消息组件的一个或多个依赖项(道具)正在更新。检查是否有任何道具取决于 fetch msg 操作。

如果有要传递给 Message 组件的函数,请将它们包装在useCallback钩子中。

如果问题仍然存在,您可以传递一个函数来检查 React.memo 中的 prevProps 和nextProps

 const isEqual = (prevProps, nextProps) => {}
 React.memo(Message, isEqual)

推荐阅读