javascript - 如何在未安装的组件上修复 'index.js:1446 Warning: Can' t 调用 setState(或 forceUpdate)...“在 ReactJS 中

标签 javascript reactjs firebase

我是 ReactJS 的初学者。我想构建一个供我自己使用的 React 应用程序。事实上,在我的网页中,我有三个按钮,一个用于增加我的 firebase 数据库中的一个字段,一个用于增加我数据库中的另一个字段,最后一个用于清理这两个字段和 UI。 这些按钮有效,但是当我离开页面转到另一个页面时,控制台显示这些错误“index.js:1446 Warning: Can't call setState (or forceUpdate) on an unmounted component. This is a no-op , 但它表明您的应用程序中存在内存泄漏。要解决此问题,请取消 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;

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

最佳答案

您不应该在 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()

react 文档:

Avoid introducing any side-effects or subscriptions in this method. For those use cases, use componentDidMount() instead.

关于javascript - 如何在未安装的组件上修复 'index.js:1446 Warning: Can' t 调用 setState(或 forceUpdate)...“在 ReactJS 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54150211/

相关文章:

javascript - 为什么导出 withAlert(Alerts) 会导致错误,但 withAlert()(Alerts) 却有效?

javascript - React.createClass 不是一个函数,可能是 webpack 编译错误

javascript - componentWillReceiveProps 不会触发

firebase - 将大型 json 文件从 Firebase 存储传输到 Firestore

angularjs - 如何使用 Angular 删除firebase中的json数据对象?

javascript - 在 JS 中哪里添加分号可以防止缩小错误?

JavaScript MaxLength 不适用于新的文本字段

javascript - 水平溢出内容无滚动条拖放

java - 如何将 .addSnapShotListener 设置为 fragment 中的集合引用

javascript - 如何将属性 `preserveAspectRatio` 添加到 Highchart svg