Я создаю веб-приложение, которое принимает сообщения WebSocket и регистрирует эти сообщения, используя React, Next.js.

У меня проблема с состоянием. Когда я ссылаюсь на state, всегда возвращается начальное значение.

Мой код выглядит следующим образом:

import React, { useState, useEffect } from 'react';
import { Container, Row, Col } from 'react-bootstrap';

export default function Home() {
  let socket = null;
  const [eventLog, setEventLog] = useState([]);
  const [updateFlag, setUpdateFlag] = useState(0);

  const onWebSocketMessage = (e) => {
    const data = JSON.parse(e.data);

    setEventLog(
      [
        {
          заголовок: data.title,
          иконка: data.icon,
          тело: data.body,
          дата: new Date(),
        },
      ].concat(eventLog)
    );

    setUpdateFlag(updateFlag + 1);
    console.log(updateFlag);
  };

  const connectWebSocket = (token) => {
    socket = new WebSocket('wss://localhost/' + token);
    socket.onmessage = onWebSocketMessage;
  };

  useEffect(() => {
    const token = localStorage.getItem('token');
    connectWebSocket(token);
  }, []);

  const eventLogHtml = eventLog.map((obj, index) => (
    

{obj.title}

{obj.body}

{obj.date.toString()}

)); return ( <> <Контейнер>

Журнал событий

{eventLogHtml}
); }

В этом коде eventLog всегда возвращает начальное значение, которое равно []. А console.log(updateFlag); всегда записывает 0.

Я ожидал, что eventLog и console.log(updateFlag); увеличатся при получении сообщения, но на самом деле устанавливается только самый новый и в журнал записывается 0.

Любой совет будет очень признателен. Спасибо!

Kaoru

Ответов: 2

Ответы (2)

У вас есть несколько проблем, таких как:

  • закрытие значения updateFlag, которое не будет повторно отображаться при следующем сообщении
  • переназначение значений, таких как socket и функции соединения
  • запись в журнал устаревшего значения состояния, когда setState является async.

Подведем итоги проверки исправленного кода:

let socket = null;

export default function Home() {
  const [eventLog, setEventLog] = useState([]);
  const [updateFlag, setUpdateFlag] = useState(0);

  useEffect(() => {
    console.log(updateFlag);
  }, [updateFlag]);

  useEffect(() => {
    const onWebSocketMessage = (e) => {
      const data = JSON.parse(e.data);

      setEventLog((prev) => [
        {
          title: data.title,
          icon: data.icon,
          body: data.body,
          date: new Date(),
        },
        ...prev,
      ]);

      setUpdateFlag((prev) => prev + 1);
    };

    const token = localStorage.getItem("token");
    socket = new WebSocket("wss://localhost/" + token);
    socket.onmessage = onWebSocketMessage;
  }, []);

  ...
}

Потому что вам нужно добавить dependencies на useEffect. Попробуйте это

useEffect(() => {
    const token = localStorage.getItem('token');
    connectWebSocket(token);
}, [eventLog]);

Как сказал Деннис. Он переподключает websocket при изменении eventLog. Поэтому вы должны разделить подключение и прослушивание события.

const token = localStorage.getItem("token");
socket = new WebSocket("wss://localhost/" + token);
//outside function component

useEffect(() => {
  const onMessage = () => {// do stuff}
  socket.on('message', onMessage)

  return () => socket.off('message', onMessage)
}, [eventLog, updateFlag])

2022 WebDevInsider