У меня есть глобальная служба widgetService
, которая содержит данные для ряда виджетов, каждый из которых идентифицируется как widgetID
. Данные каждого виджета могут измениться в любое время. Я хочу отобразить виджет с компонентом React, скажем WidgetReactComponent
.
Реактивный компонент должен взять идентификатор виджета в качестве свойства и получить информацию, отображаемую из службы виджетов. Данные виджета могут быть запрошены из сервиса виджетов методом getWidgetData(widgetID)
. И чтобы иметь возможность публиковать изменения данных, он также предлагает два метода: addListenerForWidget(widgetID, listener)
и removeListenerForWidget(widgetID, listener)
.
Если предположить, что свойство установлено один раз и никогда не изменяется, это можно сделать следующим образом, следуя рекомендациям React:
class WidgetReactComponent extends Component {
constructor() {
super();
this.state = {
data: widgetService.getWidgetData(this.props.widgetID)
};
this._onDataChange = this._onDataChange.bind(this);
}
_onDataChange(newData) {
this.setState({data: newData});
}
componentDidMount() {
// React documentation: "This method is a good place to set up any subscriptions."
widgetService.addListenerForWidget(this.props.widgetID, this._onDataChange);
}
componentWillUnmount() {
// React documentation: "Perform any necessary cleanup in this method, such as [...] cleaning up any subscriptions that were created in componentDidMount()."
widgetService.removeListenerForWidget(this.props.widgetID, this._onDataChange);
}
render() {
return <div className="Widget">{this.state.data.stuff}</div>;
}
}
Компонент может быть использован следующим образом:
<ReactWidgetComponent widgetID={17} />
Однако свойство widgetID
может измениться в любое время, и компонент должен обработать это, чтобы нормально функционировать при любых обстоятельствах. В соответствии с рекомендацией реагирования это должно быть выполнено путем установки состояния на основе свойств с помощью функции static getDerivedStateFromProps
. Но так как он статический, у меня нет доступа к компоненту и я не могу соответственно изменить слушателей.
Один из способов обойти это - сохранить widgetID
в состоянии, а затем использовать метод жизненного цикла componentDidUpdate
для обнаружения изменений, например:
constructor() {
super();
this._onDataChange = this._onDataChange.bind(this);
}
static getDerivedStateFromProps(nextProps) {
return {
widgetID: nextProps.widgetID,
data: widgetService.getWidgetData(nextProps.widgetID)
};
}
componentDidUpdate(prevProps, prevState) {
if (prevState.widgetID !== this.state.widgetID) {
widgetService.removeListenerForWidget(prevState.widgetID, this._onDataChange);
widgetService.addListenerForWidget(this.state.widgetID, this._onDataChange);
}
}
Однако componentDidUpdate
не будет вызываться, когда shouldComponentUpdate
возвращает false
. Это не похоже на безопасный способ сделать это. Также я считаю, что слушатели будут ошибаться в течение всего промежутка времени между изменением свойства и завершением обновления. Как я могу безопасно реализовать это?