1. 程式人生 > >How to Use React to display NASA’s Astronomy Picture of the Day

How to Use React to display NASA’s Astronomy Picture of the Day

How to Use React to display NASA’s Astronomy Picture of the Day

Goal: Display NASA’s Astronomy Picture of the Day from the date a user inputs

In my first week of learning React, after wrapping my head around the ideas of state and props, I discovered that it’s really fun to build things with React! I wanted to build something of my own, so I decided to use NASA’s Astronomy Picture of the Day (APOD) API to build an app that allows users to view photos based on a date. NASA claims that their Astronomy Picture of the Day website “has the popular appeal of a Justin Bieber video,” so I wanted to try to make something even better. We’ll walk through the steps to create a very simple React app that displays a photo from the NASA APOD API based on the date that a user inputs.

Creating the App

To create and start the app, you can use the handy Create React App project generator developed by Facebook:

create-react-app astronomy-picture-of-the-daycd astronomy-picture-of-the-daynpm start

This sets up a React app so you can start building! In your browser, you should automatically be redirected to and see the “Welcome to React” page:

This page even tells us where to get started: src/App.js.

Setting Up The Components

Our App is going to render two components: DateInput to get the user’s input of a date andPhoto to display the photo. Create a folder in the src folder called components and then create a file for each of these components in this folder:

cd srcmkdir componentscd componentstouch DateInput.jstouch Photo.js

I like to first set up a very simple static version of my app to ensure that I have the correct import and export in each file.

