Сервер отправляет события, которые умножаются при входе в React - PullRequest
0 голосов
/ 29 июня 2019

У меня есть простое приложение Java Spring, которое использует отправленные сервером события для отправки данных во внешнее приложение React.Вот как написан сервер:

 @GetMapping(value = "/plot", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux get() {
        return Flux.interval(Duration.ofMillis(1000))
                .map(interval ->
                        currentStateMapper.map(eventRepository.getAll()).stream()
                                .map(plotDataMapper::map)
                                .collect(Collectors.toList())
                );
    }

Возможно, это менее важно, но идея в том, что я сохраняю последние события, а репозиторий передает мне все сохраненные события (они хранятся вкэш бесконечности), а затем я использую некоторые средства отображения, чтобы получить текущее состояние, а затем сопоставить его с объектами, подходящими для визуализации с помощью графика XY.

Он должен отправлять сообщение с данными построения на веб-интерфейс каждую секунду.И когда я открываю конечную точку с помощью своего браузера (Chrome), он работает как шарм.может видеть новый JSON, появляющийся каждую секунду.Но когда я использую источник событий React для получения сообщений вместо 1 сообщения каждую секунду, я получаю 6 одинаковых сообщений каждую секунду.Вот реализация веб-интерфейса:

const Component = () => {
  const plotDataEventSource = new EventSource(
    "http://localhost:8080/tags/plot/antenna"
  );

  useEffect(() => {
    plotDataEventSource.onmessage = e => {
      console.error(e)

      setData(prevState => {
       /* some data handling */ 
        return newState;
      });
    };
  });

  return ( /* html with plot */ );
}

И поэтому console.error () регистрируется 6 раз в секунду, идентичные объекты.В чем может быть причина такого поведения?

Ответы [ 2 ]

1 голос
/ 29 июня 2019

useEffect будет вызывать обратный вызов при каждом рендеринге - если вы хотите, чтобы он вел себя как componentDidMount , вы должны передать пустой массив в качестве второго аргумента.

Второй аргумент - это массив значений (обычно реквизит):

  1. Если изменяется любое из значений в массиве, обратный вызов будет вызываться после каждого рендеринга.
  2. Когда он отсутствует, обратный вызов всегда будет запускаться после каждого рендеринга.
  3. Когда это пустой список, обратный вызов будет запускаться только один раз, аналогично componentDidMount.
1 голос
/ 29 июня 2019

В нем отсутствуют некоторые важные части вашего кода, но повторная визуализация может происходить из-за того, что вы не сообщили useEffect, при каких условиях он должен выполняться, и это может быть достигнуто с помощью второго параметра в useEffect method.

Как вы написали, useEffect срабатывает каждый раз, когда ваш компонент рендерится.Если вы внесете небольшое изменение, передав условие useEffect, оно будет выполняться только при изменении этого условия.Например:

useEffect(() => {
    plotDataEventSource.onmessage = e => {
      console.error(e)

      setData(prevState => {
       /* some data handling */ 
        return newState;
      });
    };
  }, [data]); // <---- Assuming you are changing something called data.

Когда ваш компонент выполняет рендеринг, useEffect будет сравнивать значение data и будет работать, только если оно изменилось.

...