如何正确分离Firebase DB子事件侦听器?

时间:2019-12-29 13:38:55

标签: javascript reactjs firebase firebase-realtime-database

我正试图分离此侦听器:

listenForNew() {
    const firebase = this.props.firebase;
    let newestDate = new Date().getTime();
    if(this.state.subitiq.length !== 0) {
        newestDate = this.state.subitiq[this.state.subitiq.length-1].date;
    }
    console.log("listening after date " + (newestDate+1));
    const ref = firebase.database().ref().child('subitiq').orderByChild('date').startAt(newestDate+1).on('child_added', snapshot => {
        console.log("added new subitie with key " + snapshot.key);
        let subitie = snapshot.val();
        subitie.key = snapshot.key;
        let subitiq = this.state.subitiq.slice(0);
        subitiq.push(subitie);
        let showedSubitiq = this.state.showedSubitiq.slice(0);
        showedSubitiq.push(subitie);
        this.setState({subitiq: subitiq, showedSubitiq: showedSubitiq});
        //console.log(subitie);
    }, error => {
        console.error(error);
    });

    this.addRefListener(ref, 'subitiq', 'child_added');
} // listenForNew()

这是addRefListener():

addRefListener(ref, refPath, listener) {
    let refs = this.state.refs;
    let listeners = this.state.listeners;
    let refPaths = this.state.refPaths;
    refs.push(ref);
    refPaths.push(refPath);
    listeners.push(listener);
    this.setState({refPaths: refPaths, refs: refs, listeners: listeners});
} // addRefListener()

这就是我试图分离的方式:

    componentWillUnmount() {
        this.componentCleanup();
        window.removeEventListener('beforeunload', this.componentCleanup); // remove the event handler for normal unmounting
    }
    componentDidMount() {
        window.addEventListener('beforeunload', this.componentCleanup);
//...
}
    componentCleanup() { // this will hold the cleanup code
        // whatever you want to do when the component is unmounted or page refreshes
        const firebase = this.props.firebase;
        for(let i=0; i<this.state.refs.length; i++) {
            try {
                firebase.database().ref().child(this.state.refPaths[i]).off(this.state.listeners[i]);
                console.log("removed listener at '" + this.state.refPaths[i] + "' on '" + this.state.listeners[i] + "' #1 block");
            } catch(er) {
                console.log("error block #1");
                console.error(er);
            }

            try {
                firebase.database().ref().child(this.state.refPaths[i]).off(this.state.listeners[i], this.state.refs[i]);
                console.log("removed listener at '" + this.state.refPaths[i] + "' on '" + this.state.listeners[i] + "' #2 block");
            } catch(er) {
                console.log("error block #2");
                console.error(er);
            }

            try {
                this.state.refs[i].off(this.state.listeners[i]);
                console.log("removed listener at '" + this.state.refPaths[i] + "' on '" + this.state.listeners[i] + "' #3 block");
            } catch(er) {
                console.log("error block #3");
                console.error(er);
            }
        }
    }

我在第3块上出错(this.state.refs [i] .off不是一个函数),第1块和第2块没有给出错误,但实际上它们没有释放。 /> 我发现了很多问题,尝试了很多事情,但我仍然不明白我该怎么做?

2 个答案:

答案 0 :(得分:0)

  

您可以通过将单个监听器作为参数传递给off()来删除它。在不带参数的位置上调用off()会删除该位置上的所有侦听器。

例如,如果您有此侦听器:

const ref = firebase.database().ref().child('subitiq').orderByChild('date').startAt(newestDate+1).on('child_added', snapshot =>

然后将其分离,您需要使用相同的引用并执行以下操作:

ref.off('child_added');

off()也是Reference内部的方法

https://firebase.google.com/docs/reference/js/firebase.database.Reference.html#off

答案 1 :(得分:0)

在下一行中,由于具有on(...)函数,因此您调用的ref对象不是Reference / Query对象,而是实际上的快照回调函数(snapshot => { /* ... */ })。

const ref = firebase.database().ref().child('subitiq').orderByChild('date').startAt(newestDate+1).on('child_added', snapshot => { /* ... */ }, error => { /* ... */ });

要获取引用/查询对象,必须将这些行拆分为以下内容:

let queryRef = firebase.database().ref().child('subitiq').orderByChild('date').startAt(newestDate+1);
let callback = queryRef.on('child_added', snapshot => { /* ... */ }, error => { /* ... */ });

一旦拥有了这两个功能,就可以调用addListenerUnsubscribe函数的我的版本addRefListener

addListenerUnsubscribe(queryRef, 'child_added', callback);

稍后清理组件时,您只需像这样调用unsubscribeAllListeners()

componentCleanup() {
  unsubscribeAllListeners();
}
addListenerUnsubscribe(ref, eventType, callback, name) {
    let listeners = this.state.listeners;
    listeners.push({ref: ref, eventType: eventType, cb: callback, name: name});
    this.setState({listeners}); // this seems unneccessary
}

unsubscribeAllListeners() {
    let listeners = this.state.listeners;
    listeners.forEach((listener) => {
      listener.ref.off(listener.eventType, listener.callback);
    });
    this.setState({listeners: []});
}

使用上述代码,如果需要,您还可以按名称删除一组侦听器。

unsubscribeListenersByName(name) {
    let listeners = this.state.listeners;
    let remaining = listeners.filter((listener) => {
      if (name !== listener.name) return true; // keep
      listener.ref.off(listener.eventType, listener.callback);
    });
    // remaining is an array of still active listeners
    this.setState({listeners: remaining});
}

参考文献: