How to Use React to Display NASA’s Astronomy Picture of the Day— Part 2

Goal: Allow the user to select a date from a calendar to view the corresponding photo

Jennifer Snyder
7 min readSep 27, 2018

In Part 1 of building a simple React app to display NASA’s Astronomy Picture of the Day, we were able to make a fetch to the NASA APOD API to display the photo for a date entered by a user. We had three components: an App that rendered both a DateInput that asks the user to input a date and a Photo component that displays the photo. In the state of our App, we kept the date and the photo so we could get and receive the necessary information from the children components. In the version we built in Part 1, we required a user to enter the date in the exact format required by the API. Not ideal.

In working to improve this user experience, my second iteration had a form with dropdown menus for users to select a month, day, and year, which would then be properly formatted into a string when the form was submitted. I got it to work, but after testing out the app, I realized that entering dates this way was kind of a pain. So I found a better way!

Understanding React DatePicker

I came across the React Date Picker package that provides a “simple and reusable DatePicker component for React.”

To use the DatePicker, we first need to install the package.

npm install react-datepicker --save

Datepicker requires Moment.js and PropTypes, so I installed them as well.

npm install moment --save

npm install prop-types --save

DatePicker is relatively easy to use. It is a React component that can display a selected date and respond to a change in the date with a function. As shown in its documentation, the simplest form of a DatePicker is:

<DatePicker
selected={this.state.date}
onChange={this.handleChange}
/>

This format is of course assuming that the date is stored in the state of the component that renders the DatePicker and that the component has a function to handle the change. Depending on the structure of your app, these elements may come from somewhere else, like the component’s props.

Adding React DatePicker

In our Astronomy Picture of the Day app, we will be rendering the DatePicker in the DateInput component. The date is stored in the state in the App component, which is the parent of DateInput. This means that our DatePicker’s selected date and function to handle the change in the date will come from its props, passed down from App.

In Part 1, we already set up our App to render the DateInput component and pass down a changeDate function. Now, we’ll also need to pass down the date from App's state to display in the DatePicker.

//App.js
import React, { Component } from "react";
import DateInput from "./components/DateInput";
import Photo from "./components/Photo.js";
class App extends Component {
state = {
date: "",
photo: ""
};
changeDate = e => {
e.preventDefault();
dateFromInput= e.target[0].value
this.setState({ date: dateFromInput });
};
render() {
return (
<div>
<h1>NASA's Astronomy Picture of the Day</h1>
<DateInput
changeDate={this.changeDate}
date={this.state.date}
/>
<PhotoContainer date={this.state.date} />
</div>
);
}
}
export default App;

We can use our React Developer Tools to verify that the date is now being passed down to DateInput along the with changeDate function.

We will need to make some changes to our changeDate function later to handle the new input, but first we need to get an idea of what input we’ll get from this DatePicker component.

In the DateInput component, we can now render the DatePicker component and set its selected date to the date that was passed down to DateInput. The DateInput component also receives a function from its parent to handle the change in the date — changeDate. We can set this to be called onChange of the DatePicker. In this component, I also had to require the CSS file from the DatePicker package:

//DateInput.js
import React from "react";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
const DateInput = props => (
<div>
Select a Date:
<DatePicker
selected={props.date}
onChange={props.changeDate}

/>
</div>

);
export default DateInput;

Check out our page now:

Cool! We can now select a date on a calendar!

But wait! You might have noticed some scary-looking warnings pop up:

What’s going on?! It looks like our date is currently a string, but the DatePicker was expecting an object.

Using Moment.js

This is the tricky part about DatePicker — it uses Moment.js, which creates a wrapper for the JavaScript Date object. Let’s walk through how we’ll update the date in our app to use Moment.js.

In our app, we want to automatically load the photo for today when the page loads. To do this, we’ll set the date in App’s state to the current date. To get the current date using Moment.js, you can call moment() without any parameters. Remember to import moment or you’ll see an error telling you that ‘moment’ is not defined.

import React, { Component } from "react";
import moment from "moment";
import DateInput from "./components/DateInput";
import Photo from "./components/Photo.js";
class App extends Component {
state = {
date: moment(),
photo: ""
};

If we look at our app now, we can see that the date is filled in with today’s date! Pretty cool.

What happens if we try to change the date?

Well, that’s not great. But we can see that the error occurred in the changeDate function in App. So at least we know that the correct function is being called when we change the date.

According to the DatePicker documentation, the function that handles the change is passed the date as a Moment object. That means that we can store this date in state in App and get the photo using this date object.

class App extends Component {

...
changeDate = dateFromInput => {
this.setState({ date: dateFromInput });
this.getPhoto(dateFromInput);
};
...}

Now what happens when we change the date?

Where’s the photo? If we check our React dev tools, we can see that the date has been updated to a Moment object, but our photo is not there. Instead, we have an error message telling us that our date is not formatted correctly.

Formatting the Date

One more step to get our DatePicker working correctly. We need to format our Moment object into the date format the API needs : “YYYY-MM-DD”. How can we do this?

Moment objects have built-in functions that can help us get the pieces of the date that we need. Let’s take this one step at a time using the current date.

let today = moment()

We can easily get the year:

today.get('year')
//2018

The month is a little trickier.

today.get('month')
//8

Hmm. It’s September, so we would expect to get 9. Unfortunately, Moment numbers the months starting at 0, so we’ll have to remember to add 1 to get the number we need.

Finally, we can get the date:

now.get('date')
//26

Now we can write a function in App using these methods to format the moment into the string we need to make a fetch to the API: YYYY-MM-DD. After testing, I realized that the API also accepts months and days with only one digit, so we don’t need to worry about adding a 0 to single-digit numbers.

class App extends Component {
...
formatDate = moment => {
let year = moment.year();
let month = moment.month() + 1;
let day = moment.date();
return `${year}-${month}-${day}`;
}
...
}

Finally, we need to format the dateFromInput before we pass it to the getPhoto function.

class App extends Component {...  changeDate = dateFromInput => {
this.setState({ date: dateFromInput });
this.getPhoto(this.formatDate(dateFromInput));
};
...}

Cool! It works!

A user can now easily select a date from a calendar, and our app will render the appropriate Astronomy Picture of the Day! Awesome!

But I still think we have some room for improvement. How about making a button that will return a random photo and show the date it’s from? That would be neat! Check out how to implement this feature in Part 3!

--

--

Jennifer Snyder

Software Engineer at Vistaprint // Former Science Teacher // Graduate of Flatiron School DC https://github.com/jensnyder