Есть ли способ избежать непрерывной повторной визуализации при вызове WebSocket из компонента React?

#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 секунду один раз.