【问题标题】:Warning: setState(...): Can only update a mounted or mounting component, How to unmount?警告:setState(...):只能更新已安装或正在安装的组件,如何卸载?
【发布时间】:2018-03-26 14:03:11
【问题描述】:

我知道这个问题标题已被多次询问,但我的问题有所不同。我不确定如何使用componentWillUnmount 解决这个问题。

我正在使用firebase 的新FireStore 添加数据。我也关注变化

componentDidMount() {
        fdb.collection(collectionName)
            .onSnapshot({includeDocumentMetadataChanges: true}, function (querySnapshot) {
            let items = [];
            querySnapshot.forEach(function (doc) {
                let source = doc.metadata.hasPendingWrites ? "[OF]" : "[ON]";
                items.push(source + " -> " + doc.data().title);
                console.log(source, " data: ", doc && doc.data());
            });
            this.setState({"items": items});
        }.bind(this));
    }  

也就是说,每次加载一个新的更改,整个组件都会刷新,也就是说当前的组件会被丢弃,这样理解正确吗?

如果是,那意味着我应该停止收听这个快照,因为这个快照会消失。这种理解正确吗?

如果是,我不知道如何停止收听这个正在进行的手表。
我的整个代码看起来像

import React from "react";
import {fdb} from "../mainPage/constants";

const collectionName = "todos";
export default class ToDos extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            items: [],
            textBox: "",
            loading: true
        }
    }

    componentDidMount() {
        fdb.collection(collectionName)
            .onSnapshot({includeDocumentMetadataChanges: true}, function (querySnapshot) {
            let items = [];
            querySnapshot.forEach(function (doc) {
                let source = doc.metadata.hasPendingWrites ? "[OF]" : "[ON]";
                items.push(source + " -> " + doc.data().title);
                console.log(source, " data: ", doc && doc.data());
            });
            this.setState({"items": items});
        }.bind(this));
    }


    handleTextBoxChange = (event) => {
        this.setState({textBox: event.target.value});
    };

    handleAddItem = () => {
        fdb.collection(collectionName).add({
            "title": this.state.textBox
        }).then(function (docRef) {
            console.log("added " + docRef.id , docRef.get());
        }.bind(this));
    };

    handleRemoveItem = (index) => {
        let remainingItems = this.state.items;
        remainingItems.splice(index, 1);
        this.setState({items: remainingItems});
    };

    render() {
        return (
            <div>
                <div>
                    <input type="text" value={this.state.textBox} onChange={this.handleTextBoxChange}/>
                    <input type="submit" value="Add Item" onClick={this.handleAddItem}/>
                </div>
                <div>{this.state.items.map((item, index) => <Item key={index}
                                                                  index={index}
                                                                  item={item}
                                                                  onDeleteClick={this.handleRemoveItem}/>)}</div>

            </div>
        )
    }
}

const Item = ({index, item, onDeleteClick}) => {
    return <div>
        <input type="button" value="delete" onClick={() => onDeleteClick(index)}/>
        <span>{item}</span>

    </div>
};

我在开发者控制台上看到的是

Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the ToDos component.  

有人可以帮我解决这个问题吗?

【问题讨论】:

标签: javascript reactjs firebase google-cloud-firestore


【解决方案1】:

根据@Brahma Dev 的评论,这就是我解决它的方法。

我在 Component 的状态中添加了对 onSnapshot 的引用,并在调用 componentWillUnmount 时调用它。

componentWillMount() {
    let unsubscribe = fdb.collection(collectionName)
        .onSnapshot({includeDocumentMetadataChanges: true}, function (querySnapshot) {
        let items = [];
        querySnapshot.forEach(function (doc) {
            let source = doc.metadata.hasPendingWrites ? "[OF]" : "[ON]";
            items.push(source + " -> " + doc.data().title);
            console.log(source, " data: ", doc && doc.data());
        });
        this.setState({"items": items});
    }.bind(this));
    this.setState({"unsubscribe": unsubscribe});
}

componentWillUnmount() {
    this.state.unsubscribe();
}

如果ReactJS 有更好的处理方法,请告诉我。谢谢

【讨论】:

  • 我建议不要将函数放入状态,因为它会使 react 的内部差异变得无用。而是在 componentWillMount 中执行 this.unsubscribe = fdb... 并在 componentWillUnmount 中执行 this.unsubscribe && this.unsubscribe()
猜你喜欢
  • 2017-04-26
  • 2016-10-13
  • 1970-01-01
  • 1970-01-01
  • 2017-03-02
  • 2019-08-15
  • 1970-01-01
  • 2016-09-25
  • 1970-01-01
相关资源
最近更新 更多