Thinking in React - Fetching Data with AJAX

Just jotting down some 'aha' moments in my understanding of React:

  • React provides a declarative library that keeps the DOM in sync with your data.
  • React components just render props and state.
  • React components just represent the UI at a certain point in time.
  • Use the componentDidMount method to fetch data with AJAX.

TLDR; Skip to the codesandbox snippet below to take a look at the code


Random Aside: The cool thing is that grokking this 'React Thinking' has helped to structure my code at work. Our stack at iHerb is just jQuery *cries*, and so it's super easy to start writing a spaghetti mess. Our team made some significant strides by refactoring to follow the module and prototype pattern, but having this 'React Thinking', making the UI a representation of application state, has drastically increased the maintainability of our code.


React Components Just Render props and state

React just renders components, and data in React comes from two places: props or state.

When thinking about where to fetch data in React, the underlying concept is that data needs to somehow get into the component's props or state.

React Components Represent the UI at a Certain Point in Time

The beauty of React is that a component is just supposed to represent the UI at a certain point in time.

The render() method, therefore, should not have any code that contain side effects, nor anything that is asynchronous in nature. It is just suppose take the current props and state and represent that as DOM elements.

Fetch Data in the componentDidMount lifecycle method

The componentDidMount method is the recommended place to make any AJAX data calls.

The componentDidMount method only executes once during a component’s life: at the point when the component mounts to the DOM for the first time.

By using this lifecycle method, it is clear that data won’t be loaded until after the initial render and enforces the pattern of setting up an initial default state to prevent any undefined state that could result in unexpected app behaviour.


Below is a simple example of how we can update a component’s state (a list of GitHub repos) with this.setState in the componentDidMount method. Once the state is updated, React triggers a re-render, and then the repos are rendered to the DOM.

export default class GitHubRepos extends React.Component {  
  constructor(props) {
    super(props);

    this.state = {
      repos: []
    };
  }
  componentDidMount() {
    axios
      .get(
        window.encodeURI(
          `https://api.github.com/search/repositories
             q=stars:>1+language:javascript&sort=stars&order=desc&type=Repositories`,
        ),
      )
      .then(response => {
        const repos = response.data.items;
        this.setState({
          repos
        });
      })
      .catch(error => {
        console.log(error);
      });
  }

The full code is in my codesandbox below:


Caveat with Fetching Data in componentWillMount

It seems logical to use the componentWillMount method to load data, since the goal is to have data loaded into the app before it gets rendered to the DOM.

However, fetching data with AJAX happens asynchronously. There is no way to pause or delay React from continuing to render the component (maybe with a hacky setTimeout? I haven't tried..).

The component will end up rendering before that data is loaded.

The problem with using componentWillMount is it isn't explicit (to the developer / maintainer) that the component will render without data at least once. By assuming that the component will have data returned on first-render, the developer could naively skip setting up the component's default state, and the handling of default state.

Without setting default a state, the initial render of the component will have a state of undefined (and probably some bugs to track down!).

Duncan Leung

Front End Developer at iHerb.com

Irvine, CA

Subscribe to Duncan Leung: Javascript and Front End Development

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!