无法在未安装的组件上调用 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 语句不运行,&amp;&amp; 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的主要内容,如果未能解决你的问题,请参考以下文章

在未安装的组件上调用 setState() [重复]

React 警告:setState(...) 只能更新已安装或正在安装的组件

卸载组件时对 setState 做出反应警告

如何解决反应原生 EventEmitterListener 警告

不变违规:无法在未安装的组件上找到节点。阿波罗

React:“无法在未安装的组件上执行 React 状态更新”,没有 useEffect 功能