as

Settings
Sign out
Notifications
Alexa
Amazon Appstore
AWS
Documentation
Support
Contact Us
My Cases
Get Started
Design and Develop
Publish
Reference
Support

Fetch the Video List

Now that we have a Landing Screen that can pass data to a VideoCard component, the next step is to call an API to retrieve video data that the Landing Screen can use.

We will be using React hooks in order to manage data and state of our application (useState) and direct the app to retrieve data upon load (useEffect). Hooks are essentially reusable logic that can be used in your code. We won't be explaining hooks in detail in this guide, but recommend you read more about them (here)https://reactjs.org/docs/hooks-intro.html.

Define the Data

Before we retrieve video data, we need to define what the data will look like in TypeScript.

  • Open LandingScreen.tsx.
  • After the import statements, create an interface called IVideo with the following definition.
interface IVideo {
  id: string;
  title: string;
  description: string;
  duration: number;
  thumbURL: string;
  imgURL: string;
  videoURL: string;
  categories: string[];
  channel_id: number;
}

Store the Data

Now we need a place to store the video data and a way of updating it that will cause the UI to re-render any component that uses it ("reacting" to events). The useState hook does both of these things for us. It returns a variable and a function to update the variable. Anytime the variable is updated using the function, it will cause the UI components that use that variable to re-render (they are "reacting" to events).

  • In LandingScreen.tsx update the import statement for 'react' to include useState. Since useState is a named export, you'll need to include it in curly braces. You'll also need to change the syntax of the statement to avoid errors.
import React, {useState} from 'react';
  • At the top of the LandingScreen arrow function, add the following statement:
const [videos, setVideos] = useState<IVideo[]>();

The updated LandingScreen.tsx code should look like this:

Copied to clipboard.

import React, {useState} from 'react';
import Header from '../components/Header';
import VideoCard from '../components/VideoCard';

interface IVideo {
  id: string;
  title: string;
  description: string;
  duration: number;
  thumbURL: string;
  imgURL: string;
  videoURL: string;
  categories: string[];
  channel_id: number;
}

const LandingScreen = () => {
  const [videos, setVideos] = useState<IVideo[]>();

  return (
    <>
      <Header />
      <VideoCard
        title="My Video"
        description="My Video Description"
        imgURL="https://le1.cdn01.net/videos/0000169/0169322/thumbs/0169322__002f.jpg"
      />
    </>
  );
};

export default LandingScreen;

Retrieve the Data

Next we need to create a function that will execute our API call. The function will use the Fetch API to call our API endpoint (axios, another API used for calling other APIs, will be supported in the future). We'll use the setVideo function to set the array of videos we get back from fetch. Because fetch returns a Promise object, we need to handle the code in an asynchronous manner using .then.

Copied to clipboard.

const url = "https://d2ob7xfxpe6plv.cloudfront.net/TestData.json";
  • Create an arrow function called getAllVideos() in the body of the LandingScreen (i.e. in the LandingScreen arrow function).
  • Call fetch and pass in the url.
  • Add .then to wait for the response, then convert it to json.
const getAllVideos = () => {
  fetch(url).then(response => response.json());
};
  • Add another .then statement to set the value of videos to be the appropriate part of the response object.
const getAllVideos = () => {
  fetch(url)
    .then(response => response.json())
    .then(data => setVideos(data.testData));
};
  • Add .catch to any error messages and print them using console.log.

Your getAllVideos() function should look like this:

Copied to clipboard.

const getAllVideos = () => {
  fetch(url)
    .then(response => response.json())
    .then(data => setVideos(data.testData))
    .catch(error => {
      console.log(error);
    });
};

