React:动态更改Firebase路径

时间:2018-02-28 11:23:10

标签: javascript reactjs firebase firebase-realtime-database

我想在点击按钮时更改firebase路径。旧连接断开连接但未建立新连接。下面是我正在使用的代码实例。

import React, { Component } from "react";
import firebase from "./firebase";

class ParentComponent extends Component {
  constructor() {
    super();
    this.state = {
      path: "someDirectory1/subDirectory"
    };
    this.changePath = this.changePath.bind(this);
  }

  changePath() {
    this.setState({ path: "/someDirectory2/subDirectory" });
  }

  render() {
    return (
      <React.Fragment>
        <ChildComponent path={this.state.path} />
        <button onClick={this.changePath}>Change path</button>
      </React.Fragment>
    );
  }
}

class ChildComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      mountRef: firebase.database().ref(this.props.path + "/path2")
    };
  }

  componentWillMount() {
    var ref = firebase.database().ref(this.props.path + "/path1");
    ref.once("value", snapshot => {
      var data = snapshot.val();
      //Some functionality
    });
  }

  componentDidMount() {
    var ref = this.state.mountReference;
    ref.on("value", snapshot => {
      var snapshotData = snapshot.val();
      //some functionality
    });
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.path !== this.props.path) {
      this.state.mountReference.off("value");
      var ref = firebase.database().ref(nextProps.path);
      this.setState({ path: nextProps.path, ref });
    }
  }

  render() {
    return (
      <React.Fragment>
        {/* {Some rendering} */}
        {/* {Some rendering} */}
      </React.Fragment>
    );
  }
}

如果我添加componentWillUpdatecomponentDidMount来侦听新路径,则侦听器会进入无限循环。如果我使用shouldComponentUpdate,那么最初会多次调用它,因为父组件中的其他状态正在更改,并且数据不会呈现,因为条件nextProps.path!==this.props.path返回false

2 个答案:

答案 0 :(得分:0)

由于您希望在Click上更改路径,因此您应远离生命周期方法,并将您的逻辑放入一个单击时触发的函数。如果您希望在组件安装时触发一次该函数,则在componentDidMount中调用它。

例如:

funkyFirebaseFunction() {
 firebase.database()
  .ref(this.props.path + "someDirectory1/subDirectory")
  .once("value", snapshot => {
      var data = snapshot.val();
      //Some functionality
    });
}

然后你可以在函数内重复firebase调用,并在boolean in状态的基础上在两者之间交替。

this.state = {
  clicked: false
}

请确保在firebase调用后翻转布尔值。

funkyFirebaseFunction() {
  this.state.clicked ?
     firebase.database()
      .ref(this.props.path + "someDirectory1/subDirectory")
      .once("value", snapshot => {
          var data = snapshot.val();
          //Some functionality
        })
     : firebase.database()
      .ref(this.props.path + "someDirectory2/subDirectory")
      .once("value", snapshot => {
          var data = snapshot.val();
          //Some functionality
        });

     this.setState({clicked: !this.state.clicked});

    }

然后调用函数onClick

<button onClick={() => this.funkyFirebaseFunction()}>Change path</button>

你可以在componnetDidMount中弹出对它的引用,如果你想要它开始一次。

componentDidMount() {
  this.funkyFirebaseFunction
}

答案 1 :(得分:0)

我找到了多路径的解决方案。

import React, { Component } from "react";
import firebase from "./firebase";

class ChildComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      mountRef: firebase.database().ref(this.props.path + "/path2")
    };
    this.oneTimeListen = this.oneTimeListen.bind(this);
    this.asyncListen = this.asyncListen.bind(this);
  }



  componentWillMount() {
    var ref = firebase.database().ref(this.state.path + "/path1");
    this.oneTimeListen(this.props.path, ref);
  }

  componentDidMount() {
    var ref = this.state.mountReference;
    this.asyncListen(ref);
  }



  componentWillReceiveProps(nextProps) {
    if (nextProps.path !== this.props.path) {
      this.state.mountReference.off("value");

      // initial listen
      var ref = firebase.database().ref(nextProps.path + "/path1");
      this.setState({ path: nextProps.path });
      this.oneTimeListen(nextProps.path, ref);

      // listens to changes
      ref = firebase.database().ref(nextProps.path + "/path2");
      this.asyncListen(ref, true);
    }
  }

  /**
   * Listens to path only for one time initially.
   * @param {String} path - firebase path
   * @param {Object} ref - firebase reference variable
   */
  oneTimeListen(path, ref) {
    ref.once("value", snapshot => {
      var data = snapshot.val();
      //functionality
  }


  /**
   * Listens continuously to changed values
   * @param {Object} ref - firebase reference variable
   * @param {Boolean} setNewRef - if true, change this.state.mountReference, (only true, when firebase path changes)
   */

  asyncListen(ref, setNewRef) {
    ref.on("value", snapshot => {
      var snapshotData = snapshot.val();
      //functionality

      if (setNewRef) {
         this.setState({ mountReference: ref });
      }
    });
  }

  render() {
    return (
      <React.Fragment>
        {/* {Some rendering} */}
        {/* {Some rendering} */}
      </React.Fragment>
    );
  }
}

oneTimeListen()用于初次收听path1

asyncListen()用于在path2上持续收听。

每当收到新路径时,componentWillReceiveProps()会调用oneTimeListen()asyncListen()并将新引用发送给相应的功能。