- Read Tutorial
- Watch Guide Video
If you go to the "MemiPedia" project on DevCamp Space, you'll see that you have a new API endpoint here.
DevCamp Space
It is a GET request to retrieve posts and the endpoint is going to be "memipedia_posts". So if we make a call to this API right here, what we're going to do is we're going to pull in all of those sample posts that we created.
Memipedia
So I'm going to go down to view the data here.
Memipedia
You can see the sample data that I created. You can see that I added five different memes here with the name content and a different images for each one of them. So that is going to be the data we're going to start seeing inside of this guide. For right now, I'm just going to mainly render out some debugging output so that we can make sure the API call is working and then over the course of the next few guides, that's when we'll start styling it and making it look nice. So let's get started here. I'm going to open up Visual Studio Code here, and let's work on our "FeedScreen". I'm also going to open up the simulator.
FeedScreen
You can see I'm logged in as a user and this is the same user that has all of that sample data. Make sure that you're doing that. If you created multiple users, you have to use the one or be logged in as the one that has those posts. So now, let's clean up our "FeedScreen". I want to get rid of all of this "CurrentUser" data here. So let's remove that from the view.
FeedScreen
In fact, I'm just going to get rid of the Text tag here because I'm going to put some debugging output here once we actually have our POST data. So let me remove that, get rid of the "currentUser".
FeedScreen - (After Removal)
Then remove that import, and then let's also remove the "useContext".
FeedScreen (After Imports/useContext removal)
So for our hooks, we're going to use two hooks as we build out this "FeedScreen". The first hook is going to be state, and the reason for that is because we need a piece of state where we can store our POST data as it comes in and then we can loop through it. That's how we're going to render all of our posts. We also need to set up a trigger so whenever the Post screen is accessed, the API is called and it pulls down all of the posts that have been uploaded into your application. So let's import both of those here. I'm going to say "useState" and then "useEffect".
FeedScreen (Add useState/useEffect)
So with both of these in place, we can come down into the function itself and let's add the first piece of state that we're going to want to use. I'm going to set up a useState hook that uses posts and that's going to have posts as the value and then "setPosts" as our setter for being able to store data inside of our posts value and then that's going to "useState" and the first element or the starting state is simply going to be an empty array.
FeedScreen
So what that means is that we're giving TypeScript and our component, a little bit of a hint so that it knows that this is going to be a collection. So TypeScript is going to know okay, this is a collection which means that it's going to have the ability to be mapped over, iterated on and that kind of thing. If we just did something like starting off with "useState" as null, that's not really the best idea because then we're not giving any type of guidance on what this is doing, and then even worse, if we were to say "useState" starts off as a string, then we would start to get errors later on in this component when we try to treat it like an array. So we're going to start it off as an array because that's what it's going to stay throughout its entire lifespan. So that is our first thing. That's going to be our state. Now we need to create the "useEffect" hook. So I'm going to say "useEffect" and if you remember, in our "AuthLoadingScreen", we also use this.
AuthLoadingScreen
So this is the same "useEffect" trigger that runs whenever the application loads. In the "AuthLoadingScreen", we use this to see if the user was logged in or not. We're going to be able to use the same type of workflow inside of our "FeedScreen" to go and retrieve all of the posts that have been created. So I'm going to say "useEffect", that is a function so we call it with parens. The first argument is just going to be a normal function and it's a fat arrow function that doesn't take in any arguments and so we're going to say fat arrow function and then I'm just going to add a TODO so I'm going to say TODO and then "getPosts" because that's going to be the exact name of the function we're going to create and then once again, very important, make sure right after the curly brackets that you add a comma and you add a second argument of regular square brackets.
FeedScreen
That will ensure that this is only called one time because remember, if you do not do that, what will happen, so if I kept it just like this, what would happen is any type of change to the component, such as the user even touching the screen or scrolling a little bit would actually go and call the API again and again and again. You could end up with thousands of calls in a single minute and so that's definitely not what you want to do. So I'm going to add those brackets in and this ensures that this is only going to be run one time when the component is created.
FeedScreen (useEffect)
useEffect(()=>{ // TODO // getPosts(); }, []);
So now with that in place, let's come and let's create this "getPosts" function. So I'm going to say const "getPosts" and this is just going to be a regular fat arrow function that won't take in any arguments and we're going to call the API.
FeedScreen
Now, in order to do this, we have to show the API that we're authenticated. So in order to do that, we're going to have to do the same thing we did in the "AuthLoadingScreen" where we grabbed our secure token from the store and we pulled that down and sent it up in our headers. So let's first import that. So we're going to import the "SecureStore" and we can just copy this straight from the "AuthLoadingScreen".
FeedScreen
After that, we're going to have to make "getPost" an async function and then from there, we can retrieve our token and store it inside of a variable. So I'm just going to take all of that text right there and then I can just paste that in and so now we'll have access to the token and we can be confident that we're going to have access to this token because they can't see or even access this screen unless we've already checked that that token is active and it's valid. So with all of that in place, now we can call the API. Now, if you have the autoimport extension, you should just be able to start typing api, hit Tab and that will "autoimport" it for you. If not, you can just import it manually, just like it is up here.
FeedScreen
So I'm going to say api.get and then the first argument for get is going to be the path, which we already looked at that endpoint at the beginning of the guide and it is "memipedia_posts" and that is the URL endpoint that we're going to hit and also, just as a side note, notice how helpful it is to use an API utility like this. If not, if we just used "axios" by itself, every time we make an API call, we would have to put that long URL, even though even a few items would really change. So this is really a nice way of doing it. So the first argument is the API endpoint. The next one is going to be that call to the headers and our authorization token, and we can just go back to "AuthLoadingScreen" and copy that because it's going to be identical. So you can copy all of the curly brackets, starting at the comma right after the logged_in text and let's just paste that right after where it says "memipedia_posts" and hit "Save" and that's all we need to do.
FeedScreen
So this would call the API and it would pass in the token. So with that in place, now let's say what we want to happen after that. So after we've retrieved the posts, we want to perform these tasks. I'm going to say then response and then have a fat arrow function. Before we start trying to see it on the screen, the first thing I usually do when I'm building an app is I just start with a "console.log(statement)". So I'm going to say "console.log(res.posts)" and then just say "response.data" and then I also want to catch any server errors. So I'm going to say I want you to catch any errors and I'm just going to copy this and I'll say error from posts and here we're just going to print out the error itself.
FeedScreen (getPosts)
const getPosts = async () => { const token = await SecureStore.getItemAsync("memipedia_secure_token"); api .get("memipedia_posts", { headers: { Authorization: `Bearer ${token}`, }, }) .then((response) => { console.log("res from posts", response.data); }) .catch((error) => { console.log("error from posts", error); }); };
So now, this is really all we need in order to call the API. The only thing we have to do now is to have this function run and so we do that inside of the "useEffect" hook. I'm going to comment that out.
FeedScreen
Call it now and now, whenever we access the "FeedScreen", we should print out in the terminal the data from the API. So let's go check on the terminal. I'm going to open up where I have Expo running and as you can see, this is all working. These are all of the posts that we have on the server, that I have on the server.
Terminal
You're going to see the ones that you uploaded for your sample data. So you can see everything from the content, you can see the name, you can see the "image_url", so all of this is looking really nice. So let's go and let's actually see what this looks like on the screen. So I'll open up the simulator. Not Google Chrome. There you go. Visual Studio Code and the simulator and now, let's store all of this data that we have coming in, let's store it in our local state. I'm going to keep the "console.log(statement)" there because we may want to reference this to see the structure of the data, and here I'm just going to say "setPosts" and then "response.data.memipedia_posts".
FeedScreen (getPosts)
const getPosts = async () => { const token = await SecureStore.getItemAsync("memipedia_secure_token"); api .get("memipedia_posts", { headers: { Authorization: `Bearer ${token}`, }, }) .then((response) => { console.log("res from posts", response.data); setPosts(response.data.memipedia_posts); }) .catch((error) => { console.log("error from posts", error); }); };
To see this on the screen, before we start iterating it, we're just going to look at what it looks like from a debugging perspective. So inside of this View tag, where we used to keep the "currentUser", I'm going to place a Text tag and then curly bracket so that we can run "JSON.stringify" so "JSON.stringify" and then pass in our posts.
FeedScreen (return)
<Container navigate={props.navigation.navigate}> <Text>Feed screen</Text> <View style={{ marginTop: 20 }}> <Text>{JSON.stringify(posts)}</Text> </View> </Container>
Okay, let's hit "Save" and there you go. Did you notice how for a second there, there was just empty brackets and that's perfect. That's exactly what we want because when this function loads, it starts and posts is set to those empty brackets and then it gets filled with the content and we have a warning here. We can take a look at it, and it looks like it's one of those warnings where it had some data or a potential memory leak.
Simulator (warning)
We're not going to worry about that right now because we still have a lot of things we're going to be putting in. We're going to be putting in a loader, we're going to be putting in some things and so I'm not going to worry about this right now. I'm going to hit "Dismiss".
Simulator (Dismiss warning)
This all looks great. You can see we have all of the data. We have the image_urls, we have the names, we have the content. All of this data is right here and we now have access to it and it's stored in our local state of "posts" here. So this is looking fantastic. In the next guide, I'm going to walk you through how we can create a loading state for our posts so that while we're going out and we're getting the data from the API, we're going to see a little spinning activity indicator.