Refactoring the ImagePicker Component
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

So our PostFormScreen now has all of the data elements it needs in order to create a post. Now what we need to do is start wiring it up so that we can wrap up the data, such as the name, the content, and then the image file, and then pass that up to the API in a way that the API can understand it,  process it and then store it in the database.

So the very first thing that I want to do is to work on the image component because that's going to really be one of the trickiest parts of this entire form. You've already built out a form where you were able to take in the name and content, or things like the name and content, with the username and the email in our AuthScreen. So you've already gone through that.

Now let's see how we can work with the image. And we're going to start off by opening up the PostImagePicker. Now earlier, I said one of my big goals for this course isn't just to teach you React Native and not to teach you just how to build an application but really how to think like an advanced developer and experienced developer.

And so the very first thing I did when I met a component that I'd never worked with before, like the ImagePicker. I went to the documentation, and if you remember, we simply copied and pasted the example code straight into our application.

What that told us was that the Component worked, we didn't have any conflicts with dependencies, the documentation was up to date, and we're able to see it on the screen. That was all great, and that was the first part of what we needed to do in order to build out this feature. But now, we need to take it to the next step.

We now need to customize the Component so that it fits our own application's needs. Then also, I want to add our own flavor to it. I'm not a huge fan of simply copying and pasting someone else's code and plugging it into the application because I've seen applications that were built that way, and it ends up looking like a, just kind of a mishmash kind of setup where you have code in all codes of different styles and follows different conventions, and it can be not very clear to maintain.

So I would like to do is I want to make this Component now fit in with the rest of the style of our entire application. So if we take a look at the code here, you can see it uses a class-based Component, and that's fine. It's perfectly fine to use a class-based component. However, if I look through this code, I'm not seeing any reason why this Component can't be a functional component.

A functional component in the React world is typically your best option. I probably use functional components now that we have React hooks, probably about % of the time. And I don't see any reason why this Component can't be a function-based component. So the first thing I'm going to do and our main focus of this guide is we're going to convert this class-based Component into a functional component and get it to match with the rest of the styles in the rest of our application, and then we're also going to integrate the very first steps we need to grab the data from this form or this element here and pass it back up to the form component.

So let's get started with that. The first thing we're going to do is get rid of where it says class, all the way to Component here.

