Я пытаюсь реализовать живой значок - актуальны ли текущие данные. 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
.