#reactjs #websocket #rerender
#reactjs #websocket #повторный рендеринг
Вопрос:
Я застрял в том, чтобы избежать повторного рендеринга компонента, когда я использую Websocket для получения данных и обновления их в пользовательском интерфейсе. У меня есть компонент с именем A, и я использую Websocket в нем для получения сообщения в режиме реального времени, а затем показываю его в пользовательском интерфейсе. Я использую такой хук «useEffect»:
function User() {
let ws = new Websocket(host);
let [users, setUser] = useState([]);
useEffect(() => {
let message = [];
ws.onmessage = evt => {
message = JSON.parse(evt.data);
setUser(message);
}}, [users]);
return (
<div className="user-table">
<Table users={users} />
</div>
)
}
Поскольку Websocket часто содержит новые данные (1 секунда), это приводит к постоянному обновлению компонента. Итак, есть ли какой-либо способ избежать этой проблемы? (кэширование или что-то в этом роде)
Комментарии:
1. Вы делаете
setUser
— можете ли вы показать, какuser
используется? Это где-то отображается?2. Я объявляю это с помощью перехвата react. Вот так: пусть [users, setUser] = useState([]). Извините, что пропустил это в сообщении.
3. Да, понятно, что это перехват, но где он используется ? Можете ли вы показать, как компонент отображает?
4. Я действительно не понимаю, в чем здесь проблема. Причина, по которой вы используете сокеты, заключается в том, что, вероятно, вам нужны данные в реальном времени, и если вы хотите избежать частого получения данных, тогда зачем вам вообще использовать websockets. Просто используйте простой ajax-запрос всякий раз, когда вам нужны новые данные. Кроме того, если вам достаточно однократного рендеринга, вы можете изменить ` [users]` на
[]
5. Привет, Гарри, я использую сокет, потому что я хотел бы быть уверенным, что не пропущу никаких новых данных, и я хочу, чтобы пользовательский интерфейс автоматически обновлялся всякий раз, когда на сервере появляются новые данные.
Ответ №1:
Проблема здесь не в самом сокете, а в том факте, что ваш useEffect
массив зависимостей содержит состояние, и что useEffect
обратный вызов добавляет слушателя, и что обратный вызов изменяет состояние. Каждый раз, когда setUser
вызывается, users
изменяется — и когда users
изменяется, useEffect
выполняется снова, потому что изменилась одна из его зависимостей.
Удалите users
из массива зависимостей и объявляйте сокет только один раз в useEffect
, чтобы у вас был активен только один сокет (по User
крайней мере …) одновременно.
function User() {
const [users, setUsers] = useState([]);
useEffect(() => {
const ws = new Websocket(host);
ws.onmessage = evt => {
setUsers(JSON.parse(evt.data));
};
// Close socket on unmount:
return () => ws.close();
}, []); // <-- empty dependency array; only run callback once, on mount
return (
<div className="user-table">
<Table users={users} />
</div>
);
}
Также обратите внимание:
- Лучше предпочесть
const
, чемlet
в ES6 - Чтобы уменьшить количество ошибок, назовите переменные соответствующим образом — если у вас несколько пользователей, используйте
users
иsetUsers
. (Если у вас только один пользователь, используйтеuser
иsetUser
)
Если есть вероятность, что их может быть больше одного User
, было бы лучше создать сокет только один раз в родительском, а затем передать его как prop; таким образом, вы не будете создавать несколько сокетов, которые все делают одно и то же.
Комментарии:
1. Спасибо за вашу помощь. Я понимаю, что моя проблема в том, что сокет всегда отправляет данные примерно за 1 секунду один раз.