تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Creating Tweet model0:00

Okay, let's start working in the backend. Let's create a Tweet model and see if we can get communication going between our backend Laravel app and our frontend React Native app. So I have a blank Laravel app here. The only thing I've done is set up the database. So let's go ahead and set up a Tweet model. So php artisan make:model Tweet -a for everything else. Okay. Let's go to the create_tweets table. Let's go ahead and add some fields here.

Updating database migrations0:29

Let's go to the createTweets table. Let's go ahead and add some fields here. So let's add a field for the userId. So let's say foreignId, it's going to be a userId, and we can say constrained. So this will reference the users table. Okay. And for now, let's just say table text for the actual tweet, and we'll name it body. And that's fine for now for our tweet. Let's also make some updates to our users table. So createUsers table.

Let's also make some updates to our users table. So create users table. Let's add a username. So we'll say table string username, and that has to be unique. And let's also add an avatar. And that will just be a URL to an image. So that will be a string as well. It's an avatar. And that's fine for now. Let's set up our relationship between users and tweets.

Defining model relationships1:32

And that's fine for now. Let's set up our relationship between User and Tweet. So a User has many Tweets. So let's add that down here. Tweets. Let me just move this up. Return this hasMany Tweet class. Okay. And let's do the opposite case. So for Tweet, let's say User.

And let's do the opposite case. So for tweet, let's say User. And we can return this belongsTo User. belongsTo User class. Okay. Let's close those out. We can close these. Let's update the UserFactory. So down here, we can add one for the two new fields that we added. So let's put an afterName.

Building factories and seeding2:23

So down here, we can add one for the two new fields that we added. So let's put an after name. We have one for username. And Faker does have a username method we can make use of. So this Faker, and we want it to be unique. And username, okay. And for the avatar, let's add that in. I'm just going to make use of a service. It's called Pravatar. And there are a few options here, but I'll just stick to the one where we can use a random

It's called Pravatar. And there are a few options here, but I'll just stick to the one where we can use a random image ID. And I believe there's only 70. So we have to create a random integer between 1 and 70. So let's grab that URL, actually. Let's grab this. Let's paste that in. And then we'll have a random integer here. So let's append that on.

And then we'll have a random integer here. So let's append that on. And let's just say this Faker number between, and like I said, there are only 70. So one and 70. Okay. Save that. Let's go into our TweetFactory. And for our definition, let's just add user_id. And for now, we'll just create a new User for each new Tweet. So UserFactory is fine.

And for now, we'll just create a new User for each new tweet. So user factory is fine. For the body, let's just use this Faker sentence. And let's just say 20 words. Okay. Let's also add something for the created_at field. So we have different values. So created_at, say this Faker date, timeBetween, and let's just generate random days between now and 30 days ago. So we can say negative 30 days.

now and 30 days ago. So we can say negative 30 days. And now. Okay. Let's make sure to import User. And that should be good. And now for our database seeder. Let's go ahead and create a random amount of Tweets. So let's get rid of this, say TweetFactory. Let's create 40.

Creating tweets API endpoint4:51

So let's get rid of this, say TweetFactory. Let's create 40. And this should also create 40 Users. And that's fine for our first step. Let's make sure to import Tweet. Okay. So now everything should be set up. Now let's go ahead and make an API endpoint, which our React Native app can consume. So let's go to routes/api.php. And let's create a new endpoint here.

So let's go to routes/api.php. And let's create a new endpoint here. So I'm just going to do it as a callback for now. So let me just move this up. Let's call it /tweets. And let's just return everything for now. So tweet all. And let's see if this works. Okay. Don't need this param.

Okay. Don't need this param. Okay. So let's see if we can load these tweets in our REST API. So I'm going to go to Insomnia. Let's go ahead and make a new endpoint. So it's a new request. What was my project name? LC Laravel Twitter Clone. Actually this is the name.

Laravel Twitter clone. Actually this is the name. So we can just say Laravel Twitter clone. And let's go ahead and add that endpoint. So LC Laravel Twitter clone.test/api/tweets, I believe that's what I named it. Let's go ahead and try that out. And I didn't remigrate the database. So let's do that. So php artisan migrate:fresh --seed.

So let's do that. So php artisan migrate:fresh --seed. Okay. So everything does work. Let's try this again. And now we are getting all of our tweets. So there should be 40 in here because I specified 40 in our seeder. And it looks like there are 40. Cool. You can see the created_at timestamps are different.