[Capture #1 [3:39]]

So we're going to keep export default, and then I'm going to say export default, and then I'm just going to do a fat arrow function. So the very next thing we're going to see here is that there's this state definition. Well, we know that we can use React hooks in order to use the useState hook.

So I'm going to say import, curly brackets, and useState from react. And then I can come down here, and I can get rid of this, and I can define our image value. So I'm going to say const image, setImage, and I'm going to set this equal to use the default of null so that we're following exactly what we had before with our class-based Component. Now, our function components do not need a render function. That's only required if you're using a class-based component. So I'm going to delete where it says render here, and then I'm going to delete that trailing curly bracket at the very end.

Now, here online, you'll see that in the documentation, they were using destructuring so that they could call image from our state object, but because we're using React hooks in this functional Component, we can get rid of this code entirely because we can call image from anywhere in the application. We don't need to use this anymore. So the next thing is this componentDidMount function. This is a trigger.

It is going to be some, it's a lifestyle hook so that when this Component loads up, it calls this function here. Well, if you remember, we can use another hook for that called useEffect. So I'm going to import useEffect. So I'll say useEffect and then right below our state definitions, I'm going to say useEffect, and then inside of that, we pass in a function, a fat arrow function, and then right after the curly brackets, we say comma and then square brackets just so this useEffect is only triggered one time.

[Capture #2 [5:48]]

And then from there, we can simply copy this function call inside of it, and then we can get rid of where it says componentDidMount. Now, because we're using this functionbased Component, we don't need to use the keyword this anymore.

So we can delete that. And you can see that we have an error here because it can't find the name getPermissionAsync. That's because whenever you're converting a class-based component to a function component, you need to store all of your functions in variables. So let's take this function and let's cut it, and let's put it right below. But now, what we're going to do is we're going to store it in a variable. So right before where it says getPermissionAsync, I'm going to say const and now you can see that that error's gone. So I'm looking through here. Doesn't look like we have any other calls to this or anything that's state-related. So I think this function's good.

And then now let's come down to this last function here called pickImage. I'm going to cut all of this, and I'm going to paste it right above our return function. Now to kinda talk about part of the reason why I'm doing this is because I said I wanted to have this function match the rest of the application My personal preference is to have the return statement here at the very end and I don't like having functions below it because there've been times where I'm working on a component and I forget that it have something below the return function and it can be a little bit confusing. So I like the return statement to be the very last thing in the function. So I moved it up here and then also, this is going to be something you'll notice in quite a bit of JavaScripttype of documentation is this little underscore before either a variable name or a function.

Whenever you see that, if you're not familiar with what that is, that is JavaScript's convention for saying that either this is a variable that's not going to be used or it's a variable that is private because JavaScript didn't have the concept of private functions. And so we're not going to follow this convention. I'm just going to get rid of that, And I'm going to say const pickImage Another example that you may see this in is I say I switch to the FeedScreen right here and I go to our API call, another time you'll see this is if you're getting data back from an API call, but maybe it's just a confirmation message or something like that, you're not actually going to show it to the user, a lot of times you'll see a underscore right below the response value, and that means that's telling the code and it also tells the TypeScript interpreter that that is a variable that's not going to be used.

So that's a little bit aside, but I just wanted you to see that just in case you'd never heard of that convention or you're confused on when you saw an underscore before a variable name. Okay, so we have this new function we're storing in pickImage. And let's look inside of it.

So, so far in this result variable, looks like everything's good. Then right here, this is what we're going to change. So you see where it says if the result is not canceled, which means, in other words, if it's successful, if we get the image back, right now we're saying I want you to store this in the image state. So what I'm going to do here is call setImage, and we're going to set it with the result. So I'm going to say resulturi, and I can get rid of what we have here, and then I'm going to get rid of this tsignore. You can see that we still have an error here, and I'll hover over it and see what it says. It says property URI does not exist on type imagePickerResult.

So what that means is this ImagePicker, they don't have a type definition, so TypeScript is confused, It's not able to find it. So the way we can fix this is, yes, we've already seen how you can do the comment with tsignore, and that perfectly fine. You could do it, and it'd fix that, or you could come up to result here and say let result any.

[Capture #3 [10:14]]

That's saying that result is going to be stored and it's of any data type, which means that we're going to be able to have URI called on it and we're not going to have any errors. So now let's take this PickImage here, come down to our button and let's just paste this in. Okay, and hit Save.

Now, notice, we were able to cut out lines of code. And we have the exact same functionality. We were able to cut out lines of code, and now we have this nice, I think, more cleanly written Component. I think it's a little bit easier to read. And let's go and make sure this is still working. So click on Pick Image from the camera roll. And go and pick an image. That looks like it's all working great. So I think this is good.

There's only one more thing I want to do, and then we'll take a break, and that is I want to build an interface for this because we cannot let this Component live on its own. This Component, when it gets its image value, it needs to pass that back up to the API, So let's see how we're going to do that. I'm going to say interface, and I'll call this IPostImagePickerProps. That's what we're going to call the interface. And then let's just call them, we really only need one prop here, and it's going to be a function. It'll be setPostImage, and that's going to take in; for right now, let's just say it's going to take in an argument that's going to be of type any. We can refine that later on if we need to, and it's going to return void.

[Capture #4 [11:57]]

So all this means is that we're going to be able to call this function now and then pass in or take in a value, which is going to be the image and then pass it back up to the form. So let's try this out here. So I'm going to say setPostImage. It takes in any value and then return void means it just doesn't do anything. It doesn't return any values, So come down here, and you can see where it says setImage, and it says if result's not canceled, what that means is, like I mentioned before, it means the image process was not canceled, we have an image to work with.

And so what I can do here is set the image, and then I can also call propssetPostImage resulturi. And let's see We have a little bit of an error here. Cannot find the name props, And that's because I've not called it yet. So let's call props, And then inside of props, call IPostImagePickerProps.

Okay, so this is looking good. Lemme see what this little warning is. Okay, no, that's fine, we don't need that. That one was simply because I hit refresh, and so now let's go back to the PostFormScreen. You'll see we have an error here now because our ImagePicker's expecting a function.

It's expecting that setPostImage, so let's add that in. So we're going to add a new piece of state here called postImage and then setPostImage, and then we'll start this off at null. And then we're going to set PostImage, we're going to just send it right in as a prop, so setPostImage equals curly brackets, setPostImage, and then just for fun, just so we can actually see that this is working, let's create a little View tag here. Let's do it below the button. So I'm going to say View and then a Test tag and which we need to import from the top. This is only for debugging purposes. This is just to test this out to see if the value is getting passed in, and then I'll say here, not setPostImage, I'll say if postImage, so if that is not null, then I want you to get the postImage or render it and if not, I just don't want you to do anything.

So let's hit Save here, and let's see if this works. So pick an image. I'll grab an image, hit Choose. And there you go.

[Capture #5 [14:41]]

You can see right here, we are now passing that postImage back up from the PostImagePicker to the PostFormScreen, and this long string, this is the path to that image file. This is what we're going to need in order to send it to the API so we can store that in that database. So this is all working really nicely. We've now not only refactored our PostImagePicker, we've connected the PostForm with that picker so that we now have all of the data that we need in order to start sending this up the API and having that surrendered so all of our other users can see 'em.

Resources