DEV Community

Cover image for NASA Photo of the Day 2
Cesare Ferrari
Cesare Ferrari

Posted on

NASA Photo of the Day 2

Building an app that connects to a remote API to show Redux middleware

In the previous article we have seen how to set up a basic application that fetches the NASA photo of the day.

Our application has a button that when clicked fires out an action that connects to the NASA API and asynchronously fetches some data, including an image. We then display this image in our view.

Application states

We can think of our application having multiple states.
The initial state is just a blank page.
When we click the Fetch button, we enter into the LOADING state.

In the LOADING state we have initiated the API call and we are waiting to see if we get data back from the remote server.
In our example, we are going to show a loading animation while in this state, so the user has some visual feedback that something is happening.

Once our API called is resolved, we pass from the LOADING state to either a SUCCESS state or a FAILURE state, depending if our call was successful or not.

If the call is successful, we transition into a SUCCESS state and display the data received to the screen.
If the call is unsuccessful, we transition into a FAILURE state and we display an error message.

From this description, we gather that the action creator handling this button click needs to be able to dispatch three different actions to the reducer: FETCH_PHOTO_START, FETCH_PHOTO_SUCCESS, FETCH_PHOTO_FAILURE.

We call our action creator getPhoto and we define it in a new index.js file inside src/actions/

mkdir actions
touch actions/index.js

Let's start small by just handling FETCH_PHOTO_START.

Remember, an action creator is a function that returns an object with a mandatory type property and an optional payload property.
The type we want to return is FETCH_PHOTO_START
Here's our action so far:

// src/actions/index.js

export const FETCH_PHOTO_START = 'FETCH_PHOTO_START';

export const getPhoto = () => {
  return {
    type: FETCH_PHOTO_START
  }
}

We need to make our application aware that we are in the LOADING state, so we add a new property to our state called isLoading, initially set to false. We will switch it to true when the transition to the LOADING state starts.

In our reducer, we add the new property to the initial state:

// src/reducers/index.js

const initialState = {
  // ... existing code ...
  isLoading: false
}

We also add a switch statement to the reducer so we can return a new version of the state with the isLoading property set to true when FETCH_PHOTO_START is received:

// src/reducers/index.js

const reducer = (state = initialState, action) => {

  switch (action.type) {
    case FETCH_PHOTO_START: {
      return {
        ...state,
        isLoading: true
      }
    }

    default: return state;
  }
}

Since we are using a new state property, we need to add it to our mapStateToProps function in the NASAPhoto component:

// src/components/NASAPhoto.js

const mapStateToProps = state => {
  return {
    // ... existing code ...
    isLoading: state.isLoading
  }
}

We said we are going to show a loading spinner so we add a dependency called react-loader-spinner:

npm install react-loader-spinner

Once it's installed, we can use it in our component by importing it and configuring it through props.
Note that we show the spinner only when isLoading is true, so we check for that condition and if it's true we add the spinner component:

// src/components/NASAPhoto.js

import Loader from 'react-loader-spinner';

const NASAPhoto = props => {
  return (
    <>

 // ... existing code ...

      { props.isLoading && (
        <Loader type="BallTriangle" height={90} width={60} color="#00BFFF" />
      )}

    </>
  )
}

Note: height and width in the Loader need to be numbers, it will give an error if we type height="90" because that's a string, so we need to interpolate the number inside braces as the prop value.

At this point, everything should be ready to load a spinner when our application goes into a LOADING state and isLoading is true.

But how do we trigger this change of state?
We will trigger the state change when we click the Fetch button so we need to add an onClick event listener and create a function that fires the FETCH_PHOTO_START action when the event is detected.

We'll do this in the next article.


I write daily about web development. If you like this article, feel free to share it with your friends and colleagues.

You can receive articles like this in your inbox by subscribing to my newsletter.

Top comments (0)