Cool. You can see the created_at timestamps are different. So for our Twitter app, we want the latest on top. So let's change our tweetAll to tweetLatest. And then we can say get. Okay. Let's run this again. Now the latest should be on top. So 15, 14. And it looks like it works.

So 15, 14. And it looks like it works. Cool. So if you take a look at our simulator here, we also need information about the User. So we want to make sure that we eager load the User as well in here. So let's do that. So we can just say with user. Okay. Save that. And now we have User information in here.

Save that. And now we have user information in here. And we do. Cool. So if you want, you can just limit it to what you need. So we just need these fields here. So let's do that. So we can add a :. We need the ID, name, username, and the avatar. Okay.

Fetching tweets in React Native7:40

We need the ID, name, username, and the avatar. Okay. So if we try that again, then we only get those fields for the User. So let's jump back into our front-end code and see if we can grab this information from our back-end. So this is the back-end. I have the front-end here. And let's open up the simulator as well. So let me just hide the sidebar as we're only working with the home screen for now. So I'm going to make use of Axios here for our network requests.

So let me just hide the sidebar as we're only working with the home screen for now. So I'm going to make use of Axios here for our network requests. You can make use of Fetch as well, but for bigger projects, I prefer using Axios. So I'm going to stop the server. Let's yarn add Axios. And I'm also going to add datefns. And that's because we need to format our date in this format here. And the datefns package can do that. And you can see that here. Okay.

And you can see that here. Okay. So let's run that. Okay. Let's start our server again. Let me just reload the project here. Let's go ahead and import Axios here. I'm just going to import it in our home screen for now. Later on, we can make it global because we need it across all screens. So import Axios from Axios.

Later on, we can make it global because we need it across all screens. So import Axios from Axios. Sorry, spelled that wrong. And let's go ahead and replace this data. So I'm going to comment it out for now. And let's make use of the useDate for the data that's coming from our server. So let's say const dataSetData equals useState(). Make sure to import that. Did that import? It did.

Did that import? It did. And we'll default it to an empty array for now. Okay. So now when the screen loads, we want to load the data from our backend. So we can make use of the useEffect hook. So useEffect. Make sure to import that. It's going to be a callback, where the first parameter is a callback. And then the second parameter, we just want it to run when the screen loads, at least

It's going to be a callback, where the first parameter is a callback. And then the second parameter, we just want it to run when the screen loads, at least for now. So we'll give it an empty array. And within the body, this is where we want to communicate with the backend. So let's call a method here called getAllTweets, and that's where we'll do the work. So underneath here, let's go ahead and make that method or function getAllTweets. Let's make use of Axios here. So Axios, it's a GET request. The endpoint is this endpoint here.

So let me just paste that in. You'll see that it does work. Now if you're testing on an external device, then obviously this URL won't be available to you because it's running on this machine. So what you can do is make use of a tunneling service like expose or ngrok, and you would expose your project here, and that service should provide you with a URL accessible to anyone on the internet. And you would use that URL instead of the test URL that we're using here. So be sure to keep that in mind. But luckily for us, like I said, the simulator does work with this web server that we have.

So be sure to keep that in mind. But luckily for us, like I said, the simulator does work with this web server that we have running on our machine. So that's great. Now let's just go back to Expo. So let's go ahead and say .ven, let's grab the response. And for now, let's just console.log the response.data. And let's catch the error here, if there is one. And for now, we'll just do console.log error. Okay, save that.

And for now, we'll just do console.log error. Okay, save that. And let's comment out our flatList for now, because it's referencing this data variable that we don't have anymore. So where is our flatList? flatList. Let's get rid of this or comment it out for now. Save that. Okay. And let me just reload the app here.

Okay. And let me just reload the app here. So I'm going to press R. And we are getting a network error. Sorry, I forgot to add the http here. So let's do that. Save that. Let's check out the console. And as you see, we are console.logging all of that data from our backend. So now instead of console.logging the data here, we can just set the data in our state. So we can say setData = response.data, okay.

So now instead of console.logging the data here, we can just set the data in our state. So we can say setData response.data, okay. So now this data variable should be a list of tweets coming from our backend. So let's save that. And let's go to our method here responsible for rendering the item. And let's see where we're referencing this item here. And right here, we're grabbing the title, and we no longer have that. So this should be the user's name. So we have item.user.name. So let's just see if this works now.

