2

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

2 Answers 2

2

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>
        )
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks a lot - works brilliant! And thanks for code cleaning advice ;)
As another sidenote, you could create a <Loading/> component and import it in anytime you need to use. Passing props for loadingText etc...
1

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 });
}

5 Comments

Still the exactly the same. I've written this: async componentDidMount() { let ref = firebase .initializeApp(DB_CONFIG) .database() .ref(); const firebaseResponse = await ref.once("value"); await ref.once("value").then(dataSnapshot => { this.response = dataSnapshot.val()["modulesData"]; this.setState({ modules: this.response }); }); }
Is this method firebase.initializeApp(DB_CONFIG).database().ref() synchronous or asynchronous ? If synchronous, then you also need to add await to it.
None. What is more, I can properly log retrived data from Firebase. So it's not about configuration. I even tried to rstart server.
It hold an array of objects - exactly the format that I need to display :)
and says that "value below was evaluated just now"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.