Building A Linktree (ish) Clone With React (LIVE)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
i suppose that i'm live well let me get my chat up although i think this time around i'm not gonna have the chat on the screen just simply due to the fact that i need more room uh more visible room here on my screen so i'm gonna just move the chat a little bit over here just getting that ready so uh what am i doing well i'm gonna be building a linktreeish clone using react i've been doing a lot of these code live videos where i'm just coding live and i would say it's not really a tutorial but i will be explaining my thought process as i build these things so in a way you're probably going to learn a lot or you can just watch me if you're bored and you like these sorts of things that's what i'm here for so since this is a react app i'm going to go ahead and bootstrap the process or just get the process going of creating the app and as that's going i'm going to talk a little bit about the tech that i'm going to be using in this video and all that great stuff so just gonna go ahead and run npx create react app and i'm just calling this linker it's probably not an original name but it's just what i come up with because hey this is what this is just for fun and i code for fun you know that's a totally normal thing to do right so as this is building out i'm gonna talk about the stack that i'm using here so obviously react for the front end but since this is a linktree clone-ish and i'm saying link tree-ish for a reason we'll get to that in a minute it needs some sort of database right because when you share the links with other people they're going to have to access the links that you've saved or stored for a given page so you're going to have to be sharing data across the world which means we're going to need some sort of database and in my case i'm going to use firebase for that because i love using firebase it's a great solution for that it's free as long as you don't get super popular and hey if you get super popular you're probably already rich right so uh firebase is what i'm using here this is going to be a uh sort of like a multi-step process um right so i'm gonna break it down into steps the first step is we're gonna have to create authentication we're gonna have to create a login form because we're gonna have to associate users with pages or links right so we're gonna have to create some sort of authentication mechanism for users to be able to sign up and sign in that's the very first step second step is going to be to create a dashboard where you can see all of the you know the links that you've created the link pages that you've created already and also a button to create a new one that's the second step the third step is going to be a form so to say like a forum of sorts to be able to input all the links you need for your link page and then i guess the final step is going to be the actual link page itself which is just going to pull in the data for the given link page via some sort of id grab the information from firebase and then display a list of links for a given page id that is pretty much the entirety of the app verbally let's just start building this out step by step the first part of this was the authentication since since i'm using firebase it comes with a really good tool for authentication so i'm going to use it and just for now i'm going to use email and password sign up so for this i'm going to do enable here and let me zoom in i'm going to enable email and password sign up but i'm not going to do password list sign in right now so i'm going to save that and zoom out a little bit so now i've enabled authentication via email and password for my project i actually have to implement that now what i'm going to say is throughout this video since this isn't really a tutorial i'm going to be using code snippets that i've just created in the past because i've done this so many times i've used firebase probably like for for probably at least 10 different projects so i've implemented a lot of this code in react so it's like i'm just going to use previous implementations that i've already done and then paste it in and change it and of course talk about what i'm doing as i do it i just don't feel the need to just code every single thing from scratch it doesn't make sense so i this has finished loading up the project but i have this end file yes i'm sure i want to move it i've already populated my firebase information into the into this end file and i'm hoping that by the end of this video i do not accidentally leak that information because then i'll have to delete this project or change my credentials in some way this contains all of the secrets that i need in order to load and bootstrap firebase which i'm while i'm prototyping and building this live i'm going to be these are going to be in the browser anyway because i'm going to be accessing the api directly from within the browser but typically in a production environment i would end up loading firebase on the server side and then just communicating with an api that i build that implements firebase that way any of the firebase credentials will never end up in the browser at all but since i'm just doing this live for fun i don't see the need to go through that whole process just hopefully i don't accidentally click this and then show everyone my credentials um just uh just wanted to put that out there so the first thing i'm going to do before i actually implement the auth stuff is just kind of go through and figure out what i am and am not going to be using throughout this uh video or this stream and just delete the stuff i'm not going to use and i did it i clicked it i knew that was going to happen that's fine i'm not gonna make this a production app or anything like that so um i'm not really worried about it leaking or anything but it was kind of a challenge to myself and i failed really early on so that's nice um let's just i i like to convert this to an arrow function export here non-default export convert to arrow function and return hello now one thing is i just want to make sure i have prettier in my application so that when i save well i might already have prettier as part of create react app so i'm going to go into my preferences and just see if i can enable format on save really quick and i enable format on save but then i also need to set my formatter to prettier which is right here and then in theory if i click save okay so i actually need to add a prettier config file so in my root i'm going to do dot prettier rc and in here i'm just going to paste in a config that i use for pretty much every project and it's right here so if i save it maybe if i go back and click save there it is it automatically like got rid of the extra spaces at the end and this um this semicolon i think it added that and a couple other things so prettier is just a great tool to use in general i like to have that every time i start a new project deleting that not using that anymore what else do i need to delete really quick uh this then i can get rid of this import and this is now a default sorry non-default import and i'm gonna move app into its own folder because i like to have a components folder because i end up having helpers and like uh constants and just like a shared folder hooks etc so i'm gonna create a components folder and then within here folders for every component so i can drag app.js into here and app.css into here i'm going to use css modules so i'm going to rename this to styles.module.css and these are the sorts of things i do every time i start a new project i should probably fork create react app or create my own script to do this for myself but i just like to do it as a way to sort of remember why i'm doing the things that i do and in here i create an index.js file that's used just to export app and that way i can go here and instead of doing app slash app or in this case since i put it in a components folder now components app slash app i can just say app and then from the folder itself it should allow me to import the app component um not sure that i'm going to use a global css file unless there's eh yeah let's just keep that okay so i think i'm done kind of doing the bootstrappy stuff i say bootstrap i'm not talking about css bootstrap i'm talking about bootstrapping and application i think i'm kind of done doing that and i can probably start working on the login form but the first thing is i wanna i wanna make sure i have firebase integrated into my app so i need to install firebase so npm install firebase now i know this is old school but i still like to add dash dash save beforehand because it's just habitual and i just like doing it but i don't think i have to do that anymore just a note that i think it's dash dash save by default nowadays uh let that install probably is gonna take a second i guess while that's installing i can just make sure i got everything i think i might need to update some import somewhere right so no we're good here oh that's what it is and here i'm importing it as app.css but i'm using css modules so i can import styles from there and then whenever i have a div or something like that i can say class name equals styles.main for example if i want to give it the main class and this should be here of course there is no main class right now so i can create the main class and i already know i'm going to use flexbox so i can just probably go ahead and add that goodness and then set the flex direction to column so for whatever this is which i haven't quite talked about that yet this is going to have display flex and flex direction column so we have a comment in the chat that says what does dash dash save do dash dash save installs a module to the project it installs it in this node modules folder here for the given project instead of installing it globally for your computer so it essentially ends up adding it as like a project dependency instead of a module that you install on your actual machine so hope that answers your question d all right so back to this i'm pretty sure that's finished by now good zero vulnerabilities i hate it when i install something and it's like found five thousand severe vulnerabilities and i have to go through and just you know maybe three thousand of them can be fixed automatically and then i have to fix some other ones anyway so far so good i'm on firebase 8. so what i always do the easiest way that i've found to integrate firebase into a react application is to do what i'm about to do and that is to create a new folder called service and in here a new file which i will call firebase i guess dot js and then i like to always include an index file in any directory that i create within my project to export everything from there now the firebase file since i've already done this a million times i'm going to copy it over and just kind of talk about what it is um and actually i want to instead of just putting this service folder at the root level i want to put this inside of a shared folder because really this is like a shared concept service firebase is going to be used throughout the entire app so anything shared can go in this shared folder and there's this service folder in here and i call it service because it's going to be what i'm calling a firebase service now i'm pasting this in let's talk about this for a second so i need to import firebase before i import anything else now i'm not going to use storage so i can get rid of that but i am going to use auth and firestore throughout this and since i'm not using storage i can go ahead and knock that out of there i don't need that and i can get rid of this so what's going on here so i'm importing what i need from firebase then i'm initializing firebase but that is certain scenarios especially if you're using next.js or something like that there you could have already initialized that when this loads for example like on the server or something like that it's not going to load properly when you do it like this there's certain scenarios where it won't work so go ahead and add a catch that's what i've done here but what this is doing is it's pulling stuff from my end file that i accidentally leaked earlier and initializing firebase with the values for my firebase project then below all of that i'm exporting a const which is just a javascript object make sure it's visible that is called fb which is short for firebase and it's an object that just contains two items firestore which is firebase.firestore notice the parentheses and same thing for auth what i'm doing is i'm creating an instance of firestore and an instance of auth and then giving it uh assigning it inside of an object so that i can share the same instance throughout my entire application because there are cases where if i were to just um like within one component say firebase.firestore like this and then in another component also say firebase stop firestore like this i have two instances of firestore throughout my application i want to share the same instance throughout the entire application so what this is doing is just that it's making my life way easier hope that makes sense okay cool so close that don't need that anymore right now and i need to um what do i need to do i need to go ahead and i guess start working on that sign in form right so i guess i could create a new component called like what do you want to call off no let's call it login it looks like we're doing capital letters for this level here and then what capital letters again for the component name so login.js now i guess i can just knock out the boilerplate of you know it being a component so export const login and can pretty much just say something like return uh i am the login but i'm also going to need one for sign up right so we'll go ahead and create a new folder called sign up do the same stuff basically create a new file sign up dot j paste in change this to sign up instead of login same here now both of these just need an index.js file which exports everything from that given file copy that go into the login folder do the same thing index dot js paste but instead it is login and now i have pretty much the boilerplate for the login and sign up components so i can start you know actually implementing them but i want to make sure everything is running at this point so in here i'm gonna leave hello and below this i'm gonna put in the login form now obviously i need to import that so i since i have that uh you know that that index.js file i can import it from the directory instead of the um the file so i can import login from now i can go out of directory into the login and that should be good so let's see if i can run the app npm start um missing script npm star i need to be inside the right folder there we go npm start wait hold on okay for a second i was worried that i installed the firebase outside of the linker folder because i ran npm install but i wasn't inside the linker folder hold on no way okay so i did that yeah that's so dumb wait did i do that it looks like i don't see any reference to firebase here at all refreshing here somehow i goofed that up okay so i need to actually run npm install firebase again now that i'm inside of the right directory yeah so let's install firebase alright not paying attention there so let that do its thing and it's weird because i installed firebase outside of this folder but i don't see a package.json or node modules i wonder where all of that ended up probably not in here oh my gosh so many a b c d e f i don't see it let me see if g h i j k l i don't know i don't see it so just let that finish and here it is and found 80 moderate severity vulnerabilities well let's run npm audit fix and see if that gets the 80. vulnerabilities probably not it seems like most of the time it yeah fixed to zero of eighty so in order to fix these vulnerabilities i would need to manually review them i'm gonna pass on that for now so running npm start again to see if it all works so just give this a minute here uh looks like it loaded it says hello i am the login which is exactly what i would expect because i'm using the login component let me do the same thing with sign up make sure the signup component loads i don't know why it wouldn't so this is kind of pointless but i'm in full automated mode hello i am the sign up zoom in a little cool the project has been successfully bootstrapped i can start working on the signup form yay um sign up needs to be done first because i need to be able to sign up in order to log in so sign up needs to be done first so create a div and it here i'm going to give it a class name of styles dot i don't know what main i just like using main but i need to actually import styles i have a snippet for that but there is no styles.module folder in this directory so create that and create a main class this of course is going to be display flex and flex direction column it would be nice if i could get this auto complete stuff working the way that i wanted to but anyway so in this this is essentially going to be a form i'm not going to use a form html element um i just don't want to i prefer to do a div and then just have inputs and then control them manually probably not the best practice it's just how i'm going to do it um so we're going to have what how many inputs are we going to have we're going to have an email address and a password but we want to be able to confirm the password so three inputs total now the uh the first one is email so the type type is equal to wait what is going on here was hoping for some sort of uh whatever some sort of autocomplete inside of here would have been nice but i'm not getting it that's fine the value we're going to create state for so const whoops spell const correctly uh we'll say email and set email equals use state which i need to import from react import use state from react and we're going to initialize that as an empty string now um hey indra can i call you indra for short um do we have a discord community we do not but i would love to start one um right now uh the best way to you know to be part of the community is to follow me on twitter tweet out um and of course youtube comment section i'm also on twitch so if you're watching this on youtube follow me on twitch port exe and if you're watching this on twitch follow me on youtube same um i do not quite have a discord channel yet i want to but right now i've just been focusing on growing the the channel and haven't quite gotten around to building like a discord server or anything like that so um so the email is initialized as an empty string so now i can just set the value as email now whenever this input changes so on change we need to update the email so set email equal to e.target dot value um i want to quickly go to my prettier file and change the print width to 80 since i'm zoomed in it's like 100 is a little too wide see now when i save it automatically collapses to the next line i think that looks way better let me know in the chat if you agree right so now i'm going to basically paste this three times because we need three inputs right um this one is gonna be password which i'm gonna use pw for short because that is so much easier sorry type password that needs to actually be spelled out but this will be pw and this will be set pw need to add that in state we can initialize that pw set pw initialized as empty string but we also need to verify pw so verify pw and set verify pw is also empty string good stuff now here we have password and set password here we're gonna do verify pw this is also a tight password and then instead of set email set verify pw okay let's see if the three inputs at least show up on the screen so i got the three inputs definitely need to add placeholders to these so let's do placeholder is equal to uh email address and then just put like a little well i don't need to put required they're all three required so um placeholder and this is password and then this will be verify password cool so now i get those placeholders i just want to quickly do a little bit of styling because i don't like how it's the size of the entire screen um the let's say the width is going to be what um i'm thinking 500 pixels i can probably i can probably fit these on the screen at the same time while i do css i really like to have a visual going on here so um the width of being 500 pixels is a bit much but i am also zoomed in so when i zoom out this is what it actually ends up looking like so keep in mind folks that i'm actually zoomed in so you all can see this a little better to 250 percent so 500 pixels seemed okay but i think 350 was better and then i should probably set a max width you know just thinking about mobile first design and all that max width of like 97 percent something like that cool so that gives me that but the the uh the actual form itself should be centered horizontally in the screen but it's not and the reason why it's not is a mystery because oh i know exactly why so it's inside of this div the sign up form is inside of this div but we need to set the div to be width 100 uh which didn't do it oh i know what it might be let's uh let's click inside of here and inspect and see if i can figure out where like what is um let's see the main class here this is the main class for the sign up form and then oh it's because it's flex direction uh i need to do justify content here i'm mind exploding let's do a line item center that should do it cool so now it is even on both ends it's uh horizontally centered great but i want to set like a padding let's set a padding of 25 pixels no that's too much because i'm zoomed in i'm gonna zoom out a little uh still that's still too much maybe five pixels let's just set it for the top padding top padding top and we'll do 15 pixels there we go that looks okay i like that so back to the sign up form at the very top i'm just going to throw an h1 tag in here that says sign up that looks cool now keep in mind folks running through this i'll worry about the design a little bit later functionality first 100 of the time in my opinion um hey mad candy and also indra says what is linktree linktree is a website that allows you to create uh pages uh where you list links and then you can share those with people and then people can click those links and go wherever you set the links to go in my case it's going to be a little different because i'm going to allow people to create multiple link pages and and manage them so um looks good so far i need a button let's throw a button in here so this button is going to say submit or sign up maybe let's do that now this particular button is going to have functionality but i want to give this button a little bit of a margin top i don't know 10 pixels maybe and actually i think also maybe the inputs should also have the same yeah that looks better now i want to style the inputs just enough to where they're not so ugly that i hate looking at it let's do a padding of 5 pixels per input and then let's do border radius whoa border radius seven pixels maybe and then let's get rid of the outline and the border and just add a box shadow of zero zero five gray that looks a tiny bit better um sure now the button we're gonna do some of these same things so i can actually like throw these in there same with this and the button i want to set the background color to like a navy blue but the actual text color needs to be white or else it would never show up but this navy blue is a little too dark so i'm thinking maybe something like that that's a little better and i'm gonna set the cursor to pointer okay looking good looking good so at least it's a little bit more presentable but i don't like this giant signup thing but i'm not gonna be that picky right now cool so this needs to be disabled until um these three things have been satisfied so what we'll do is create another piece of state const we'll say valid valid set valid and that is whenever the form is valid we'll initialize that as false which will allow me to come down here and say disabled and we want to disable it if not valid now it's disabled but you can't tell so visually you can't tell i need to add a little bit of css to say whenever it's disabled and you can do that like this i want the background color to be gray and i want the pointer i'm sorry the cursor to be not not allowed save that now it's disabled and you can see the little not allowed circle with the you know the ghostbusters uh anyway so once i fill out the email address fill out both these fields and the passwords match then we want to enable this so let's start there um [Music] so let's create a use effect that changes whenever any of the inputs change so we want to look for email password and verify password now whenever any of those three things change we're going to set valid equal to a boolean that evaluates true or false now we want it to be true if email password and verify password are not empty so we can say email and password and verify password but we also need to make sure that verify password and password are equal so we can say password is equal to verify password so now essentially if i come in here and do that now it enables but the second i make verify password different than the password is disabled again okay well one thing is for sure and that is this was not an email right so i came in here and i typed in some stuff and that's fine i don't need to make the password super complicated like you need eight letters you need this and then the other i don't need to do all that for a fun streaming twitch youtube live app but what i do need probably is at least to verify uh that an email is formatted correctly so i'm going to look at a regex that i made before in a different app for this exact thing let me see where is this thing it's under components it's under login or probably something called sign up right or off let's see i'm looking at another app that i made in the past um you know what it's not on here oh wait it's in a different project so it's in here under here there it is i think source components sign up form there it is now the regex that i'm looking for is called email regex and it is right here okay so here is my email regex it's a rather simple one okay just kidding that's not super simple um but since i'm probably you know i might use this elsewhere too for example the login form i'm gonna add this in my shared folder i've got a shared folder i'm going to add a constants file and that's going to be js by the way dot js and i'm going to export this regex here i'm going to call this regex oh gosh uh email regex i hate vs code sometimes but i love it so much stop doing that email regex and i'm exporting it but i need to go in my shared and create a new file called index.js export everything from constants so now in my signup component i can import that regex from constants okay so email and email regex dot test no comma email so now let's try this again see fdsa does not allow that to work but as soon as i do at you know aol.com because we all have aol emails that works fine cool so that use effect is working as i wanted to i need to create a sign up function that happens whenever i click the button so on click equals we're going to have a function called sign up now the first thing that i want to do in this signup function oh my gosh um is check that we're valid i know that the button is disabled and therefore you're not able to click the button if it's disabled but you can still right click in there and hack the dom and say like inspect element and then enable the button and then i don't want people to hack my website so i need to do another check in here this is if valid then run the functionality otherwise just don't do anything now if we're valid i want to import firebase and do some firebase stuff what is this sign up regex i don't know what that is um so i need to import firebase import fb is what we called it from the service folder right so it's in here shared service slash firebase or i don't even think i need to do that i could probably just import it directly from service because i have the index.js file probably anyway so fb dot now i have two items in there i have auth and firestore obviously in this case i care about the off dot sign what we need um what we need to do is look at the exact method name i think it's like sign create user it's create user with email and password so firebase gives me this create user with email and password thing and we're gonna use email now that is going to return a promise so if this succeeds then what do we want to do well we want to essentially navigate them away from the login page to a dashboard so instead of doing any of that right now i just kind of want a console.log something like signed up success exclamation point and then verify it in the dashboard of firebase to see if this is all working as expected so it looks like i have an error auth is not exported from firebase app um well let's head over there see what's going on this is happening in firebase.js before i do that let me just add slash firebase make sure that that wasn't what was causing it i didn't think so um hey nicker glad that you're here all right so yazoof on twitch says do you usually take care of accessibility using arya in html i do not on live streams but if i'm creating a production app or something like that that i actually want to be used in a production environment then i i go all out on those sorts of things hope that answers your question um i'm gonna be looking at the chat here and there but for the most part i'm trying to zoom through this so i won't be as interactive with the chat that you know like as interactive as i normally am but uh carrying on here figure out this bug really quick so and i'll just do this oops go in here see what it's talking about says auth is not exported from firebase app okay this is interesting i wonder if this is some sort of new version of firebase um and version 8 has a breaking change with the way it handles exports so now i have to import it like this [Music] yeah that seemed to have worked so there was a breaking change with exports in version eight i now have version eight and now i fixed it by doing what they said stack overflow i love you okay so send her an email a password and click sign up okay so it says sign up success i don't believe it that would be too great if it just worked the first time so let's verify it and here by clicking users and you can see that now there is a user with my email that i just created so i know that it worked sign up works now let's do the same thing with login right so if i refresh this i'm still logged in because the way that firebase works so what i should do is quickly clear my um clear my app stuff like my cookies and everything so i'm going to clear my cookies i'm going to clear my session storage all that maybe i can just go to storage and click clear all clear site data maybe yeah it looks like everything seems to be cleared so now i should technically not be logged in so i want to kind of just copy this stuff over into my login form all right so go to sign up essentially copy most of this i'll say like from here down a lot of copy pasting going on here today import styles create the styles folder i mean file then go to the sign up component steal my styles and now styles should work use effect needs to be imported from react and so does use state go ahead and add that there i like to add it below it um and i think that's fine i don't need the verify password state and i don't need the va well i'll keep the valid state and obviously i do not need that here either so i don't need this check right here the only thing i care about is that email and password are not you know empty strings or null and also that the email passes the email regex which i can just auto import now this variable doesn't exist so i can get rid of that firebase needs to be imported as it is here you can see that i've done this so many times at this point it's just like muscle memory up until a certain point within the app where i have to start thinking uh more deeply instead of calling this sign up i'm going to call it login and we're not going to use this particular function here instead we're going to use sign in with email and password here it is sign in with email and password we'll use the email and password state and then instead of saying sign up success i want to say log in success get rid of this h1 keep the h1 call it login instead of sign up email keep that password keep that get rid of the verify input call the login function change this text save cool so what we should have in the components app folder now file is instead of sign up let's call it login you know import login instead of sign up save let's see what we have in the browser we have login the two inputs that we would expect so let me type in the wrong password really quick okay so i didn't handle the error that's going to happen in the case of like wrong password all that other stuff so what i want to do is copy some of my old code where i handle all that good stuff um here we go sorry i'm looking at my other screen to kind of find my old code we'll start with the log in form since i'm already on it and just do a quick error handling situation okay so over here on my code in the login form where we're calling the sign in with email and password there's potentially cases where you know we type in a username and password that is wrong or just this email doesn't exist etc so we need to have this catch in place for those cases now my other code is saying like we have this error state so i need to actually add this error state see just creating some error this was typescript where i've done this in the past initialize it as an empty string and now we're setting error based on the response here if there is an error but also there's there's a case where like there is no error but um but the user doesn't exist and that is going to happen here so let's say right here we want to say set air we're having trouble logging you in please try again it's like a fallback if we log in but there's no user in the response then there's something horribly wrong right and add that parenthesis then if there is an error we're just checking for the error codes and giving some sort of response or error message that makes sense to a normal person then we need to display this error here at the bottom i want to use some styles to make it look errory so in here i'm going to create an error class and then in the form here which i need to quickly grab from my earlier implementation uh i want to probably display above the button maybe below the button let's do it below the button let's display it here so what this is saying is if there is an error in state then let's add a div in here and display the error message with the error styles and the error text but that also introduces a new potential issue which is whenever we do successfully like whenever we try to log in again we should probably reset um the error so let's set error back to an empty string at the beginning of the login attempt and then if something goes wrong within that process we can set error so let's just see what we end up with here so i'm just typing in a random email that doesn't exist and some random password i click login it says no account for this email so that is good but it's not red why is it not red let's see by the way guys um if you if you see like sometimes i'm kind of like uh struggling to see something it's because in order for you all to see what i'm working on i have to zoom in everything on my screens and for me that really limits my my view so it's really hard sometimes to see what i'm looking at um okay well i just need to specify that in my styles color red save go back oops i like that so no account for this email cool so then if i put in the right email but the password is wrong it says invalid credentials and then if i put in the right password the error goes away and it did not seem to log oh i know why i didn't log it it's because i accidentally removed that so it we need to say else here console.log log in success i think something just happened let me see you got speed bro yeah i know i'm i i code a lot so that's probably why something happened on the uh i got some notifications but i don't know what happened anyway um login success will get logged so i need to clear my cache and just check if the log works the log message where we at where are we at oh it's right here okay clear site data yeah i'm definitely not used to it being this zoomed in okay see if this happens for me login login success great so login is working sign up is working i'm not going to go back and add in like the error messages for the sign up or anything like that because live coding don't want to spend too much time on this but what i would do in a production environment is take the same concepts that i applied here to the login form with handling the errors and just moving that over to the up as well yeah but since i have an account now i don't really care about the sign up right now this sort of like a hand it to the junior developers type of thing i joke i joke um cool so once we log in i don't really want to do anything here per se because what i love about firebase is like it works under the hood a lot in the browser so i i can have a listener that's listening to firebase authentication changes and when there is a authentication change it's going to tell me whether or not someone is logged in or logged out and when that change triggers i can react to that particular state change that's how i'm going to handle this now what i normally do and what i'm going to do in this stream is create a hook um called off so we'll call it off well auth user off user.js and i'm going to [Music] um look at my other project to see exactly how i implemented this in the past file open recent this particular project and i'm going to show you something that i love doing because it's super powerful and in my opinion kind of the way to go if you're using hold on firebase authentication in a react project so i just pasted it in now i used typescript typically which is why i have types in here i need to get rid of the types because i'm just using raw javascript in this and i just kind of want to sort of talk about what's going on here so i'm importing firebase from shared but i need to update that because actually it's being updated from shared slash service and i'm creating two pieces of states two pieces of state two yeah is off or i'm sorry is auth which means is the user who is using this app currently logged in or not and also auth user which is the authentication firebase user itself then i'm creating an effect that is triggered only on a knit so this will only ever hopefully run once on a net whenever this hook is loaded and this you know whenever you have a effect you can return a cleanup function which is what i'm doing here and basically what all we're doing is we're listening to the firebase auth on state changed event and if there's a user we're setting the auth user and whether or not they're auth and then the same thing in auth user and is auth in the case of them being logged out so i have this super awesome hook and i can you know i'm going to create my index.js file where i will export this and i want to import it into my app component this one over here so let's import it um call it i think it was what was it i'm sorry it was use off so i want to rename it here too to use off that is the convention that i like so import use off from hook slash use auth and i don't there was supposed to be an s on this supposed to be hooks like plural you know so let me fix that okay so let's bring in and use this hook and show you how i love using this so const and now i can destructure out is off from use off and that's really all i care about is whether or not the current user is logged in or not so is auth is whether they are logged in or not and i want to render either the signup form or the login form or something else sorry based on whether or not they are authenticated at the time so let's say if is auth if they are authenticated we want to just show the dashboard so i'll just literally render the word dashboard for now otherwise i want to render the login form now on the login form i should have a link to the sign up form but again i'm just kind of skipping that for now because i want to move forward with the app but that's something i'll probably add later but um i would expect now to see the dashboard yeah but let me like clear out my storage or the site data and refresh and now i see the login form so as i log in i would hope that as soon as i click the login button now i see the dashboard so that is perfect working great stoked on that okay yeah zoof says you could have is auth as a constant user equals null instead of state hopefully you'll understand the power of the way that i'm doing this and the reason why i'm holding it in state because we are able to share this state throughout the application without having to have multiple on state changed listeners and so we can kind of keep this in state i know we can do like firebase dot user and there's some other ways to do it too but just having it all in one place having one source of truth for the user um and whether or not they're logged in is is really powerful and super clean just look how clean it is to be able to just pull this out at any given point i just i love it so now that we got through part one which is authentication it's time to start working on the dashboard so if i pull open my firebase here i'm gonna be using the firestore and i need to create a collection called what do you wanna call this um pages yeah link pages we'll just call it pages or link pages we'll just call it link pages just to be super specific about it now each link page will have its own unique id okay so i'm going to create a fake one here just generate a fake id here we're going to have a couple of things here we're going to have a list of links for a given link page so that will be an array array of strings because these will be links so i don't know um let me open an incognito window and just go to like reddit and what i don't like how i'm in sure let's just let's just literally have read it um as the the first link and then for the second link i can just do something like google.com no not goog what google.com i don't know why it went to gmail i guess it automatically went there and then we'll just have google as the second one without this id at the end just to have a couple of links in there so we have links another thing that we would want is an id of the user who this particular page belongs to so i don't know user id and then this will coincide directly with the id that firebase generates for a user so let's go to firebase so i'll have two firebase tabs open you can see all my projects yay um yeah so this id right here will be the user id yeah is there anything else that really needs to go in here maybe later on i can add other things such as like a background image like a url to a background image so that you can style it and maybe like different fonts so you can customize it but for now i think links and user id is sufficient okay so we have link pages and we have one fake example link page here i think that's enough to get started with the dashboard so creating a component here called dashboard and i have to do my usual boilerplate stuff i really need to create a cli tool for myself for this i'm going to chew on some trail mix while i do this i'm going to back away from the mic so you don't hear me chewing okay um yeah let's just return dashboard i gotta figure out how to be able to like eat food in front of a microphone without it being annoying so in here instead of just returning this this thing that says dashboard i want to have the actual dashboard component rendered out save that and this is just too much i need to where's my prettier config i'm gonna have to go down even further to like 75 there we go so insight says i'm starting out to learn react using typescript can you give me some tips for beginner it's hard because everybody's different and everybody has a different level of knowledge going into learning something and especially something complex as engineering it's like what do you know what you already don't know and i would say the most general knowledge i can give you a foot activated mute button thank you james that's amazing i wish i could gift you some sort of sticker i don't have merch or else i would send you a sticker for that brilliant idea but yeah insight so the most general advice i can give to someone is build some projects first of all if you don't if you don't know typescript at all and you don't know react at all learn those tools first then build something with typescript build a react project with typescript kind of like i'm doing right now but just start way more simple and when you get stuck on something simple or because you are going to get stuck on something except when you get stuck on this something within the simple app you can have specific questions to ask i would go to like reddit or some forum somewhere and ask a more specific question because that's when you really learn is is in the context of something like uh uh super specific in my opinion so just build build build once you get stuck ask specific questions that is my advice um okay so so far so good now in the dashboard component i want to load all of the link pages that i own so if i own a link page as i'm calling it own but i mean data ownership not like political ownership or like capitalism i'm talking about i am the user who created this page so i own it um i want to get a list of all of the link pages that i own right off the bat so i again if i'm dealing with collections in firebase and i'm using react i have a hook that i love to use for that so let me um pull this from code that i've already written so new file we'll say use pages yeah dot js because it's pages that we're dealing with so i'm pasting this in here getting rid of my types rename this from use posts to use pages instead of owner id we were calling it i think user id get rid of this type got rid of all the typescripty stuff um um and then i'm gonna talk about what's going on here in a second uh we don't have a time stamp so don't want that user id return pages that won't exist because i'm calling this posts where are we at set pages get in there okay okay hold on let me just i think i think i got rid of all the i think i converted it to this project basically so what's going on here that is the question um this is what's happening we're creating some state called pages and this is going to be an array of pages that i own so we're passing in the user id wherever we are using this hook we're going to pass in the user id so it knows who owns who the owner is then we create an effect and whenever that changes because you know you can sign out and sign in so whenever that changes we are going to update our list of pages so we're going into firebase grabbing firestore and grabbing the pages collection so if i go here you can see it's actually link pages not pages glad i looked so i need to quickly call this link pages we're grabbing that collection and we're grabbing all of the documents in that collection where the user id attribute which is this guy right here is equal to the user id that we pass in and then on snapshot means whenever that link page updates on firebase it's going to send a notification to us that something changed and then we're gonna run this code again and update our data so in here we're saying on snapchat snapchat what that's hilarious on snap shot change on snapshot change we are going to create an empty pages array and then for each of these snaps we're going to push the data for that page into the array basically so that is what's happening and then we're also creating a new property called id which is this id right here and then just adding it as a property to the object so they don't have to go out a level to access it it makes it just so much easier i this is code that i'm proud of anyway um so let's let's first access that right so we need to do const oh i should probably export it from the shared i'm sorry from the hooks folder so export from oh what's going on here use pages okay so let's um let's say use pages now in order to use use pages i have to have the user id right so const we need to pull from use off to get the user id and that is off user now we have to pass in that id for the auth user into here so we can say auth user optional chain um id now inside of these pages i'm already handling the case where like id isn't is undefined i think so it should work just fine if the user id is undefined is what i'm saying so this logic should make should work fine and let's pull out pages um i don't think it's returning an object it's just returning an array so pages is equal to use pages now i just want to log pages and see if we're getting what i expect to get back from firebase so save see what sort of horrific error messages are in the console um cannot resolve off user um what's it talking about let's see cannot find module auth user in hooks okay it's because it's not called auth user it's called use off i thought i would have got that error message earlier on right just happened okay dashboard so let's try that again refresh and we are getting another error message that says oh why am i trying to access it from shared wait what is it talking about okay hold on one thing at a time here move a little slower sometimes i think no not user off use off okay so let's see if that fixes it no module not found shared in hooks where are we trying to access shared why is it trying to access shared let's see here it's trying to access it here okay so i think the problem is we need to go no that's certainly the right place so what is it's because it's capitalized huh wait yeah wait i am confusing myself right now what is going on here so i'm thinking mostly in my head so this probably doesn't make sense to anybody who's watching the stream right now but basically this is what's going on it says cannot resolve to shared now this is capitalized and it's saying that the error is coming from use pages but shared is capitalized and if we go to use pages um whoops did not mean to change that there go to use pages use pages shared is capitalized why is it capitalized okay got it all right that should get rid of the air good refresh and we get a different error of course it says query.where is called within valid data an unsupported field value undefined so the field value is undefined for some reason so it turns out i lied by accident i need to inside of my use pages thing go up here and say if user id is a thing then run that otherwise you know undefined maybe that will help okay good stuff so now we're getting undefined we i wouldn't expect to get undefined um i would expect to see a list of pages so the reason why we're getting that might have something to do with the way auth user works so i want to um log off user instead of pages so let's log it so auth user has a lot of stuff that looks extremely cryptic and it's uid that's why so it was always undefined because it's uid and not id so now i can kind of backtrack a little bit to where i was logging pages with the correct data this time and just refresh okay look an array boom all right mad candy is on point just bring the chat over here we got people in the chat um thanks a lot helps me i am already feeling that problems and solving them with digging deep into yes so digging deep and hands-on is the way to learn almost anything theory is how you prime your brain so you get you learn the theory you learned and you understand what the tools are you prime your brain then you have to actually put it to practice because that's when you actually really learn but you can't really do that without the theory part right so you need to learn it first then just do the hands-on okay so i got an array of link pages where i am the owner of the link page so i want to just test this and create another link page with a different user id to make sure that i don't get both and i still only get the ones that i own so let's say links array https youtube.com and then um oops let's do [Music] user id abc123 save now i would hope that when i refresh this we still only have one item in it and we do and it's the one that i own so we're only getting the ones that i own and that is good so i'll drink a sip of water to that and i really wish i had um james's foot activated mute button right now because i'm about to chew on some trail mix this stuff's exhausting i need some calories for my brain by the way what i'm about to do now is start rendering out the links on the screen oh it's a thing he said i can order it on amazon it's actually a thing i did not know you i mean it makes sense right i mean it makes perfect sense it's just a controller probably like maybe a usb controller or something makes perfect sense i'll look it up thanks james so i'm going to map through the pages and i want to map each page here i have the index as well that was accidentally i want to wait i wonder if you can even see what i'm typing yeah you can let me scroll up a little bit um i want to render a div for every single link page now obviously i have to return the divs that i iren uh create so each one of these needs a unique key and bless uh we want to render out okay this is this is interesting right so right now all we want to do is we want to thanks kevin kevin said thank you for your videos they are so helpful well thanks for being here thanks for watching thanks for supporting it's because of all of you that i do this in the first place so right now i want to render the pages out but i don't really care about the links until you click on a page then it should take you to the page so you can view all the links so you know makes me wonder like what this even looks like you know what i mean because we have like a list of link pages but we're not really naming the link pages are we um so what what do you see like a tile like a square that says link page number one link page number two um what do you see hmm well for now i am gonna do that uh no we should name we should have a name for each link page yeah so i'm gonna add one more field called name and i'm just going to call this like test and i'm going to name this one example there we go so now we can render out the names is that raining ah it's not raining um we can render the names here so we can just say p dot name um whoops okay cool um okay so now i see the name example here now because it's flexbox it's appearing over here i'm gonna get rid of the flex styling here that's better uh so each of these will be rendered out in front of me but i think what i would expect is just maybe a list of pages and each one will have like be inside of a little box with an outline perhaps so we have main which is the container for the dashboard component but we can have like page now this can have a padding of 5 pixels border radius of 8 pixels i don't know and then a border of 1 pixel solid black or i like to do box shadow instead of border zero zero three five sure yeah let's do three and then i need to add the class um let's move this over boom and i need to add the class here so each of these will get the class page save okay it looks a little wonky display flex align items center uh font size 10 pixels and also justify content center and cursor pointer so that it's obvious that you can click on it and i don't know when i hover over it maybe i want some sort of effect that like just isn't so boring so maybe i'll take give it like a transition oops transition of zero point two seconds and then apply that transition for the non-hover state as well and just change the box shadow to be i don't know five pixels black instead of three pixels gray see what we got uh and then we can also change the padding to three pixels or wait what is it three five so i don't like that it changes sizes so we'll just keep it like that all right so not exactly beautiful but it's working um so when i click on this it should then take me to the link page itself so i could preview the links inside of there which means i probably need to have the react router so time to install react router uh where's it react router dom let me look it's react router dom so time to close this and do npm install react router dom okay now installed let me go to the index component not that one um let's just do index.js and we want the one in the source folder here we go import some stuff from react router dom we don't want use use location we don't want use location we don't want switch we want to wrap everything in it's been a while since i've used react router so i'm just looking at the my code example here so we just want to wrap it in router which comes from react router dom there we go so this is really what i wanted to import and then i want to wrap the app and the router component just like that which should provide my app with the router context that i need in order to use routing within react now inside of my app component now we can do we can import what i was importing previously at least some of it because i don't want use location right now um we can do a a route actually i want this on my dashboard no hmm no i don't i want to oops render a switch here instead of my dashboard then inside of the switch we want to render different routes based on the current route now let's start with the path name equals just a forward slash which means just the base path name like this we want to render the dashboard component which we were already doing so if i refresh it should still potentially work as expected okay uh that is if i'm running the app so npm start npm start needs to be running in order for this to work obviously and it says cannot read property map of undefined well that makes good sense actually and the reason why that's happening is because in the dashboard component we're just like mapping through pages but pages might not exist yet because pages is loaded loaded asynchronously which means we need to do this we need to check for pages and if pages exists then we can run the map but i can just use optional chaining because that's way better so now we're we're in good shape so that is the forward slash um scenario can we add an array of paths right maybe is that a thing can i do this and then also say slash dashboard wouldn't that be sick so let's do slash dash that should give me like um i think i'm supposed to put exact or something i don't remember exactly there we go yeah but then if i finish board we get we get the uh yeah sweet so it does accept an array good stuff now another route would be the link page itself right so a given link page we don't want exact here because it's going to be dynamic so we can set the path equal to forward slash page slash or is it colon slash colon id is that is that right no i think that's all we need then the component that we want to render when we're at slash path is going to be the page component which we need to create immediately so while i do this i'll chew on more trail mix oops okay good stuff so now now we actually have the page component should probably export it oh i'm already doing that so what happens if i go to slash page we get i'm uh page i am a page okay there's a couple of things that this needs um we need to bring out use pages um well we can do we can do use page right we can have a new hook that takes a given page well we don't want to hit firebase multiple times okay i'm just thinking in my head right so let's say we pass in the page as an argument or a prop here maybe that's not the best idea because what if the page values are updated well then it will trickle down because since we're listening for page change updates in the parent component when we drill down into this component by passing it in as a prop it will update as well that's why react is so great so maybe that is the best way to do it so maybe this takes a page as an argument or as a prop i should say yeah and then we can just render all of the links here since we could say just like page.links.map and then render a div for every page it makes me wonder if that would be the way to do it um less thinking more doing now i do know that this is going to end up being display flex column for sure so no not color i hate that it does that it's so annoying um so it's gonna be column and then instead of rendering i am a page here we should do page.name as oh wait i yeah so h1 page.name we're going to get an error wait we didn't get an error why is it still rendering i am a page there we go that's better so then under here we would do [Music] page.links.map the class name for this could be uh we better pull out the index and give it a key and all that stuff too so we can say p for page and index key is equal to index and then the class name is going to be page now the content inside of here should be oh you know actually the structure of the data is going to have to change slightly so we can do that in a minute but the links should not be just strings they should be objects where we have value which is the url and then we need a name for the url because we need to map names to urls so that we'd say like hey this is my website or this is my youtube channel whatever you know um so let's let's change the structure of this data um so i'll delete this property create a new field called links and instead of it being an array of strings it's going to be an array of what they call maps so we'll have value which is going to be the url so https reddit.com and then we will have name and we'll say reddit and then we will add another wait yes we will add another item trying to figure out this ui um there we go so we will do again value let's do google https google.com and then add fields say search engine oh wait that should be the value um for the name um hold on a second i guess from the ui i'm having trouble adding one of these yeah whatever one is fine we'll add a second one later in the actual form but that that's kind of weird i was just trying to add another item to this links array but i don't know i'm derping out right now so in here we'll say p dot name um although that needs to be in curly braces so i don't know a map of undefined so again we need to do that because we're not passing in a page yet same deal here um whoops there we go so no error message but now we actually need to pass in the page that we clicked on and the best way to do that is here we can do render props or something like that let me look what is the best way to do this i think we can actually like do something like this and then pass in the page as like the page that was clicked on which no i i see exactly what needs to be done here okay okay okay um this is not where we're managing sorry we need to i'm starting to think the router isn't even a great idea so i'm actually probably going to keep the router since i've already implemented it that's fine i might get rid of it later but i need to actually put this logic in the dashboard so i'm going to move over to the dashboard and render out how do i want to do this so we should have a route system in here yeah i'm really thinking about this one because i need to be able to keep track of which um which page that the user clicked on and i don't want to use global state to do that you know i could add a context or something that says currently clicked page that's global state throughout the application definitely don't want to do that so i'm trying to think of where i can render this page out and i think that the best way to do this is to add it to the url so it's actually right the first time let me oops go back to the app component and click undo a few times we need to essentially add it to the url right so it'll be like slash page slash and then the id for the page um which would be this id right here why can't i copy that um i just need to full screen this so i can copy it this would be the id so it'd be like slash page slash the id and then when i go to it it will pull from the id so i can use use location to grab that and then um yes sounds like a plan i need to make sure that's imported but it doesn't seem to want to import give me that auto import all right well i'll import it manually okay um all right so inside of pages uh shouldn't be called pages it should be called page we want to first grab the id of the page that was clicked from the url okay so let's do that um right now i'm just doing this to get rid of all the error messages okay so on mount so i can use use effect to say on mount empty array we want to grab the location or the url so we can say use location perhaps that comes from react router but i think we want that from react router dom right so use location but we don't want that inside of an effect we want that outside the effect so const location is equal to use location now inside of here i'm going to log location to see what this gives me um it gives me an object with a path name so i can go and essentially parse this path name or instead of making it a instead of doing slash and then the id i can add it as a query param it says id equals now we get this sort of search thing okay let's do it like that and then let's say console.loglocation.search dot replace this is not this will require me to go back in the future and do this a little bit of a better way but this is going to work for now on this live stream i'm going to say replace question mark id equals with an empty string let's log that and we get the id itself cool um in the future i don't want to do that in a production environment because there might be multiple of these query parameters and um i might change the name of it or maybe there's a like a facebook id or something click id point is this is just for prototyping and for this live stream not the production way to do it so now i have this uh this id okay so here is the id i need to set that in state i i like to set things in state at first and if it doesn't make sense for state later i change it so let's do use state you can get user id from use params it says yazoof on twitch you can get user id from use params user id i'm not trying to get the user id right now but are you saying i can import something called use params from react router dom and then get the page id from there how does how does used params work let's see what comes from that const params equals used params let me see what that looks like that might be better sounds promising i wish i had stickers to like give you all when you when you give me interesting um unique helpful information like this okay so i'm not getting it here it didn't seem to work for me i might be doing something wrong and odds are i am because i feel like use params is like an official thing um let's take a look use params react router dom um oh you have to destructure it wait hold on but wouldn't i expect i see good stuff it's been a while since i've done react router dom so this is probably stuff i've done before probably even in tutorials and just um forgot about so yazoof over here helping out the stream and again i wish i had merch because i'd give you a sticker i'd send you a sticker or something but i don't have anything um so see here um okay so now i have to do slash there it is ha ha good on you so i can get rid of these two things that i was gonna do because his way of doing it is way better so now i can say well actually i can do this id we can destructure id from that and whenever the id changes we want to set current page which is going to be state so const page set page so now i can get rid of that equals use state start off undefined once the id changes we can then go into the list of pages which we have um from use pages whoops that requires the user id right not the most efficient way to do these things so we also want to make sure that we add pages here and then we want to set set page equal to the we're going to find the page within pages where the page is equal to or sorry p dot id is equal to id right i think so and then i'm going to create a separate effect simply to log that page log the current page see if this works save see what we get we get errors cannot read uid of undefined uh then we get cannot read find of undefined oh well we we only want to do this if pages is a thing right so if id and pages then run this okay we have undefined as the page so [Music] we somewhere have what we're expecting refresh and okay so pages is here set pages pages dot find where p dot id is equal to the id now wait what why is the id equal to id equals that did i not do that right let me see console.log id one more time just by itself it's keeping that is so weird to me so if i just keep this as params this out just log params if i just log params it's keeping id what am i doing wrong here oh my gosh i had a typo in my id i thought i was going crazy for a second we're good folks um all right so yes yes if i know i just witnessed that as i was doing this so we need to [Music] say id and pages get rid of this go back and now we get reddit okay good so now when i click on reddit i would expect to go to reddit so let's add an on click and obviously a better way it would probably be to make these link tags or something like that but i'm not going to do that for now so e window window dot well i think we can do like window.create or window.add or what is the exact term of window javascript javascript open new tab i forget the exact method it's window.open window.open window.open the url for the one that we clicked which is gonna be p dot um i shouldn't be calling this p i should be calling this l for link where is it l dot um value and i i don't know why i added that we'll do that okay um see if it works refresh click opens reddit awesome so i would say oh and then i clicked it again um you know obviously there's some things left i'm about to end the stream for today and then probably continue this tomorrow so make sure that you're following me whether it's on twitch whether it's on youtube make sure to follow me because i will be continuing this up and finishing it tomorrow but what's left we need to add the ability to create these pages from within the ui itself so basically a create page form with links and the ability to do all that good stuff we need to be able the ability to delete pages we also need to add styles because this isn't exactly the most beautiful app i've ever seen i also don't like how when i refresh it i see the login page for a split second before it redirects me to the dashboard i don't want to see the login page so these are all things that i need to fix the next time around so i don't know how many sessions i'm going to break this into but just keep an eye out thanks everyone for showing up i will continue very likely tomorrow at some point during the
Info
Channel: PortEXE
Views: 1,276
Rating: 5 out of 5
Keywords: linktree clone, linktree react, react app, live coding react, live coding web developer, building an app in react
Id: Wnl1uMcivTA
Channel Id: undefined
Length: 109min 55sec (6595 seconds)
Published: Sat May 29 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.