So we have item.user.name. So let's just see if this works now. So I'm going to save this. Let's go back to our flat list and put that back. So let's re-comment this back in. Save that. Sorry, the data should be our new data, so lowercase data. Save that. And we are getting the users from our backend. So Natalie and Brady should be the top two tweets.

And we are getting the users from our backend. So Natalie and Brady should be the top two tweets. Let's take a look at our REST client. And that is correct. Cool. So let's go back to our renderItem method, and let's replace everything else. Also, we can rename item to tweet, if that makes more sense to you. And it does for me, so we'll rename it. So instead of item, we'll make use of tweet. So this is the username.

So instead of item, we'll make use of tweet. So this is the username. So tweet.user.username. This is the time, which we'll work on in a second. And this is the tweet body. So tweet.user, or not user. So just tweet.body. So let's get rid of this, tweet.body, save. And it looks like it does work. Cool.

And it looks like it does work. Cool. How about the avatar? Where's the avatar? It should be in this image component up here. Okay. So let's get rid of this. It should be tweet.user.avatar. Save that. And it looks like it does work.

Formatting timestamps with date-fns14:46

Save that. And it looks like it does work. Cool. So for the timestamp here, let's go to that, actually. For now, let's just say tweet.createdAt. And that should be a long timestamp, and it is. So now we can make use of date-fns and one of its functions to convert it to the format that we want. So I have it up here. It's called formatDistanceToNowStrict, and it will format it in this format here.

So I have it up here. It's called formatDistanceToNowStrict, and it will format it in this format here. So let's take a look at an example here. We can just use this, pass it a new Date. So let's do that. So we'll use this method, and this should be a new Date. New Date, okay. And let's make sure to import this method from date-fns. And that should have imported it. Let's check.

So for days, we just want D, and for minutes, we want M. And there's no easy way to do that within dateFns, but I did find a thread, which you can find here, where someone provides a solution. So if you take a look at this and scroll down, there is a solution here. So let's try this. Let's just copy and paste everything and try to get it to work, and then we can clean it up. So let's import this locale. So let's put that here. Let's grab all of this.

So let's put that here. Let's grab all of this. And here is where the custom formatting happens in this method right here. So formatDistanceLocale. And we also need this. Okay, so let's copy that. Let's just paste that in here for now. Actually, we don't need this first part over here. This is how you would consume it. So let's get rid of this.

This is how you would consume it. So let's get rid of this. Let's go down to where we defined it. So let's comment this out. Actually, let's just duplicate it, comment this out. And now this method takes a second param. So after the date, and that's pretty much what I deleted. So all of this stuff here. So we don't want the suffix. We just want the locale and the formatDistance.

So we don't want the suffix. We just want the locale and the format distance. So let me just grab this, paste that in. Okay. And hopefully this works and gives us the format that we want. So let's save that and let's take a look at our simulator. And it looks like it does work, cool. So we have two days, but the D formatting for days. So last thing I want to do is just clean this up and put it in its own file. Let's also get rid of this data.

Extracting formatting helper17:43

So last thing I want to do is just clean this up and put it in its own file. Let's also get rid of this data. We don't need it anymore. So let's get rid of all of this, or not get rid of it, but put it in its own file. So this can go in its own file. We can export it from there and then import it in this file. So actually we need this as well. Okay. So let's make a new folder here. Let's call it helpers, or you can name it utilities or whatever you want.

So let's make a new folder here. Let's call it helpers, or you can name it utilities or whatever you want. And let's name it formatDistance.custom.js. Okay. And let's paste that in. Let's export default this function, which is what we need. So export default function formatDistance. Let's save that. And now we can import it in here, in our home screen where we need it. So right here, let's import formatDistance and there it is right there from that custom.

And now we can import it in here, in our home screen where we need it. So right here, let's import formatDistance and there it is right there from that custom file. Okay. So this should still work and it looks like it does, but we've extracted that logic to a custom file. And one more thing I noticed here, there should be an app with the username. So let's add that. Let's just put an app here and that should be good. So yeah, that should be it for this episode.

Let's just put an app here and that should be good. So yeah, that should be it for this episode. So I have two repos now, so I need to make two commits. So this one will be start communication with backend. So that's the front end obviously. And this is our Laravel backend. Let's say git add, git commit, or it's not a git repo yet. git add, git commit, say create Tweet models or Tweet model and starting data.

Laravel APILeverage Axios

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