//App.jsimport React, { Component } from "react";import DateInput from "./components/DateInput";import Photo from "./components/Photo.js";
class App extends Component {  render() {    return (      <div>        <h1>NASA's Astronomy Picture of the Day</h1>        <DateInput />        <Photo />      </div>    );  }}export default App;
//DateInput.jsimport React from "react";
const DateInput = props => <div>DateInput</div>;
export default DateInput;
//Photo.jsimport React from "react";
const Photo = props => <div>Photo</div>;
export default Photo;

In the browser, you should see:

Cool! Our components are rendering correctly.

Thinking About State

Next, we want to think about what state we need and where it should live. We know that the DateInput component will receive a user’s input of a specific date. We will use that date to fetch a picture from NASA’s Astronomy Picture of the Day API, then display that picture in the Photo component. Both the date and the photo can change, so we’ll keep both of them in state.

Where should the state live? The DateInput component will update the date, which will be used to fetch and update the photo, which will need to be passed to the Photo component to render. Because of this, we will keep the date and photo in the common parent to these components, which is App. For now, we’ll add state to our App and initialize each piece with an empty string.

class App extends Component {  state = {    date: "",    photo: ""  };    ...
}

Using the React Developer Tools, we can verify that our state is where it should be:

Getting a Date

Now that we have the basic parts of our React app set up, we can think about the data flow in our app. From a user’s perspective, they will enter a date and the corresponding photo will appear. In terms of our app, that means the following steps will occur:

  1. The user will input a date in the DateInput component
  2. The App’s state will update to reflect the user’s date input
  3. We will use the date to make a fetch to the API, then update the photo in the App's state
  4. The Photo component will display the photo

Let’s focus on the first two steps for now. We need to have a form in DateInput where a user can input a date. When the user submits this form, it needs to update the date in the state of App. That means we need to write a function in App to update the state, and then pass that function down as a prop to DateInput. The function will be called when the form is submitted, and update the state in App using the value entered into the form. Since we haven’t created the form yet, let’s just prevent the default behavior of the event (so the page doesn’t refresh) and log the event’s target. This will help us determine how to get the value the user entered.

class App extends Component { ...
changeDate = e => {    e.preventDefault();    console.log(e.target);  };
render() {    return (      <div>        <h1>NASA's Astronomy Picture of the Day</h1>        <DateInput changeDate={this.changeDate} />        <Photo />      </div>    );  }}

We can verify that the function has been passed to our DateInput component by using the React dev tools:

Now we need a form in DateInput. When a user submits this form, it will call on the changeDate function that is in its props. For now, let’s assume the user will input the date in a very specific format: YYYY-MM-DD (the reason for this will become apparent in our next step; we’ll improve the user experience later!)

const DateInput = props => (  <form onSubmit={props.changeDate}>    Enter a date (YYYY-MM-DD):    <input />    <input type="submit" />  </form>);

We should now see a form where “DateInput” used to be.

Let’s enter a date and see what happens. In our console, we should see the event’s target:

This shows us that the event target is the form. The first input field in the form is where the user enters the date, so we can access the value of that input using e.target[0].value. In our changeDate function, we want to update our the date in our App’s state to this value.

class App extends Component { ...
changeDate = e => {    e.preventDefault();    let dateFromInput = e.target[0].value;    this.setState({ date: dateFromInput });  };
...
}

Now when we enter a date and click Submit, we should see the state updated with the date we entered:

Now we’re ready to get a photo!

Fetching Today’s Photo

The NASA APOD API is pretty simple to use. NASA provides a default API key, but if (like me), you exceed the rate limit and can no longer make requests, you can sign up to immediately get your own API key. The query has one optional parameter of date, which defaults to today’s date, and needs to be formatted YYYY-MM-DD (just like our state!).

Where are we going to make this fetch? We want to store the photo in the state of the App, so we’ll do it there!

It would be nice if today’s photo automatically appeared when a user visits the page, before the user even enters a date. Luckily, React has a lifecycle method that we can use to make a fetch just before the component renders: componentDidMount. If we make a fetch to the API without providing a date, it will return today’s photo. (If you are using your own API key, you should replace DEMO_KEY in the url below.)

class App extends Component {   ...
  componentDidMount() {    fetch(`https://api.nasa.gov/planetary/apod?api_key=$DEMO_KEY`)      .then(response => response.json())      .then(json => this.setState({ photo: json }));  }
  ...}

We can use the React dev tools to see that we now have today’s photo in the state:

Cool! Let’s see if we can display it. We need to first pass this photo down to the Photo component, which will render it.

class App extends Component {   ...
  render() {    return (      <div>        <h1>NASA's Astronomy Picture of the Day</h1>        <DateInput changeDate={this.changeDate} />        <Photo photo={this.state.photo} />      </div>    );  }}

Now we just need to update our Photo component to display the photo that it has access to in its props. We’ll show the picture’s title, the photo from the url, and the explanation.

const Photo = props => (  <div>    <h3>{props.photo.title}</h3>    <img src={props.photo.url} alt={props.photo.title} />    <p>{props.photo.explanation}</p>  </div>);

If we look in the browser, we should see today’s photo!

Changing the Picture Based On Date

Our last step is to use the date a user inputs to fetch a photo to display.

We need to write a function that will take in an argument of a date, make a fetch to the url with the date given, and set the photo in the state to the photo data received from the API.

class App extends Component {  ...
 getPhoto = date => {    fetch(`https://api.nasa.gov/planetary/apod?date=${date}&api_key=DEMO_KEY`)      .then(response => response.json())      .then(photoData => this.setState({ photo: photoData }));  };
...
}

When do we we want to invoke this function? After a user inputs a date and clicks submit. We already have a function that handles that — changeDate! We can call getPhoto at the same time that we set the date in state to fetch the corresponding photo.

class App extends Component {
...
changeDate = e => {    e.preventDefault();    let dateFromInput = e.target[0].value;    this.setState({ date: dateFromInput });    this.getPhoto(dateFromInput);  };
}

We can make sure all of this is working by entering a date and clicking submit. The photo changes!

Now, when you enter a date (currently only in the correct format), you should see the title, photo, and description for the Astronomy Picture of the Day!

Awesome! We made a super simple React app!

Next, we’ll greatly improve the user experience by allowing them to select a date on a calendar. Stay tuned for part 2!