Search code examples
asynchronousreactjsfirebaseflux

Flux - How to initially load Store data with asynchronously fetched data


Using: Vanilla React and Flux Firebase

I'm trying to keep my store synced with realtime updates and so I've been following the instructions of this article Handling Synchronized Arrays with Real-Time Firebase Data

I've placed a call to a the WebAPI utilities class to fetch the initial data and placed it in the componentWillMount listener of my top level component as instructed by many.The code looks like so.

var MessageSection = require('./MessageSection.react');
var React = require('react');
var ThreadSection = require('./ThreadSection.react');
var ChatWebAPIUtils = require('../utils/ChatWebAPIUtils');
var ChatApp = React.createClass({

  componentWillMount: function(){
    ChatWebAPIUtils.getAllMessages(); **Here is my call to an action**
  }

  render: function() {
    return (
      <div className="chatapp">
        <ThreadSection />
        <MessageSection />
      </div>
    );
  }

});

module.exports = ChatApp;

The problem is that even though my store will be loaded correctly, it looks like because it's an asynchronous fetch there will be calls to render components whose data is still not ready.

What is the conventional way to wait for the store be initialized before my program tries to render itself?


Solution

  • You might be able to use the components state for this.

    getInitialState() {
        return {
            messagesLoaded: false,
            messages: [],
            threads: []
        }
    },
    onMessagesLoaded() {
        this.setState({
            messagesLoaded: true,
            messages: ChatWebAPIUtils.messages,
            threads: ChatWebAPIUtils.threads
        });
    },
    componentDidMount() {
        ChatWebAPIUtils.getAllMessages(this.onMessagesLoaded.bind(this))
    },
    render() {
        if(!this.state.messagesLoaded) {
            return (<div className="chatapp">Loading...</div>);
        }
    
        return (
            <div className="chatapp">
                <ThreadSection />
                <MessageSection />
            </div>
        );
    }
    

    You set the initial state to empty arrays for messages and threads. As soon as the component did mount, you call your async function and pass a callback function to it which will then update the state of the component - therefor causing the component (and the children which receive the new state) to update. As long as the data is not loaded - a "Loading" message is displayed.

    It should also be possible to call your getMessages function in the componentWillMount() section.

    I guess that the MessagesSection should only show the messages of the currently selected thread. I didn't take this into account for the example - so you'll have to add this logic somewhere too.

    Edit: added information about preventing rendering of child components before data is loaded.