How to Save Files to a React Server With Thunks
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.
Lesson Transcript
[00:00 - 00:05] Save the project using thunks. At this point we can save our drawings as PNG files.
[00:06 - 00:12] In this section we'll make it possible to save the project to the server. It will be possible to load them later and continue drawing them.
[00:13 - 00:19] We will learn how to perform side effects in Redux based applications using th unks. First let's define the API module.
[00:20 - 00:39] As we're going to perform a server request, let's define an API module, create a new file, SRC modules, strokes, API, TS, and define the new project function there. We'll need the stroke type, import stroke from utils, types.
[00:40 - 00:50] Then we export const new project. That is a function that receives name, string, strokes, stroke array, and image , also a string.
[00:51 - 01:04] Inside of this function we're going to call fetch method, we'll fetch HTTP, localhost, 4000, that's the address of our server. It's a good idea to define it in the .env, but here we will just hard code it.
[01:05 - 01:09] Project, new. It's going to be a post request so we need to pass a bunch of options.
[01:10 - 01:28] First of all specify the method, it's going to be post, headers, we need to specify the accept header, that is application JSON, and the content type, also application JSON. We set both headers because we will communicate and JSON will receive JSON and send JSON.
[01:29 - 01:47] So we send the body, it's going to be JSON, stringify, name, strokes, and image , format the document. Don't forget to return fetch, and after the fetch method is performed, we can do then and parse the response as JSON.
[01:48 - 02:02] This function will perform a post request to our server and send the strokes list representing our project, project name and project thumbnail. The fact that we send the whole stroke array to the back end will allow us to use undo and redo functionality immediately after we load the project.
[02:03 - 02:11] Now let's handle saving the project. Saving the project is considered a side effect, and the official way to handle side effects in Redux toolkit are thunks.
[02:12 - 02:27] Think of them as special kind of action creators instead of returning an object with type and payload, they return an async function that will perform the side effect. Open SRC, store TS, and here export new type up thunk.
[02:28 - 02:38] It's going to be a thunk action. Thunk action is a generic type, where we'll pass void, root, state, unknown, and action of type string.
[02:39 - 02:45] In front of the root state, thunk action, and action. Now we can define the safe project thunk.
[02:46 - 02:56] Go to SRC strokes, slice TS, and define safe project thunk. First let's define a type, safe project arg.
[02:57 - 03:05] That's going to be the argument type for our thunk. It's going to contain project name of type string and thumbnail of type string.
[03:06 - 03:12] We're going to store the thunk nails as base 64 images. In other words, we'll store images as strings.
[03:13 - 03:19] Expert const safe project. Here we define our thunk, create a sync thunk.
[03:20 - 03:29] The type of this thunk is safe project, and then we need to pass on a sync callback. A sync first will get the project name and thumbnail.
[03:30 - 03:38] The first argument is going to be safe project arg. And then we'll receive the get state from the default thunk arguments.
[03:39 - 03:58] Now inside of the thunk, we try to get the response using the await new project that we defined in the API. We need to pass in the project name, the state get state as root state, and then we get strokes from it.
[03:59 - 04:05] And also the thumbnail. Let's add a catch block. If we catch an error, we'll log it.
[04:06 - 04:09] Console log e, or even error. All right, we have our safe project thunk.
[04:10 - 04:20] We defined it as a function that receives project name, thumbnail, and regular thunk arguments. For example, you have access to get state.
[04:21 - 04:30] We could also use dispatch method. We just don't need it here and some others. You can check the type of the arguments that you're getting by hovering it, and you will see that it's getthunk API.
[04:31 - 04:47] The thunk will make the post request using new project function from the API, and send the project name, strokes from the state, and the thumbnail to it. Now we need a function that would allow us to create a base64 thumbnail from the project that we're drawing.
[04:48 - 04:57] Inside of the utils folder, create a new file, call it scalar.ts. You can copy the contents of this file from the project attached to this lesson .
[04:58 - 05:05] What it will do is it will accept the file blob and the scale ratio. Here we use 0.1 by default.
[05:06 - 05:24] The types of the arguments are defined in the scalar orgs type. Then we create a file reader that will actually load the file, and after it's done, it will create an invisible canvas element and render this image, scaling it down, or up.
[05:25 - 05:35] If drawing image was successful, then we convert it into data URL, which is going to be the base64 representation of our image. So we'll get a string as a result.
[05:36 - 05:47] Then we return a promise, and we resolve it to this data URL. If there will be an error somewhere, we will reject the promise with this error message.
[05:48 - 05:55] Alright, now let's update the project save model to actually be able to save the files. First we'll need to get the canvas ref.
[05:56 - 06:11] const canvas ref equals use canvas. Let's import it from the canvas context. And then inside of the window body block, we'll add a field row stacked div with an input for the project name.
[06:12 - 06:24] Let's define the on project name change handler. const on project name change is going to receive change event from the html input element.
[06:25 - 06:40] And then update the project name state. Name equals use state with an empty string as a default value.
[06:41 - 06:50] So inside of this function, we're going to call set project name event target value. Alright, now we have the project name, and we have the canvas ref.
[06:51 - 06:57] Now we need to define the save button. Above the cancel button, create another button with text save.
[06:58 - 07:04] It will call the on project save function. Let's define it.
[07:05 - 07:21] const on project save is an async function. We will get the file, file await get canvas image from canvas ref current. After we have the file, we need to actually check if we have it.
[07:22 - 07:36] If we don't, then we return and do nothing. Otherwise, we generate the thumbnail equals await get base 64 thumbnail from the file and scale 0.1.
[07:37 - 07:42] Then we dispatch save project. We pass in the project name and thumbnail.
[07:43 - 07:50] We reset the project name and hide the model. Alright, let's try to open our app and save the image to the backend.
[07:51 - 08:04] Let's try to draw something, press save, select the project name, test, save. And if you open the network tab, you should see that the request to the project 's new was performed successfully.
This lesson preview is part of the Fullstack React with TypeScript Masterclass course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to Fullstack React with TypeScript Masterclass, plus 70+ \newline books, guides and courses with the \newline Pro subscription.
![Thumbnail for the \newline course Fullstack React with TypeScript Masterclass](/_next/image?url=https%3A%2F%2Fs3.amazonaws.com%2Fassets.fullstack.io%2Fn%2F20220425171607321_CoverImage_FSReactWTypeScript_Masterclas.png&w=3840&q=75)