无法在未安装的组件上调用 setState
Posted
技术标签:
【中文标题】无法在未安装的组件上调用 setState【英文标题】:Can't call setState on an unmounted component 【发布时间】:2018-11-19 08:19:57 【问题描述】:在React Native中不断收到如下错误信息,真的不明白是从哪里来的
警告:无法在未安装的设备上调用 setState(或 forceUpdate) 零件。这是一个无操作,但它表明您的内存泄漏 应用。要修复,请取消所有订阅和异步任务 在 componentWillUnmount 方法中。
我有以下简单的组件:
class App extends React.Component
constructor(props)
super(props)
this.state =
isLoggedIn: false,
componentDidMount()
this.fetchToken()
async fetchToken()
const access_token = await AsyncStorage.getItem('access_token')
if (access_token !== null)
this.setState( isLoggedIn: true )
render()
const login = this.state.isLoggedIn
if (login)
return <NavigatorLoggedIn />
else
return <Navigator/>
【问题讨论】:
你应该在构造函数内初始化状态,而不是在它之外。并使用this.state
,而不仅仅是state
。我也不会将 async
属性应用于 React 的默认生命周期方法,最好保持原样。为此创建一个单独的async/await
组件函数,然后在componentDidMount
中调用它
感谢您的回答!用您的建议更新了组件。原始警告仍然存在;(
componentDidMount()
在渲染后运行,因此在render()
中看不到/不可用更新状态。然后我想这个组件在任何情况下都会通过render()
卸载,因此根据错误消息,在导致内存泄漏之后调用fetchToken()
。
@radarbob 就是这么想的!任何解决方案的建议?试图自己找到解决方案
副手:(1) 在最顶部的render()
中执行此操作。 (2) 在构造函数中进行。在任何一种情况下,都使用带有函数的the other form of setState()
;因为setState()
本质上是异步的
【参考方案1】:
取消所有异步操作是解决办法之一
【讨论】:
【参考方案2】:你可以试试这个:
class App extends React.Component
constructor(props)
super(props)
this.state =
isLoggedIn: false,
_isMounted = false;
componentDidMount()
this._isMounted = true;
this.fetchToken()
async fetchToken()
const access_token = await AsyncStorage.getItem('access_token')
if (access_token !== null && this._isMounted)
this.setState( isLoggedIn: true )
componentWillUnmount()
this._isMounted = false;
render()
const login = this.state.isLoggedIn
if (login)
return <NavigatorLoggedIn />
else
return <Navigator/>
通过使用 _isMounted,setState 仅在组件已挂载时调用,卸载不会等待异步调用完成。最终,当异步调用结束时,组件已经被卸载,因此它无法设置状态。为此,答案只是在设置状态之前检查组件是否已安装。
【讨论】:
【参考方案3】:对我来说,我通过“yarn start”或“npm start”重启服务器解决了这个问题
【讨论】:
【参考方案4】:你需要使用 isMounted 变量。
componentDidMount()
this.setState( isMounted = true );
const access_token = await AsyncStorage.getItem('access_token')
if (access_token !== null && this.isMounted)
this.setState( isLoggedIn: true )
componentWillUnmount()
this.setState( isMounted = false );
或者如果你使用axios,你可以使用axios的取消请求功能 这里是:https://github.com/axios/axios#cancellation
【讨论】:
感谢您的快速回答!试过了但是isLoggedIn的setState不能这样工作 我不明白。如果组件仍然挂载,则 setState 正常工作。 if 语句不运行,&& this.isMounted
不工作
你是否尝试过使用 promise 或 callback 而不是 async/await。
RN 文档说不调用 setState on 将卸载:reactjs.org/docs/react-component.html#componentwillunmount【参考方案5】:
它会起作用的:
let self;
class App extends React.Component
constructor(props)
super(props)
self = this;
this.state =
isLoggedIn: false,
componentDidMount()
this.fetchToken()
async fetchToken()
const access_token = await AsyncStorage.getItem('access_token')
if (access_token !== null)
self.setState( isLoggedIn: true )
render()
const login = self.state.isLoggedIn
if (login)
return <NavigatorLoggedIn />
else
return <Navigator/>
【讨论】:
【参考方案6】:你可以使用它:
componentDidMount()
this.function()
function = async () =>
const access_token = await AsyncStorage.getItem('access_token')
if (access_token !== null)
this.setState( isLoggedIn: true )
或者您可以在constructor
中致电function
。
希望对你有帮助……
【讨论】:
感谢您的快速回答!尝试过,但在原始问题中得到相同的警告 请注意,不要在构造函数中调用 async/await 函数。构造函数应该初始化组件并尽快返回它。如果您需要等待异步函数,请在componentDidMount
中调用它。以上是关于无法在未安装的组件上调用 setState的主要内容,如果未能解决你的问题,请参考以下文章
React 警告:setState(...) 只能更新已安装或正在安装的组件