An Intro to Building React APIs and Higher Order Components
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
This lesson preview is part of the Fullstack React with TypeScript Masterclass course and can be unlocked immediately with a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to Fullstack React with TypeScript Masterclass with a single-time purchase.

[00:00 - 02:52] Logging the data. In this lesson we'll define the API function to load the data from the server and we'll create a higher order component that will allow us to load the data from the backend when we launch our application. Define the load function. Open SRC, API.ts and define a new function called load. Expert const load equals a function that will return fetch. Here we use a template string. The first part of the URL is going to be processed and react app backend endpoint /load. After we got the data we call then and here we work with the response object. Response, we want to check if response.org, then we return response. Jason, we need to cast it to a promise with AppState as promise AppState. We do it because unfortunately Jason is not a generic function so we cannot specify that the return value is going to be upstate. Even though we know that that's going to be the format that we'll get from the server. Otherwise if the response is not okay or not 200 else we throw an error that will say error while loading the state. Okay now we have two API functions, the save that performs the post request and sends the data to the backend and load function that performs the get request and we don't need to specify this in the fetch settings because the get is the default request method. How to load the data? In our application the only time we want to load the data is when we first render it. We have a provider component that is mounted once we render our application. The problem is that we can't load the data directly inside of it because then our application will first initialize with the default data and then we would get the data from the backend but our reducer would already be initialized so we need to get the data before we initialize the reducer so that the initial data will be from the backend. The solution is to have a wrapper component that will load the data for us and then pass the data through the props to the provider so it initializes with the correct data. We could create another component and then just render our upstate provider inside of it but I propose to create a more generic solution using the hook pattern. What is hook? Hook or higher order component is a react pattern in which you create a factory function that accepts a wrapped component as an argument, wraps it into another component that implements the desired behavior and then returns this construction. We will talk about hooks and other react patterns in the next chapters. For now let's practice creating one.
[02:53 - 03:54] Creating your first hook. Our hook will accept upstate provider and inject the initial state prop containing loaded data into it. This kind of hooks is called an injector hook. Create a new file, SRC with initial state dot TSX and make the necessary inverts. We'll need the use state and use effect hooks, the upstate type and the load function from the API module. Then define an expert with initial state hook. First let's define the injected props. It's going to be the type injected props that as you remember should hold the initial state initial state of type up state. Now we need to define the props without the injected. That's going to be a complex type. We'll use it to exclude the injected prop initial state from the props that will pass to the wrapper. Type props without injected.
[03:55 - 04:38] It's going to be a generic type. T base props is going to be the type variable here. And we're going to use the utility type omit where we will omit all the fields from the T base props. That are keys of injected props. So what we want to achieve is we want to get the component that we're going to wrap with this hook and it will have the initial state prop inside of it. Then we want to wrap it into our hook and the resulting component should not have this initial state prop defined in the prop types. This is why we have this utility type that will just exclude the initial state prop from the list of all the props that our wrapped component will accept.
[04:39 - 06:04] Hopefully it's going to get more clear when we implement the component. Now let 's export the function with initial state. That's going to be our factory function that is going to create our higher order component. Expert function with initial state is going to receive type T props. Again, it's going to be a generic function. It's going to wrap the wrapped component of type react component type. And component type is generic. So we pass in the type of the props is going to be a props without injected. And as you remember, props without injected removes the initial state from the props. And here we pass the T props to remove the initial state from this type variable. And then we add the injected props again. All right, we're done defining the props. We need to add the triangle bracket here. And now to the function body. Here we return a new component that receives props. And here we make sure to pass the props without injected of type T props . So the wrapper component will not have the initial state prop. And then inside of this component, we define the state const initial state set initial state equals use state of type up state.
[06:05 - 06:40] The default value is going to be an object with fields lists, empty array, and dragged item. Now, all right. And then we return the wrapped component. We pass in all the props, plus the initial state initial state. All right, we have the base for our with initial state hook, it contains the state that it will inject into our wrapped component. And what we have to do is to load the data from the back end.
[06:41 - 07:45] Load the data inside of the hook, define another state const is loading, set is loading, it's going to be use state with default value true. So we start with the is loading state. Then we'll need another state for the error, error set error, use state of type error, or undefined. And now we define the use effect, it will actually perform the fetch, or it will call the load method that will perform the fetch from the back end. Pass an empty array as the dependency list, because we only wanted to run once const fetch initial state equals async. Here is going to be a function that is going to try to get the data const data equals await load. We call set initial state with this data. And if something goes wrong, catch error, we need to check if e is instance of error.
[07:46 - 08:06] And we do this because we cannot specify the type of an error here. It's just forbidden, because in JavaScript, and as you know, type script is a super set of JavaScript. So it must support everything that JavaScript contains. So in JavaScript, errors can be literally anything. You can pass a string to it, you can pass an error object, you can pass a regular object.
[08:07 - 08:41] It allows you it's quite permissive. So in order to check that it's actually an error object, we need to use the instance of method. So if it's an error object, then we set error e. And regardless if we could load the data, or there was some error, we set loading is loading to false. And we call fetch initial state. All right, so our use effect is going to be triggered once we mount our component. And then we might have one of three different states.
[08:42 - 09:19] So first one is pending, we have the state when we've started loading, but not finished yet. So the ease loading state is going to be true. Then we have success is when we loaded the data successfully and stored it inside of the initial state, is loading is false and error is null, or undefined. And then we have the failure state when we got an error and stored it in the error state, and ease loading is also false. Now let's process those states. First of all, let's process the ease loading if is loading, then we return a div. That says loading.
[09:20 - 10:07] If error, then we return a div. That will show error message. And if everything is fine, is loading is false and there is no error, we will show the wrapped component with the initial state. Now let's use the HOC. Go to upstate context, import with initial state from the with initial state module, define the upstate provider props type up state provider props equals an object with filled children of type react react node and initial state of type up state.
[10:08 - 11:05] Now wrap the upstate provider into the HOC. So we remove this FC type. Here we call with initial state, we pass in the upstate provider props, we take the children and the initial state here that the HOC will load for us. Don't forget one more bracket. And then instead of the update, use the initial state. You can remove the update as we are not using it anymore . And also we don't need the FC type. Launch the up. Now the app should preserve the state on the back end. Let's run yarn start. Try adding the data, add the list, some list, some other list, maybe some cards. And then reload the page and it should load the state from the back end now.
[11:06 - 11:09] Congratulations, you've just completed your first react type script application .