javascript - 如何根据属性正确处理订阅
问题描述
我有一个全局服务widgetService
,它保存许多小部件的数据,每个小部件由widgetID
. 每个小部件的数据都可以随时更改。我想显示一个带有 React 组件的小部件,比如WidgetReactComponent
.
反应组件应将小部件 ID 作为属性,并从小部件服务获取要显示的信息。可以使用 方法从小部件服务中查询小部件的数据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
根据 react 的建议,这应该通过使用函数根据属性设置状态来处理。但由于它是静态的,我无权访问该组件,也无法相应地更改侦听器。
解决此问题的一种方法是将 存储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
解决方案
您不需要存储widgetID
在状态中,您可以prevProps
与以下内容进行比较this.props
:
componentDidUpdate(prevProps, prevState) {
if (prevProps.widgetID !== this.props.widgetID) {
widgetService.removeListenerForWidget(prevProps.widgetID, this._onDataChange);
widgetService.addListenerForWidget(this.props.widgetID, this._onDataChange);
}
}
您还需要在第一次渲染时不调用监听componentDidMount
器:componentDidUpdate
componentDidMount() {
widgetService.addListenerForWidget(this.props.widgetID, this._onDataChange);
}
关于您的担忧:
当 shouldComponentUpdate 返回 false 时不会调用 componentDidUpdate
从文档:
使用 shouldComponentUpdate() 让 React 知道组件的输出是否不受当前状态或道具变化的影响。
因此,如果您决定在this.props.widgetID
更改时不更新组件,那么您就违反了假设/目的,shouldComponentUpdate
并且不应该期望您的小部件侦听器被更新。
如果您无论如何都滥用,很多事情都不会按预期工作shouldComponentUpdate
(例如,组件未更新以反映新数据),因此依赖按照官方文档正确使用的 API 是实现简单性的必要条件,而不是要避免的事情.
在属性更改和更新完成之间的整个时间跨度内,侦听器都是错误的
通过这种逻辑,当您在事件处理程序中更新某些显示的数据时,您还可以声称在事件和重新渲染之间的整个时间跨度内显示的数据是错误的。您甚至可以声称您的文本编辑器在您按下键盘键和在屏幕上呈现键之间显示错误的数据。
推荐阅读
- json - 资源标识符格式错误的 Json 模板
- scala - NoSuchMethodError:org.json4s.FieldSerializer。
- reporting-services - 根据组和设置值的阈值
- python - 以科学计数法显示的注释
- javascript - 揭示模块模式 Javascript
- python - 无法将 .csv 转换为数据框错误:“str”对象不可调用
- java - 确定上传文件的确切类型/扩展名
- javascript - 带有反引号(``)的jQuery append()如何错过/不会呈现字符串变量?
- html - 如何为大行(多行的大行)设置条形表的颜色
- python - 为什么在列表推导中是 if-else before 而只是 if 是 after?