Loading and Using External Data in React

Hey JavaScripters! I’ve been learning a bunch about React lately. It’s very fun. It feels like a great way to write JavaScript. Seems to me it has almost the same feel jQuery did in the early days.

Confession though: I’m not master of it. I’m about to show you how to do something in React, without being a CertifiedSuperReactPro®. It works though, so something is going right.

State, State, State

One of the first things you learn in working with React is state. It’s pretty fundamental to React. It’s essentially data, and it could be anything!

Imagine the comments section of a website. Some of the “state” might be:

  • Is the comment form visible or not?
  • Is the “Submit Comment” button disabled or not?
  • The current value of the textarea, so it can be used in the comment preview area

But the state is also:

  • All the existing comments!

It makes sense, I think. Comments are part of different articles – they are different on every page. They are part of the data of that page. They are state.

// Just the state part of creating a React component
var Comments = React.createClass({

  getInitialState: function() {
    return {
      commentForm: {
        visible: true,
        submitVisible: false
      }
      comments: {
        unique-id-1: {
          name: "Chris Coyier",
          comment: "Lorem ipsum..."
        },
        unique-id-2: {
          name: "Sammy Sanddollar",
          comment: "Lorem ipsum..."
        }
      }
    }
  }

});

Building a mock “comment for” is exactly one of the exercises I used to help learn React. I have a video of me pairing with Sarah Drasner to do that you can watch.

Grabbing that data

In the case of comments, you likely have that data in your own app.

But data doesn’t have to come from yourself, data can come from anywhere. External data, if you will. Like from an API.

Ajax

Since we’re working entirely on the front end here, grabbing data from an API is Ajax territory. I don’t know about you, but I think of Ajax like this:

// jQuery!
$.ajax {
  url: "https://api.com/whatever"
}.then(function(data) {

});

But as I just learned in a recent article, jQuery isn’t exactly BFF’s with React. jQuery is mostly a DOM manipulation library, and React has its own way of doing those things. The Ajax stuff that jQuery provides is convenient, but replicable by other more focused libraries.

Axios is a library like that with an identical API.

Example Data

Let’s use some simple, publicly available JSON:

http://codepen.io/jobs.json

It’s simply a chunk of data that describes all the job postings on the CodePen Job Board.

Requesting the Data

In Axios, requesting that data is like:

axios
  .get("http://codepen.io/jobs.json")
  .then(function(result) {    
    // we got it!
  });

Setting the State with External Data

Now that we have the data, let’s make it available to our app by setting the state in React. The result is the chunk of JSON. The main bit of that is an array of job, exactly what our data setup is expecting. We use setState:

var App = React.createClass({

  getInitialState: function() {
    return {
      jobs: []
    }
  },

  componentDidMount: function() {
    var _this = this;
    this.serverRequest = 
      axios
        .get("http://codepen.io/jobs.json")
        .then(function(result) {    
          _this.setState({
            jobs: result.data.jobs
          });
        })
  },

  componentWillUnmount: function() {
    this.serverRequest.abort();
  },

  render: function() {
    return (
      <div>
        {/* Render stuff here */}
      </div>
    )
  }
});

There is a little bit of error handling here. If the Ajax request is still going when React (or you) decides to remove a component, the Ajax request will be aborted.

Also, make sure to render the component!

React.render(<App />, document.querySelector("#root"));

Templating the Data

You don’t need any additional libraries to do templating in React. HTML templating is a pretty fundamental part of React, especially if you write in JSX (that stuff that looks like HTML in JavaScript), which is highly recommended.

If we wrote HTML all by ourselves to represent a single job, it would be like this:

<div class="job">
  <a href="http://link-to-job.com">
    Company
    is looking for a 
    Full Time
    Web Designers
  </a>
</div>

I like thinking in that way: consider the HTML you want, then move that HTML over to JSX and replace the dynamic parts with state.

That becomes:

