метод получения реактивного класса без обновления состояния или реквизита reactjs - PullRequest
1 голос
/ 11 февраля 2020

Я пытаюсь реализовать живой значок - актуальны ли текущие данные. EventSource используется для получения данных из серверной части.

Обновленное состояние рассчитывается следующим образом: каждый раз, когда я получаю новые данные из EventSource, я обновляю state.timestamp до текущей отметки времени ; затем в isLive getter я проверяю, что между текущим временем и сохраненной отметкой времени прошло менее 5 секунд.

В случае, если API перестал отвечать (например, не работает), новые данные не поступают, поэтому состояние не обновляется, и функция render не вызывается.

Наконец, я получаю live: true, когда должен получить live: false. Как мне решить эту проблему?

import React from "react";

const MAX_DELAY_IN_MS = 5 * 1000;

export default class App extends React.Component {
  constructor(props) {
    super(props);

    // creating an instance of EventSource
    const source = new EventSource("...");

    // binding event listeners
    this.onMessage = this._onMessage.bind(this);
    source.addEventListener("message", this.onMessage);

    this.state = {
      source,

      data: [],
      timestamp: null
    };
  }

  /**
   * Checks that between current time and last response time
   * has passed less than MAX_DELAY_IN_MS milliseconds.
   *
   * @property {boolean} isLive
   */
  get isLive() {
    const { timestamp } = this.state;

    return Date.UTC() - timestamp < MAX_DELAY_IN_MS;
  }

  _onMessage(event) {
    const { data } = this.state;

    // saving new data + setting new timestamp
    this.setState({
      data: [...data, event.data],
      timestamp: Date.UTC()
    });
  }

  render() {
    const { data } = this.state;

    return (
      <div>
        {/* always shows "true", even if the backend stopped responding */}
        {/* i guess that is because state/props aren't updated, so render() isn't called */}
        <p>Live: {this.isLive ? "true" : "false"}</p>

        {data.map(item => (
          <div key={item}>{item}</div>
        ))}
      </div>
    );
  }

  componentWillUnmount() {
    const { source } = this.state;

    source.removeEventListener("message", this.onMessage);
    source.close();
  }
}

ПРИМЕЧАНИЕ: Я создал проект CodeSandbox для тестирования этой проблемы. EventSource заменяется на FakeEventSource, который выдает данные каждые 500 мс. Вы можете имитировать, что API не работает, нажав соответствующую кнопку Imitate when Backend API is Down.

...