Check out a free preview of the full Intermediate React Native, v2 course
The "Storing a List of Plants" Lesson is part of the full, Intermediate React Native, v2 course featured in this preview video. Here's what you'd learn in this lesson:
Kadi creates a store for the list of plants. After the new plant form is submitted, the plant is added to the store, which populates the list of plants on the home page. A PlantCard component that renders plants in the list is also added to the application.
Transcript from the "Storing a List of Plants" Lesson
[00:00:00]
>> Kadi Kraman: And finally, we need to store our plants in our existing storage, so the same way that we did with the onboarding state. And we want to display all the existing plants in a list on the homepage. So, I could use the same store, but I think it's nice to keep these separated if possible.
[00:00:21]
So we'll create a new zustand store and we want to be able to see a list of plants, so we want an array of plants. We want to water a plant, so watering is going to be a time stamp, so we'll say a last watered at time stamp.
[00:00:38]
And you want to be able to remove a plant from our list. So let's go,
>> Kadi Kraman: To our storage. So we store, and let's create a New File called plantsStore.
>> Kadi Kraman: So this is quite a bit of code and again I'm not going to live code it, so let's copy this file across and let's look through what it does.
[00:01:13]
So I've created a PlantType here, so each plant is going to have a unique id, it's gonna have a name, it's gonna have a wateringFrequency in days, which is a number. And then optionally a lastWateredAtTimestamp, which will be a number. So it's optional because there will be an initial state where it's never been watered or planned.
[00:01:36]
And in our zustand state, we're going to have our array of plants, which will be an array of these plant types, which will be empty or have many. We have our function to add a plant, which will take the values from this form, so the name and the watering frequency in days.
[00:01:56]
Then we have a function to remove a plant by plantId and also water a plant by plantId which will set this lastwateredAtTimestamp. I've also done something a little bit cheeky here. So in real world applications if you need unique Ids you could use a library so nano id or native uuid.
[00:02:20]
But in this case, I didn't want to install a library, and I don't need these Ids to be globally unique, I just need these to be unique in my phone. So I added a little functionality here for managing the Ids in state. So this is just telling me what the next Id I can use is.
[00:02:39]
And every time I add a plant, I increment it. So in this addPlant function I just return the existing state, then I'll increment the next Id. And in the plants array I'll add the new plant at the top of the list.
>> Kadi Kraman: For the removePlant, we return the state and then just filter out the plant by Id that was passed in.
[00:03:09]
And then for waterPlant we're going to just map over the plant's array. And then if the plant is the one that we're watering we're going to set the last watered timestamp to the current time. And lastly, same as we did with our onboarding storage, I'm going to store it in AsyncStorage.
[00:03:28]
But notice that the name of our storage key is different. So this is now the plants store. So now we would like to hook up creating plants. So in our app.new, so the new screen.
>> Kadi Kraman: Our placeholder here was a console.log. So after it's passed all these validations, it will get to adding a plant.
[00:03:54]
So let's do at plant, and this will be the usePlantStore from the stand. And we'll pick the state, we'll pick the addPlant function from our plant store.
>> Kadi Kraman: And here, we've already checked that this days is a number. So, we can safely cast it into a number. So we'll do addPlant(name, Number (days)).
[00:04:31]
>> Kadi Kraman: And once we've added it, let's also close the model. So we'll use router, for that, the router hooks. So let's do const router = useRouter.
>> Kadi Kraman: And down here we want to do router.navigate. And we'll just navigate back to the index page.
>> Kadi Kraman: So now let's do,
>> Kadi Kraman: Casper The Cactus.
[00:05:08]
>> Kadi Kraman: I don't know how often you watch your cactus three/four days, okay? So currently I've submitted this form, but nothing is showing up because we haven't implemented our list on plants yet, so let's do that. Open your theme file, cuz we need to add a couple more colors.
[00:05:27]
Let's do a colorBlack, which is just #000, and colorGrey.
>> Kadi Kraman: So, I'm actually using just this grey color, but you can also write out the hex code, which is #808080.
>> Kadi Kraman: So, in our plant store, let's export the PlantType. So we could use it in our home screen.
[00:06:04]
And for the plant card, let me just show you what we're building, maybe this will help. So this is what we're building. So we're building a list of plants. So we want this little plant card, and we'll create a separate component for that. So in your components, let's create a PlantCard,
>> Kadi Kraman: .tsx.
[00:06:27]
And for this, we can just copy this file again.
>> Kadi Kraman: There we go. So one thing that I've added here that I've not implemented yet is that for this plant card, we want to use the same PlantlyImage as we did in our home screen and in the add plant model.
[00:06:53]
But we kind of wanted to be smaller because if every one of these were close to the size of the screen that wouldn't work. So because we're using React we can customize our PlantlyImage component to optionally take in a size prop, so you could define what size it wants to be.
[00:07:11]
So let's open the PlantlyImage.
>> Kadi Kraman: And let's do a type Props and we can pass in a size which is an optional hence the question mark, it's an optional number.
>> Kadi Kraman: And here we'll de-structure size from the Props and for the image size we can say that it will be size or, if this is false or null or undefined, then we'll go to our default.
[00:07:53]
And finally, in our index page, we want to render this list of plants. So let's go to tabs, index. And now we do have an array of items to map over. So if we have an array of items to map over to have a full screen list, then we always use a FlatList.
[00:08:16]
So let's do const plants and get our plants from our zustand store. This will be usePlantStore((state) => state.plants)). So this hopefully, let's do a console.log just to validate. If I open my terminal.
>> Kadi Kraman: So I've created a plant here, so I have an array of one.
>> Kadi Kraman: Let's add another plant.
[00:08:51]
Let's do,
>> Kadi Kraman: Laura The Lilly.
>> Kadi Kraman: I'm trying to remember if Lilly is written with one l or two.
>> Kadi Kraman: Apparently both are valid.
>> Speaker 2: [LAUGH] I think it's one.
>> Kadi Kraman: Okay, it's one, I'm gonna with one. And I go with seven, okay, great. So we have two values here.
[00:09:25]
So the data is definitely getting through, understand? Let's render this in a FlatList. So a flat list is a virtualized list, whenever you want to map over an array of items, you should never use array.map in React Native, you should always use a FlatList. And now it's because it has optimized handling if the amount of data that you render is too big to be anywhere near the viewable area.
[00:09:51]
So it actually, if you're rendering like a thousand items, it doesn't render all thousand, it renders some amount of screens. So let's return a FlatList.
>> Kadi Kraman: And we'll pass in our data which will be the plants array.
>> Kadi Kraman: And renderItem. So this will be the render function for each plant and it's a function and you can destructure the item from it.
[00:10:32]
So if we do item, then that's where we get the each individual plant and we take this and we render our newly created plantCard.
>> Kadi Kraman: And we pass in the plant as the item,
>> Kadi Kraman: Okay? So this is looking good, you can do with some padding if we were to match our design here.
[00:11:08]
So in our styles I can actually use this container style. So let's do style = styles.container. And we'll keep the flex one and the background color, we don't need the align items. We also want to add some padding there but recall that you should never add paddings or margins on the style prop of the scroll elements.
[00:11:35]
You want to use a contentContainerStyle.
>> Kadi Kraman: This is styles.contentContainer.
>> Kadi Kraman: And we'll do a padding 12. And the reason you don't want to add the padding 12 here is then when you have enough items to overflow from the screen the bottom of the screen will be cut off.
[00:12:06]
So that's why we're adding the padding to the content container instead. So it's nice to add like a little list empty component as well, so when we've not added any plants yet. So with FlatList you have some convenience components so there is a ListEmpty, ListFooter, ListHeader components. So ListFooter and ListHeader will be rendered at the top or bottom of the file.
[00:12:30]
And then the ListEmpty component will be rendered automatically if the data that you're passing in is empty. So in this case, let's just use our PlantlyButton with a title and do "Add your first plant and onPress,
>> Kadi Kraman: We'll need to use router, so const router UseRouter.
>> Kadi Kraman: And onPress, we will do a router.navigate to our new screen.
[00:13:19]
>> Kadi Kraman: Okay, so this will open the new plant model if our array is empty and we can render all of our plants otherwise. So, one thing I want to draw your attention to that I used in this plantllCard that I've not spoken about before, is a shadow. So there's actually this really useful website that is great to use if you're looking to create a shadow with React Native.
[00:13:49]
So these are all the shadow props that you would use. And kind of manually playing around with it I find quite tedious, so using this as a starting point is really helpful. But one thing that you should know when it comes to shadows is that these props only work on iOS, and this only works on Android.
[00:14:10]
So when we talk about shadow, we're actually only affecting iOS. And on Android, the shadow effect is achieved with the elevation. So they actually look similar to us UI wise. So if I look at the examples screenshots here, if I look at the screenshots here, so we have Android on the left and then iOS on the right.
[00:14:36]
So they actually look quite similar, but they are using different props. So if you're creating a bunch of shadow and you have not used elevation at all, then on Android, that will have no effect.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops