React
Posted By Sebastian

Modern React From The Beginning EP13: Fetching Data


Subscribe On YouTube

Episodes

In this episode we’ll connect the React application we’ve implemented in the previous episodes of this series to a back-end. As a back-end a local Strapi project is used which is providing courses data via a REST-based web service.

Setting up the Strapi project is not part of this episode. However, if you’d like to see the steps which are needed to create a new Strapi project from scratch and setup the corresponding data model in Strapi you should take a look at the following free Strapi course on CodingTheSmartWay.com:

Getting Started With Strapi:

Re-implementing The Reducer Function And Combining State

Before actually writing the code which is needed to retrieve Course data from the Strapi back-end we’ll revise the state handling a little bit. So far we’ve been managing the courses state and the isLoading state separately. However, both states are related to each other, so it makes sense to combine those states and managing both in one state object. Therefore we’re going re-implement the coursesReducer reducer function in the following way:

const coursesReducer = (state, action) => {
  switch(action.type) {
    case 'FETCH_COURSES_START':
      return {
        ...state,
        isLoading: true
      };
    case 'FETCH_COURSES_SUCCESS':
      return {
        ...state,
        isLoading: false,
        data: action.payload
      };
    case 'REMOVE_COURSE':
      return {
        ...state,
        data: state.filter(
        course => action.payload.id !== course.id
        )
      };
    default: 
      throw new Error();
  }
};

The SET_COURSES action type has been replaced by two new action types:

  • FETCH_COURSES_START: Is used to indicate that we’re starting data load
  • FETCH_COURSES_SUCCESS: Is used to indicate that data fetching is done and that courses data is now available

For every new state an object is returned. In this object we’re using the spread operator (…) to include everything what’s available in the current state object. Then we’re adding in adding what has changed. E.g. when the action type FETCH_COURSES_START is invoked the isLoading property of the state object is set to true.

When the FETCH_COURSES_SUCCESS action is dispatched the isLoading property is set to false and the data property gets assigned the array of courses which are available via action.payload.

Initializing The New State Object

We need also to make sure that a proper initialization of the state object is done. The right place to do so is the call of the useReducer function in App component:

  const [courses, dispatchCourses] = useReducer(
    coursesReducer,
    {data: [], isLoading: false}
  );

Here the second function parameter can be used to set the initial value of the state object (consisting of the properties data and isLoading.

Fetching Data From Strapi Back-end

Now that we’ve updated the reducer function we’re able to update the code inside the useEffect hook call as well:

  useEffect(() => {
    dispatchCourses({ type: 'FETCH_COURSES_START' });
    fetch(STRAPI_API_ENDPOINT)
      .then(response => response.json())
      .then(result => {
        dispatchCourses({
          type: 'FETCH_COURSES_SUCCESS',
          payload: result
        });
      })
      .catch((e) => console.log("Error fetching courses from back-end ... " + e))
  }, []);

Inside this function we’re first dispatching the FETCH_COURSES_START action type to the reducer. Then we’re using the fetch function to send an HTTP GET request to the corresponding endpoint of the course collection type of the Strapi back-end server.

const STRAPI_API_ENDPOINT = 'http://localhost:1337/courses';

The fetch function returns a promise. When the promise gets resolved we’re converting the result into an JSON object by calling the json method on the response object. Again the return type is a promise which gets resolved when the JSON result is available. With the result object available we’re dispatching the action FETCH_COURSES_SUCCESS to our reducer and we’re passing the JSON-formatted response as the payload into the call of the dispatchCourses function. This enables the reducer to create a new state which is containing the course data which we’ve now retrieved from the back-end.

As the isLoading property is now part of the courses state object we need to change the JSX to access this property (instead of using the separate isLoading state directly):

{courses.isLoading ? (
    <p>Loading Courses ...</p>
) : (
    <CoursesList courses={filteredCourses} handleRemoveCourse={handleRemoveCourse} />
)}

Deleting Code Which Is No Longer Needed

As the course data is now retrieved from the back-end we do no longer need to keep the data as an array in our React application. Therefore you can remove courses_data array in App.js and you can also remove the code which has been added to simulate the asynchronous data retrieval (getCoursesAsync function).

As the isLoading property is now part of the courses state object, we need to remove the separate isLoading state as well from our React application.

Updating CoursesList component

Finally, we need to update the implementation of CoursesList component as the data structure we’re retrieving from Strapi is different compared to the data structure we’ve been using before in one detail: the author property is not containing the full author name as a string. Instead the author property is now containing an array of authors, each consisting of the properties first_name and last_name.

We need to change the JSX code in CourseList component to reflect this change in the data model. Therefore the map method is called to iterate through items of the author array and output first name and last name for every author associated with the course:

import React from 'react';

const CoursesList = ({courses, handleRemoveCourse}) => {
    return courses.map(course => {
      return (
        <div key={course.id}>
          <span>
            <a href={course.url}><h4>{course.title}</h4></a>
          </span>
          <span>by <strong>{course.authors.map(author => author.first_name + " " + author.last_name)}</strong></span>
          <span>| Video Hours: {course.hours_video}</span>
          <span>| Number of Lectures: {course.number_of_lectures}</span>
          <span>| Rating: {course.rating}</span>
          <br/><br/>
          <span>
            <button type="button" onClick={() => handleRemoveCourse(course)}>
              Remove
            </button>
          </span>
          <br/><br/>
        </div>
      );
    });
  }

  export default CoursesList;

If you now start the React application once again via:

$ npm start

You should be able to see the React application outputting a list courses when you access http://localhost:3000 in the browser:

90.png

This time you can only see data which is coming from Strapi and no longer data that is being defined in the inside the React application itself.

Just try it out. Log in into Strapi’s admin panel which should be available at http://localhost:1337/admin and update or create a new course record. Refresh the website and you should see the changes automatically.

Advertisement: Top 3 React Online Courses

If you want to dive deeper and become a React pro also consider taking one of the following great online courses.

React – The Complete Guide (incl Hooks, React Router, Redux)*
Dive in and learn React.js from scratch! Learn Reactjs, Hooks, Redux, React Routing, Animations, Next.js and way more!

Go To Course*

Modern React with Redux*
Master React v16.6.3 and Redux with React Router, Webpack, and Create-React-App. Includes Hooks!

Go To Course*

The Complete React Developer Course (w/ Hooks and Redux)*
Learn how to build and launch React web applications using React, Redux, Webpack, React-Router, and more!

Go To Course*

* Affiliate Link / Advertisement: This blog post contains affiliate links, which means that if you click on one of the product links and buy a product, we’ll receive a small commission. There are no additional costs for you. This helps support the channel and allows us to continue to make videos like this. Thank you for the support!


Using and writing about best practices and latest technologies in web design & development is my passion.