(This is common JavaScript and ES6 syntax that uses Promises to retrieve data from an API. The main thing to note is that we're taking data from the API response and calling setVideos.)

Test Data Retrieval

Now that we have a function that can return and update the list of videos, let's test it out.

  • Add a call to getAllVideos() anywhere after its definition.
  • Add console.log statements to log videos before and after the call to getAllVideos().
console.log(videos);
getAllVideos();
console.log(videos);
  • Reload the application. You'll notice that while the simulator displays correctly, the Metro terminal shows an endless loop of log statements. Log information can be found in different locations depending on how you are running your app:

  • If using VSCode, check the React Native output panel

  • If using CLI, look in the Metro terminal

This occurs because every time the videos variable changes, the LandingScreen is re-rendered. On each re-render, we are retrieving videos again, which causes this endless loop.

console.log(videos); // videos is undefined.
getAllVideos(); // This causes endless re-rendering.
console.log(videos); // This shows us that we are endlessly re-rendering

Add useEffect Hook

To prevent this from happening, we need to put our call to getAllVideos in a useEffect hook. This hook gives us the ability to only re-render if videos has changed between renderings.

  • Update the import statement for 'react' to include useEffect. This is a named export, so will go next to useState in the curly braces.
import React, {useState, useEffect} from 'react';
  • Wrap the call to getAllVideos() with the useEffect hook. This hook takes in an arrow function, where you will call getAllVideos().
console.log(videos);

useEffect(() => {
  getAllVideos();
}, []);

console.log(videos);

Note the second parameter is []. This parameter tells useEffect to only render once. Since we only need to retrieve the videos once, it works for our purposes. For more advanced ways of using the useEffect hook, see the React Native documentation.

  • Reload the app, and you'll see that the Metro terminal window no longer has an endless loop.
  • Remove the console.log() statements now that we have resolved the endless loop.

Create Video Categories

Finally instead of storing all the videos, let's filter the videos into specific categories to display them grouped by category in our UI.

  • Modify the state variable to hold our categorized videos instead:
const [islandVideos, setIslandVideos] = useState<IVideo[]>([]);
const [underwaterVideos, setUnderwaterVideos] = useState<IVideo[]>([]);
  • Modify the getAllVideos function to filter the videos by category after receiving them from the API using JavaScript's filter() method :
const getAllVideos = () => {
  fetch(url)
    .then((response) => response.json())
    .then((data) => {

      const islands = data.testData.filter(
        (video: IVideo) =>
          video.categories && video.categories.includes('Costa Rica Islands'),
      );
      
      const underwater = data.testData.filter(
        (video: IVideo) =>
          video.categories &&
          video.categories.includes('Costa Rica Underwater'),
      );
      
      setIslandVideos(islands);
      setUnderwaterVideos(underwater);
    })
    .catch((error) => {
      console.log(error);
    });
};

Now we have two separate arrays of videos, islandVideos and underwaterVideos, which we can use to display different categories of videos in the UI.

The updated LandingScreen.tsx should now look like this:

Copied to clipboard.

import React, {useState, useEffect} from 'react';
import Header from '../components/Header';
import VideoCard from '../components/VideoCard';

interface IVideo {
  id: string;
  title: string;
  description: string;
  duration: number;
  thumbURL: string;
  imgURL: string;
  videoURL: string;
  categories: Array<string>;
  channel_id: number;
}

const LandingScreen = () => {
  const [islandVideos, setIslandVideos] = useState<IVideo[]>([]);
  const [underwaterVideos, setUnderwaterVideos] = useState<IVideo[]>([]);

  const url = 'https://d2ob7xfxpe6plv.cloudfront.net/TestData.json';

  const getAllVideos = () => {
    fetch(url)
      .then((response) => response.json())
      .then((data) => {
        const islands = data.testData.filter(
          (video: IVideo) =>
            video.categories && video.categories.includes('Costa Rica Islands'),
        );
        const underwater = data.testData.filter(
          (video: IVideo) =>
            video.categories &&
            video.categories.includes('Costa Rica Underwater'),
        );
        setIslandVideos(islands);
        setUnderwaterVideos(underwater);
      })
      .catch((error) => {
        console.log(error);
      });
  };

  useEffect(() => {
    getAllVideos();
  }, []);

  return (
    <>
      <Header />
      <VideoCard
        title="My Video"
        description="My Video Description"
        imgURL="https://le1.cdn01.net/videos/0000169/0169322/thumbs/0169322__002f.jpg"
      />
    </>
  );
};

export default LandingScreen;