var App = React.createClass({

  getInitialState: function() {
    // ...
  },

  componentDidMount: function() {
    // ...
  },

  componentWillUnmount: function() {
    // ...
  },

  render: function() {
    return (
      <div>
        <h1>Jobs!</h1>
        {this.state.jobs.map(function(job) {
          return (
            <div key={job.id} className="job">
              <a href={job.url}>
                {job.company_name}
                is looking for a 
                {job.term}
                {job.title}
              </a>
            </div>
          );
        })}
      </div>
    )
  }
});

Demo

With all that together, we got ourselves a nice little React component that renders itself with external data!

See the Pen Load External Data in React by Chris Coyier (@chriscoyier) on CodePen.

Comments

  • Leon Shelhamer

    Chris you are the man, pleasant surprise to see your name in my Media Temple newsletter. I have learned so much from CSS-Tricks. This info introduced me to Axios, and shed some light on a subject that happens to be super relevant to a project I am getting ready to start. Thank you!

  • ShirtlessKirk

    It’s a XMLHttpRequest thing

    • Stephen Last

      Oh ok, thanks… So am I correct in saying that jQuery’s `$.ajax()` returns a XHR object (and so has an `abort()` method), but `axios.get()` returns a promise, which does not have an `abort()` method (I can only see `PromiseStatus` and `PromiseValue` properties)..??? I only ask because I’m getting `this.serverRequest.abort is not a function` on unmount.

      • ShirtlessKirk

        That’s what I’m seeing when inspecting the source for axios. Perhaps it should be calling .reject (as it is a Promise) or even check that the Promise is unfulfilled before calling anything…

        • Stephen Last

          Thanks… So Chris’s code as it stands isn’t quite right (looks like `componentWillUnmount` was taken from the FB example). Nice article all the same, I hadn’t heard of axios before, using it now…

  • While this works great for experimenting I would caution doing this in a production app. It’s best to keep the data fetching/manipulation outside of the view entirely via something like redux/[some other flux] or abstract it with something like relay.

    • Can you elaborate on the side effects of following the flux pattern – where the data fetching would actually originate from the top App component and just propagate down as props. Basically the example displayed here is bad for a single component to fetch the data but I don’t see an issue fetching it from the top.

      Maybe I’m missing something :)

    • Can you describe some of the side effects of this approach?

      • JP Shook

        For one, your components would be violating the S in SOLID, the single responsibility pronciple, by being responsible for both fetching and displaying the data. This makes it nearly impossible to unit test the component and tightly couples the data source to the view. A better approach here without using redux would be to create a smart wrapper component that fetches the data and provided it to your display component as props. That being said, Chris is only trying to demonstrate the mechanics of how you can use Ajax in React. Trying to teach Redux at the same time gets complicated quickly.

        • Makes sense. I am building a fairly decent sized app in React and felt like redux was overkill, so far it’s been good without it as it’s still easy enough to reason about the data flow.

    • Tiago Espinha (飞龙)

      Came here to say the same. It’s generally a bad a idea to do the HTTP requests in the presentation components… Maybe it would be nice if Chris added such a note to the post to avoid leading people down the wrong road.

  • [M]

    Altough it’s still experimental, an alternative to jquery and axios I would recommend using the fetch api with a proper polyfill.

  • wamala phillip

    I’ve always found chris a great teacher. His tutorials are always simple especially css-tricks. Im really new to react and im doing alot of reading about it. I find this article helpful in simplifying the way react picks external data without the complication of using redux (at least for example purposes).

  • Justin Lipshitz

    I am getting a CORS error with this. I guess codepen have blocked this. I see the example does not display the jobs here either. I suppose it is the same problem

  • Elijah

    how can I get a json file that will be hosted in a /json/ folder on my client’s web folder? I don’t want to have to define the “http://www.theirsite.com/ for the file, because I want to use it in my development server too. pls help.

Related Articles