KellyCMI
KellyCMI

Reputation: 197

Rendering data from Firebase in React

Please, help me with rendering data retrived from Firebase Realtime Database.

I succefully retrived data frome Firebase as an array. Next step is to display the data - here the problem begins.

The data I want to display should be stored in "modules" state. At first, it's set as an empty array. Then data are retrived, state is updated by setState in CoumponentDidMount lifecycle method - I can see the data as an array in my React DevTool - but component is not rendering (displaying) them.

I suppose that a propblem has something to do with lifecycle methods, because I can log the state in the console, but I can also see a pop-up info that the array (retrived from Firebase) "was evaluated just now". If I'm right, it means that the data are retrived after render method? What shall I do, to solve the problem and diplay data properly?

Here is my code:

    import React, { Component } from "react";
import firebase from "firebase";
import { DB_CONFIG } from "./database/db_config";
import ModulesData from "./modulesData";
//import LandingPage from "./components/landingPageComponents/landingPage";
import ThematicAreaNav from "./components/navbarComponents/thematicAreaNav";
import ThematicArea from "./components/singleModuleComponents/thematicArea";
import OrderList from "./components/orderListComponents/orderList";
import Footer from "./components/footerComponents/footer";

let chosenModulesArray = [];

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      holdClickedModulesNames: chosenModulesArray,
      modules: []
    };
  }

  componentDidMount() {
    let ref = firebase
      .initializeApp(DB_CONFIG)
      .database()
      .ref();

    ref.once("value").then(dataSnapshot => {
      this.response = dataSnapshot.val()["modulesData"];
      this.setState({ modules: this.response });
    });
  }

  render() {
    return (
      <div>
        {console.log(this.state.modules)}}{/*<LandingPage />*/}
        <ThematicAreaNav modules={this.state.modules} />
        <div className="main-layout">
          <ThematicArea
            modules={this.state.modules}
            orderedModules={this.props.orderedModules}
            clickedModuleNames={this.state.holdClickedModulesNames}
            chosenModulesNames={this.state.holdClickedModulesNames}
          />

          <OrderList
            clickedModuleNames={this.state.holdClickedModulesNames}
            chosenModulesNames={this.state.holdClickedModulesNames}
          />
        </div>
        <div className="footer">
          <Footer />
        </div>
      </div>
    );
  }
}

export default App;

enter code here

Upvotes: 2

Views: 2221

Answers (2)

Luke Walker
Luke Walker

Reputation: 501

From a visual perspective If your data is being returned after render(), rather than showing a blank screen or half populated component, show a loading screen whist waiting for your data to be populated - this is always good practice from a UX perspective!

Code example:

class app extends Component {
    constructor(props){
        modules:null,
        loading:true,
    }

    componentDidMount(){
        getModules();
    }
    getModules(){
        let ref = firebase
         .initializeApp(DB_CONFIG)
         .database()
         .ref();

        ref.once("value").then(dataSnapshot => {
          this.response = dataSnapshot.val()["modulesData"];
          //once the data is back, set the loading to false so it can be rendered
          this.setState({ data: this.response, loading: false });
        });
    }
    render(){
        // deconstruct 'modules' from the state to call it without this.state...
        const {modules, loading, holdClickedModulesNames} = this.state;
        const { orderedModules } = this.props;
        return loading ? (
            <div>
                loading...
            </div>
        ) : (
            <div>
              <ThematicAreaNav modules={modules} />
              <div className="main-layout">
                <ThematicArea
                  modules={modules}
                  orderedModules={orderedModules}
                  clickedModuleNames={holdClickedModulesNames}
                  chosenModulesNames={holdClickedModulesNames}
                />

                <OrderList
                  clickedModuleNames={holdClickedModulesNames}
                  chosenModulesNames={holdClickedModulesNames}
                />
              </div>
              <div className="footer">
                <Footer />
              </div>
            </div>
        )
    }
}

Upvotes: 2

Sagar Jajoriya
Sagar Jajoriya

Reputation: 2375

Bcoz you're trying to perform an asynchronous action within the componentDidMount() method. You can use async await:

async componentDidMount() {
    let ref = await firebase
      .initializeApp(DB_CONFIG)
      .database()
      .ref();

    const firebaseResponse = await ref.once("value");

    this.response = firebaseResponse.val()["modulesData"];
    this.setState({ modules: this.response });
}

Upvotes: 1

Related Questions