#javascript #reactjs #redux #react-redux #react-memo
#javascript #reactjs #redux #react-redux #react-memo
Вопрос:
Я создаю приложение для чата с помощью react, react-redux и socket.io . Теперь, чтобы повысить производительность приложения, я добавил React.memo()
его в свой <Message ... />
компонент, чтобы предотвратить повторную визуализацию. Однако, согласно профилировщику React, все мои компоненты сообщений продолжают повторную обработку, как только я получаю дополнительные сообщения. Мой код:
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 amp;amp; <Preloader type='inline' />}
</React.Fragment>
) : (
<Placeholder
text='No messages'
icon='icon icon--bubbles'
type='full'
/>
)}
</section>
...
export default withRouter(Room);
message.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: [],
};
...
Профилировщик
Ответ №1:
Это происходит потому, что одна или несколько зависимостей (реквизитов) компонентов сообщений обновляются при получении сообщений. Проверьте, есть ли какая-либо опора, зависящая от действия fetch msg.
Если есть функции, которые вы передаете компоненту сообщения, пожалуйста, оберните их в useCallback hook.
И все же, если проблема существует, вы можете передать функцию для проверки предварительных и последующих запросов в React.memo
const isEqual = (prevProps, nextProps) => {}
React.memo(Message, isEqual)