【问题标题】:How to fix 'index.js:1446 Warning: Can't call setState (or forceUpdate) on an unmounted component..." in ReactJS如何修复'index.js:1446警告:无法在未安装的组件上调用setState(或forceUpdate)......“在ReactJS中
【发布时间】:2019-06-06 14:14:44
【问题描述】:

我是 ReactJS 的初学者。我想构建一个反应应用程序供我自己使用。事实上,在我的网页中,我有三个按钮,一个用于增加我的 firebase 数据库中的一个字段,一个用于增加我的数据库中的另一个字段,最后用于清理这两个字段和 UI。 这些按钮有效,但是当我离开页面转到另一个页面时,控制台显示这些错误“index.js:1446 警告:无法在未安装的组件上调用 setState(或 forceUpdate)。这是一个无操作,但它表明您的应用程序中存在内存泄漏。要修复,请在 componentWillUnmount 方法中取消所有订阅和异步任务。

所以,我在互联网上搜索了一个解决方案,我只找到了告诉我设置一个变量 isMounted 并在 componentDidMount 和 componentWillUnmount 中更改她的解决方案。但问题仍然存在。所以我回到了我的第一个代码。 感谢您的帮助,抱歉英语不好,我是法语。

import React, { Component } from 'react';
import { Button } from 'antd';
import Nav from '../component/Nav';
import firebase from 'firebase';
import config from '../config/config';

class Recap extends Component{
    constructor(){
        super();
        !firebase.apps.length ? this.app = firebase.initializeApp(config) : this.app = firebase.app();
    this.database = this.app.database().ref().child('scoreMensuel');
    this.state={
        scoreMensuel : {
        },
        loading:true,
    } 
    this.style={
        styleTable:{width:'50%'},
        styleCell:{border:'1px solid black'},
        styleScoreField:{border:'1px solid black', height:'300px'}
    }
}

componentWillMount(){
    this.database.on('value', snapshot => {
        this.setState({
            scoreMensuel: snapshot.val()
        });
        this.setState({loading:false});
    });
}

addScore = event =>{
console.log(event.target.id);
    if(event.target.id === 'entrainementOk'){
        this.database.child('TeamGainz').transaction(function(currentValue) {
            return ( (currentValue) + 1);
        }, function(err, committed, ss) {
            if( err ) {
            return err;
            }
        });
    }else if(event.target.id === 'entrainementNotOk'){
        this.database.child('TeamKeh').transaction(function(currentValue) {
            return ((currentValue) + 1);
        }, function(err, committed, ss) {
            if( err ) {
            return err;
            }
        });
    }
}

clearScore = event =>{
    this.database.child('TeamGainz').transaction(function(currentValue) {
        return ( (currentValue) - (currentValue));
    });
    this.database.child('TeamKeh').transaction(function(currentValue) {
        return ( (currentValue) - (currentValue));
    });
}

render(){
    const loading = this.state.loading;
    if(loading){
        return(<h1>Chargement...</h1>)
    }
    return(
        <div className="reacp">
            <Nav/>
            <h1>Récapitulatif Mensuel</h1>
            <table style={this.style.styleTable}>
                <tbody className="tableauTeam">
                    <tr>
                        <td style={this.style.styleCell}>Team Gainz</td>
                        <td style={this.style.styleCell}>Team Keh</td>
                    </tr>
                    <tr>
                        <td 
                            style={this.style.styleScoreField} id='idTeam1'> {this.state.scoreMensuel.TeamGainz}
                            <Button type='danger' id='entrainementOk'onClick={this.addScore}>Entraînement Effectué</Button>
                        </td>
                        <td style={this.style.styleScoreField} id='idTeam2'>{this.state.scoreMensuel.TeamKeh} 
                            <Button type='danger' id='entrainementNotOk' onClick={this.addScore}>Entraînement Raté</Button>
                        </td>
                    </tr>
                </tbody>
            </table>
            <Button type='primary' style={{margin:'10px'}} onClick={this.clearScore}>Nettoyer le tableau</Button>
        </div>
    );
}
}

export default Recap;

即使此警告不影响按钮,我也想了解为什么会出现此警告。

【问题讨论】:

    标签: javascript reactjs firebase


    【解决方案1】:

    您不应该在componentWillMount 中调用setState。相反,请在componentDidMount 中调用它:

    componentWillMount(){
    // ^^^^^^^^^^^^^^^ change this to componentDidMount
        this.database.on('value', snapshot => {
            this.setState({
                scoreMensuel: snapshot.val()
            });
            this.setState({loading:false});
        });
    }
    

    这是一个问题的原因是因为调用 setState 会触发重新渲染器,如果我们在 componentWillMount 中调用它,我们可能会在渲染流程中的任何位置触发未安装组件的重新渲染。

    由于您基于(可能)异步回调触发状态更改,这意味着您在数据何时到达和 React 何时呈现之间存在竞争条件。

    其实React has deprecated componentWillMount and currently ships with UNSAFE_componentWillMount()

    反应文档:

    避免在此方法中引入任何副作用或订阅。对于这些用例,请改用 componentDidMount()。

    【讨论】:

    • 嘿,为什么我们不应该在 componentWillMount 中调用 setState?我知道我们不应该使用这种生命周期方法,因为它已被弃用,但是 componentWillMount 中的 setState 与警告有什么关系?
    • @HemadriDasari React 的文档明确指出,避免在此生命周期方法中同时使用 componenWillMount 和发出 XHR request/setState(很快将被弃用)
    • 您好,Firsts,感谢您的回答和解释,因为 4 天后我无法处理我的项目。所以,我尝试在componentDidMount中更改我的组件,但问题仍然存在:(
    猜你喜欢
    • 2018-11-03
    • 2019-03-10
    • 2019-01-07
    • 2019-01-26
    • 1970-01-01
    • 2019-08-23
    • 2023-04-08
    • 2018-10-28
    • 1970-01-01
    相关资源
    最近更新 更多