React 警告:setState(...) 只能更新已安装或正在安装的组件
Posted
技术标签:
【中文标题】React 警告:setState(...) 只能更新已安装或正在安装的组件【英文标题】:React Warning: setState(...) Can only update a mounted or mounting component 【发布时间】:2016-10-13 05:22:51 【问题描述】:我有一个问题:我正在使用 React/ReactNative + Flux 构建我的第一个应用程序,我收到以下警告:
setState(...):只能更新一个挂载或挂载的组件。这 通常意味着您在未安装的组件上调用了 setState() 。这是 无操作。请检查未定义组件的代码。
在我的代码上方:
class ListMovies extends React.Component
constructor(props)
super(props);
this.state =
dataSource: new ListView.DataSource(rowHasChanged: (row1, row2) => row1 !== row2),
loaded: false
;
;
componentDidMount()
ApiListMovies.getMovies();
ListMoviesStore.addChangeListener(() => this._onChange());
;
componentWillUnmount()
ListMoviesStore.removeChangeListener(() => this._onChange());
;
_onChange()
console.log(this.state);
this.setState(
dataSource: this.state.dataSource.cloneWithRows(ListMoviesStore.getListMovies()),
loaded: true
);
;
render()
return (
<ListView
dataSource=this.state.dataSource
renderRow=this.renderMovie
style=styles.listView
/>
);
renderMovie(movie)
return (
<View style=styles.container>
<Image
source=uri: movie.posters.thumbnail
style=styles.thumbnail
/>
<View style=styles.rightContainer>
<Text style=styles.title>movie.title</Text>
<Text style=styles.year>movie.year</Text>
</View>
</View>
);
module.exports = ListMovies;
如您所见,我正在以非常简单的方式向您展示电影列表。现在显示一个改变视图的 sn-p。当我将应用中的页面从放映电影的页面更改为放映信息时,我的问题就出现了。
class TabsView extends React.Component
//do stuff...
renderContent()
switch (this.state.tab)
case 'List Movies':
return <ListMoviesView/>;
case 'Info':
return <InfoView/>;
render()
return (
<View style=styles.content key=this.state.tab>
this.renderContent()
</View>
);
module.exports = TabsView;
我在第一个 sn-p 的函数 _onChange() 中放置了一个 log()(因为问题存在),当我更改页面时,该函数被调用多次并获得上述警告。如何解决?我在哪里做错了?谢谢!
【问题讨论】:
看来你没有删除监听器。所以 _onChange 函数即使你改变了页面也会触发。我不熟悉通量,但是,听众可以没有迹象表明要听吗? 【参考方案1】:您正在为每个 add 和 remove 事件侦听器函数提供一个 new 函数实例。因此,删除将无法按预期工作,因为它针对的是不同的函数实例,并且更改事件仍然会触发事件。
我猜您是在将匿名函数传递给添加/删除事件侦听器,以维护您的 this.setState
调用范围。您可以使用绑定到类属性的匿名函数来维护范围,然后在添加/删除调用中简单地引用该属性,如下所示:
componentDidMount()
ApiListMovies.getMovies();
ListMoviesStore.addChangeListener(this._onChange);
;
componentWillUnmount()
ListMoviesStore.removeChangeListener(this._onChange);
;
// We use anonymous function bound to the class property, this
// will maintain our scope.
_onChange = () =>
console.log(this.state);
this.setState(
dataSource: this.state.dataSource.cloneWithRows(ListMoviesStore.getListMovies()),
loaded: true
);
;
注意:以上依赖于class properties syntax,该class properties syntax 正在提议中,目前通过 babel 阶段 1 启用。如果你没有这个,你可以在构造函数调用中创建函数。像这样:
class ListMovies extends React.Component
constructor(props)
this.state =
dataSource: new ListView.DataSource(rowHasChanged: (row1, row2) => row1 !== row2),
loaded: false
;
// We use anonymous function bound to the class property, this
// will maintain our scope.
this._onChange = () =>
console.log(this.state);
this.setState(
dataSource: this.state.dataSource.cloneWithRows(ListMoviesStore.getListMovies()),
loaded: true
);
;
componentDidMount()
ApiListMovies.getMovies();
ListMoviesStore.addChangeListener(this._onChange);
;
componentWillUnmount()
ListMoviesStore.removeChangeListener(this._onChange);
;
【讨论】:
以上是关于React 警告:setState(...) 只能更新已安装或正在安装的组件的主要内容,如果未能解决你的问题,请参考以下文章
“警告:setState(...):只能更新已安装或已安装的组件”是啥意思?
React - setState(...): 只能更新一个挂载或挂载的组件
如何避免未使用的 setState 函数?可以在没有 setter 的情况下创建 React useState 吗?