1 00:00:02,090 --> 00:00:05,970 To avoid that the image eventually gets removed, 2 00:00:06,140 --> 00:00:11,180 we need to store it in a more permanent path on our local device filesystem. 3 00:00:11,180 --> 00:00:15,350 Of course, we can also upload it to a server but we already talked about service and so on, 4 00:00:15,410 --> 00:00:21,970 here I want to focus on all the native device capabilities. Now to work with our native filesystem, 5 00:00:22,100 --> 00:00:23,660 expo has got us covered, 6 00:00:23,690 --> 00:00:26,180 we can use the filesystem package here 7 00:00:26,270 --> 00:00:32,900 to do that. You install it just like you install the other native packages, with expo install 8 00:00:32,900 --> 00:00:34,320 expo-file-system, 9 00:00:34,320 --> 00:00:41,030 so let's do that here, expo install, again just a wrapper around npm install which you could alternatively 10 00:00:41,030 --> 00:00:41,470 use, you 11 00:00:41,510 --> 00:00:48,950 just need to make sure you're using the right version for your expo SDK version you're using and with 12 00:00:48,950 --> 00:00:52,980 that, we have that installed, 13 00:00:53,010 --> 00:00:56,000 now we can move the image after we took it. 14 00:00:56,010 --> 00:00:59,080 Now there are various places in the app where we could do that, 15 00:00:59,160 --> 00:01:04,080 we could do it in the image picker right after we took the image but at this point of time, we don't 16 00:01:04,080 --> 00:01:09,720 know yet if we will actually submit the form, if we actually keep that image. 17 00:01:09,720 --> 00:01:15,330 So what if we just took an image here but then we discard this and we go back? 18 00:01:15,330 --> 00:01:20,460 I don't want to have the image moved to a permanent place in that case, it should definitely be cleaned 19 00:01:20,460 --> 00:01:24,300 up and that's the default behavior, so I don't want to move it 20 00:01:24,300 --> 00:01:25,390 at this point yet, 21 00:01:25,740 --> 00:01:28,330 instead I want to move it once we submitted the form. 22 00:01:28,560 --> 00:01:32,610 Hence we could do it here in the new place screen, in the save place handler 23 00:01:32,610 --> 00:01:38,280 but then we would add all this filesystem logic to this component which is possible but which adds a 24 00:01:38,280 --> 00:01:41,190 lot of logic into this component which I don't really want to have there, 25 00:01:41,190 --> 00:01:43,930 I want to keep this component relatively lean. 26 00:01:44,280 --> 00:01:47,640 A great place for this however is the action creator. 27 00:01:47,730 --> 00:01:53,220 We already used this in the past for having side effects, like sending HTTP requests. 28 00:01:53,220 --> 00:01:58,680 Now moving a file is basically the same category of thing we're doing, instead of sending a request to 29 00:01:58,680 --> 00:01:59,180 a server, 30 00:01:59,190 --> 00:02:00,200 we're moving a file, 31 00:02:00,200 --> 00:02:01,620 well it's not that different. 32 00:02:03,390 --> 00:02:12,210 So therefore in this file here, in the places-action.js file, I'll import everything as filesystem 33 00:02:12,210 --> 00:02:19,500 from expo filesystem, so from this new package we installed and here in add place, I'll now use this alternative 34 00:02:19,500 --> 00:02:26,970 syntax of dispatching or of having an action creator which utilizes Redux Thunk, where we return an internal 35 00:02:26,970 --> 00:02:34,230 function here that receives the dispatch function as an argument so that in this internal function, we 36 00:02:34,230 --> 00:02:44,970 can dispatch this action by calling dispatch here and passing our action object and I will add async 37 00:02:44,970 --> 00:02:50,670 here so that we can use async await because we're going to do some asynchronous work here. In here, 38 00:02:50,670 --> 00:02:53,030 I now want to move the file, right? 39 00:02:53,220 --> 00:02:58,980 So for that, I want to use this filesystem package. Now moving the file actually involves a couple of 40 00:02:58,980 --> 00:03:00,060 things. 41 00:03:00,060 --> 00:03:05,160 First of all, we need to derive the new path of the file and that should of course be a more permanent 42 00:03:05,160 --> 00:03:12,270 directory. For that, we can use filesystem and there, you've got a couple of directories you can access. 43 00:03:12,270 --> 00:03:16,980 You got the cache directory which is actually the directory where the file is already stored in out 44 00:03:16,980 --> 00:03:25,200 of the box, the bundle directory which is not really a good directory for storing files your app uses 45 00:03:25,200 --> 00:03:28,080 either but you also got the document directory, 46 00:03:28,080 --> 00:03:34,140 this is the main directory for any files that your app needs which are guaranteed to survive. 47 00:03:34,140 --> 00:03:38,000 Now when you uninstall your app, this folder will also be erased, 48 00:03:38,010 --> 00:03:45,540 so then these files are lost but until then, they will persist across app restarts, across long pauses 49 00:03:45,540 --> 00:03:47,070 where people haven't used your app, 50 00:03:47,400 --> 00:03:49,470 so here the files will survive. 51 00:03:50,220 --> 00:03:55,620 So the filesystem document directory is the path I want to move my file to and now there's one important 52 00:03:55,620 --> 00:04:01,570 thing to know, your path also needs to include the file name you want to use in the future. 53 00:04:01,710 --> 00:04:07,410 Of course, you also get a temporary file name when you take the image but when you move a file, this name 54 00:04:07,410 --> 00:04:14,570 is actually not kept out of the box, instead it will assume this path here as a name so to say. So therefore 55 00:04:14,570 --> 00:04:18,050 this should not just be a pointer at the folder you want to move the file to, 56 00:04:18,150 --> 00:04:20,990 it should instead also include the file name. 57 00:04:21,060 --> 00:04:24,530 Now for that, I'm happy with keeping the autogenerated image name, 58 00:04:24,540 --> 00:04:31,220 of course you could also now generate your own unique image names here but for that, I'll derive the file name 59 00:04:31,290 --> 00:04:33,560 from the image which I got here, 60 00:04:33,570 --> 00:04:38,120 keep in mind that image here is a path, the temporary path to the image. 61 00:04:38,160 --> 00:04:44,880 So here, I'll actually use image which is a string and call split on this to split it by slashes because 62 00:04:44,880 --> 00:04:52,440 this path of course involves a couple of slashes in the end and split converts this string into an array 63 00:04:52,440 --> 00:04:58,620 of string segments where each segment is a segment before and after such a slash in the string 64 00:04:59,040 --> 00:05:00,420 and there by calling pop, 65 00:05:00,420 --> 00:05:01,850 I get the last segment. 66 00:05:01,860 --> 00:05:09,090 So what this code here does is it takes a look at our image path, splits it by slashes which kind of 67 00:05:09,300 --> 00:05:13,140 makes up our full path there and by popping the last element, 68 00:05:13,140 --> 00:05:15,830 well what is the last element? That is our file name, 69 00:05:15,870 --> 00:05:26,060 right, so if you have a path like somefolder/myimage.jpg, then what we do with 70 00:05:26,060 --> 00:05:34,880 split is we get an array with some folder and with myimage.jpg and by calling pop on this, 71 00:05:35,180 --> 00:05:36,920 we get myimage.jpg, 72 00:05:36,950 --> 00:05:39,250 so that's what we get here. 73 00:05:40,590 --> 00:05:42,630 So this will return us our file name, 74 00:05:42,630 --> 00:05:49,300 this code snippet here and now we can append this here to our path by simply adding it like this. 75 00:05:49,320 --> 00:05:53,730 So now this generates a path which both includes a folder and then the file name. 76 00:05:53,730 --> 00:06:00,900 This is where I want to move that file to and now we can move it by accessing FileSystem.moveAsync. 77 00:06:00,990 --> 00:06:04,130 That's a method which moves a file from a to b 78 00:06:04,260 --> 00:06:09,540 and it also uses a promise because moving that file can take a bit longer and therefore it will tell 79 00:06:09,540 --> 00:06:10,730 us when it's done. 80 00:06:11,750 --> 00:06:18,100 Now move async takes an object with two pieces of information - from and to which is pretty straightforward 81 00:06:18,140 --> 00:06:19,010 I guess. 82 00:06:19,010 --> 00:06:25,070 So from is image because image is the path to the temporary directory, so that's the from thing, that's 83 00:06:25,070 --> 00:06:32,290 where the file currently sits and to of course is our new path, like this. Now as I said, this returns a 84 00:06:32,290 --> 00:06:32,770 promise 85 00:06:32,800 --> 00:06:36,420 so we can await this and that's it. 86 00:06:36,430 --> 00:06:41,200 Now we should wrap this into a try catch block because this could fail because for example there is 87 00:06:41,200 --> 00:06:48,090 not enough space on the device or somehow we have a permissions error or anything else is wrong. 88 00:06:48,160 --> 00:06:55,690 So we definitely should try catch our filesystem actions because operations on the filesystem can always 89 00:06:55,690 --> 00:06:56,400 fail 90 00:06:56,620 --> 00:06:59,520 and there we then might want to do something, here 91 00:06:59,530 --> 00:07:04,680 I'm logging the error and I'm rethrowing it but of course you could do other things there as well, 92 00:07:04,690 --> 00:07:09,310 you could kind of store this on your own analytics server, whatever you need to do. 93 00:07:09,610 --> 00:07:15,100 Now you ultimately might want to handle this in a component too to show an alert there, I'll not do it but 94 00:07:15,100 --> 00:07:20,650 you would handle it in the same way as you do for example handle HTTP errors which is something 95 00:07:20,650 --> 00:07:22,160 I had a look at in the 96 00:07:22,200 --> 00:07:24,040 HTTP module. 97 00:07:24,040 --> 00:07:28,980 So here, we're assuming that this will mostly work or that this will always work and 98 00:07:29,050 --> 00:07:31,350 we're moving the file. Now 99 00:07:31,420 --> 00:07:34,870 once it was moved, we know it'll be in the new path, 100 00:07:34,900 --> 00:07:41,140 so of course it's the new path which I now want to store here in my place 101 00:07:41,140 --> 00:07:46,320 data or in my Redux store. That's all nice, 102 00:07:46,330 --> 00:07:50,040 this should store our image in a permanent directory 103 00:07:50,140 --> 00:07:56,110 but what we're not doing is we're not storing our data itself in a permanent place. 104 00:07:56,110 --> 00:08:01,510 We're of course using Redux here and that means it's stored in memory but whenever we close and restart 105 00:08:01,510 --> 00:08:08,010 our app, all our data will be lost because that's not stored on the device or on a server or in a database, 106 00:08:08,010 --> 00:08:12,730 it's just in memory which is active as long as our app runs and thereafter that's cleared. 107 00:08:12,730 --> 00:08:19,630 So as a next step, I want to show you how to use SQLite which is an on device database, both available 108 00:08:19,630 --> 00:08:25,360 on iOS and Android, to store more than just files but to also store our data, like the title and 109 00:08:25,360 --> 00:08:26,800 the image path and so on.