All 29 Next.js Mistakes Beginners Make

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
nextjs introduces a lot of new Concepts server components server actions suspense and streaming static and dynamic rendering and much more so it's very easy to make mistakes even if you're an experienced developer so in this video I want to help you out fix those mistakes and to do that I have a very simple example that I will use throughout all of the mistakes that we're going to talk about so I just have this one homepage right so in the world of next JS if you want to have a page you create a page. TSX file I just have on and what do I have on this page I just have this H1 my store right that's just this and then I have this product component which is a server component what can we do in a server component I can mark it as async and I can actually fetch some data without use effect directly here in a component function body and it will give me a result here I'm parsing it as Json and that's what I'm outputting here I'm just taking its title right so this is just some dummy API that I found online it will just give you some random product data and I'm just taking its title right so for ID number three that's what we see here right so this is something you can do in a server component this would not work like this in a client component don't worry we'll talk all about that and actually the homepage itself is also a server component because everything by default in the nextjs app router is a server component if we take a look at the other component that we have here this is a favorite button this is actually a client component so if I open this up you can see it's a client component because here we need some interactivity I want to be able to click on this and when I do that the state should change and based on the state we are rendering something else right so here the user needs to be able to manipulate this so this needs to run in the browser and therefore we are marking this as a client component now to really understand nextjs you do need to zoom out a little bit so I will use this diagram as we go through the examples as well right so nextjs has both a client side with client components as well as a server side with server components server actions and these route handlers now I've seen beginners make mistakes and pretty much all of them so we'll review all of these as we go through the example so let's get started now if you're building a product you're going to need analytics so let's say I have a dashboard here and so in this space of my dashboard I want to have some analytics from chart so that the user can gain relevant insights so I can include one line of code and what I will get here is the following this is made possible thanks to the sponsor of today which is SEMA 4 so SEMA 4 is a more sophisticated solution for analytics so you can integrate it directly into your own software or app and you can customize its look so it looks like it's actually part of your app and let's say your user only wants to see orders that using same day delivery I can click on this and filter all of the data you can see all of these cards automatically adjust to what I just clicked right so that's pretty slick now your users will want to customize pretty much everything here so what they can do here with semop for is change the theme but also everything else like the order and layout let's say I want a little bit more like this make this sit more like this all right but they can also customize each card here individually so if I click on the icon here I can see all of the information for just that art so here you can see the query for the data of that card I can change the data source can come from anywhere I can even write my query in natural language and then with semop for I can convert this with AI to a proper SQL query but let's say the only thing I want to do here is actually just change this from a donut chart into a bar or line chart now after I made changes I can improve the changes and now you can see I customized that card so now after reordering things here and changing this card I have a different view here or what semop for calls a lens so I want to save this particular view so I'm going to add this lens here here right different order and a bar chart I'm going to save it so next time I come back I still see this default view or lens but now we have the third icon here I can click on this particular lens that we just saved and now I get my view back and I can also set this as the default and all of the filtering and things like that still work as well right you can add semap for with a single line of code so I would say check it out for your analytic solution whether you're building a SAS or e-commerce platform Financial or Healthcare type of software or any kind of software really and you want to give your users a sophisticated analytic solution the features that I just showed you were just the basics you can do much more so I would say check out semop for's website you can find a link in the description and make sure you sign up for the weight list and they are of course today sponsor mistake number one putting the used client directive too high up in your component tree so an example of that would be the following so here we have our page component this is a server component everything by default in nextjs is a server component so here we have our product component if we go in here you can see this is also a server component we're using using async here that's only possible with a server component and then we also have this favorite button here now previously I showed you that this was a client component I changed it a little bit so now it's a server component which means that now if I want to click on here nothing happened because if we actually want to run some logic here when the user clicks we need to be able to hook into that click event and that's not possible in a server component server component only runs on the server there is no click event there The Click event is happening here in the browser in the client so what I want to do here is I want to say onclick and then I want to change some state so I also want to use a react hook here so whenever you want to hook into an event or use any react hook whether it's use State use effect use ref any react hook or any event on change on click Etc any of that you need to make it a client component so if I save here I will get an error because this is a server component still everything by default is a server component we haven't made anything here a client component yet so you will get a warning because this and this is only possible in a client component all right now what I've seen some people do and maybe they're being a little bit lazy is they think oh I get this error I need to make something a client component uh you know what I'm just going to add use client right here I'm just randomly going to put it somewhere here so here I added it to my page component file so the way it works with this used client directive is that now this component here this home component will become a client component and then also everything that you're importing also becomes a client component so now this favorite button is a client component and so the error is gone because indeed you can use react hooks as well as hook into these events in a client component so everything here is working but because we added this up here also this product component is now a client component because we're importing this into a file with use client right so this is like a boundary right so this product component now if we take a look here if you remember we were we were marking that as async and we were directly using feton there if I now open up the console you can see that we are getting a warning here because async await the way I'm using that there is not supported in client component so this product right now is a client component I'm using something that is not possible and so you will get this warning this error is often caused by accidentally adding Ed client to a module that was written for the server well that's not what happens here I did not add use client to this file I added it to a component that's sitting a little bit higher in the component Tre you could say this one right here and the way it works with this directive is that once you put it at the top of a file all the components in that file will become a client component but then also all the Imports and the problem with that is that not only is it not possible you lose all the benefits of using server component we want components to be server components if it's possible so you don't unnecessarily want to make components client components if it's not necessary right because server components have benefits you can fetch data like this you can work with secret you can keep large dependencies on the server so if you're using a third party Library that's big you can keep it on the server but all of that disappears if you make it a client component because all that code will be shipped to the browser to the client so you don't unnecessarily want to make components client components so just to show you here because it's so important if you have a tree of your your Imports because it's about import and so you have a page component that's importing these two and then they also are importing some other components if this number three here needs to hook into some event in the browser you just want to add the use client to that component file because that's the only one that needs it everything else can stay serve a component if you're careless about that and you make that page component a client component which is technically possible the downside is that now these two become client components because these are being imported into that file and that's how it works it's based on import so these two become client components but then they in turn are also importing even more components and those automatically also become client component right so this used client directive is like a boundary So based on the import right so based on how you're importing things everything that is being imported will also become a client component and in turn if they're importing something those all also become client components so here component three and four would also become client components but not component five because it's not being imported in this component so here we don't want to do this you actually rarely want to add it to the page component file because this is so high up in the tree where and you're importing usually a lot of other components so this is rarely what you want to do you want to keep them usually at the edges of your component tree the leaves of your component tree right so typically for buttons for input Fields just the small little pieces on the page that actually do need interactivity so in this case it's only this favorite button that needs interactivity we're going to ship this one to the clients everything else can stay on the server now if I refresh that error is gone now but way it's not the end of the world if a component becomes a client component it just means that this component will run in a client as well so the code to make that happen has to be shipped to the client as well so it will increase the client side bundle but it's not the end of the world so don't be afraid to use use client number two not refactoring for a client component so here let's say on the page I want to add an up phone button and I want to hook into that click event now we just saw that's only possible with a client component right The Click event happens in the browser so that component needs to run in the client now I didn't create a separate component for this it's just a element right now on the page together with everything else here so again you may think well I have to add use client now to the top of the file here but now everything here becomes a client component home product favorite button so all of this now is affected by just this little element here so what you want to do sometimes is simply create a new component and that's where I'll have the jsx markup and then here in this file I will have use clients and then I can use that component instead of this I can use it right here and I can remove this directive here so now the page component and product are still server components and now just the favorite button as well as the upod button that we just created our client components so now it's more confined to the edges of my component tree just where the interactivity is needed number three thinking that a component is not a client component because it doesn't have used client at the top so if we go back to our previous example here we have that favorite button now if I open this up you can see we needed to make this a client component and so we have used client at the Top If we don't have that we get an error here now in the real world what may happen is that this favorite button may be sitting actually in another component let's say a sidebar so it's not sitting directly like this on the page it's in a sidebar so we may actually just have a sidebar here and in the sidebar you just some sidebar component is where we have that favorite button now this sidebar may actually already be a client component now the way it works with use client is that all the Imports also become a client component right so here now I can actually remove it from the favorite button if I save here in both files I get rid of the error even though the favorite button does not have use client at the top I'm using use State here on click I don't have to add use client to the top here because it's being imported in another file that already has used client but what some people do is to see if a component is a client component they open up the component file and they don't see used client at the top so they think oh it's a server component well not necessarily because if it's going to be imported into another file with use client at the top it's going to be a client component so this technically works but in my view it would be a little bit better to Simply add use client at the top here because this component always needs to be a client component right we shouldn't just rely on it being imported in some other client component we want to make it inherently a client component so it will work properly wherever you use it whether it's in a sidebar or maybe later in some other component that does not have used client at the top all right number four this one is about thinking that if you wrap a server component like product here within a client component that it automatically becomes a client component as well so the typical example here is with the context API so I created a context provider here and it's actually just a normal react component it's typically just called like this and it's using UST States here to keep track of the active theme and because I'm using UST State here I need to make this a client component and so this component here is a client component and the way it works with the context API is that you need to wrap the part of your app that needs access to that theme with that context provider now we could do it here in the layout or in the root but let's actually try wrapping this product here which we know is a server component and I'm using async here and fetching data here in the body it's a server component now I'm going to wrap this with that theme context provider component which is a client component right so here now I've wrapped that with this client component right is a client component it's wrapping this server component it's using async and then directly in their effect so you may think hey that's not possible because this is a client component and now this product here should automatically become a client component as well right and actually if we go back now everything actually seems to work if I open up the console I don't get any errors so actually a server component can stay a server component a product can is still a server component despite being wrapped here by this client component and this is confusing to a lot of people and maybe that's because we just saw that if you import a server component into another file with used client at the top it automatically becomes a client component as well and that's true but it works different here if you just render the server component within a client component and that client component just takes that server component in it which it's getting here as children and just passing along the children here that component will stay a server component and so product here will stay a server component because we're using the children pattern here right so if I would import the product component in here right so if I would do if for whatever reason I'm doing something like this importing the product and for whatever reason this is rarely what we want to do of course but just as an example if I would do this then yes products here would become a client component because I'm I'm importing this components in a file with used clients it's about the import statements not about how it's actually nested in terms of rendering and that's a little bit tricky right so whether something automatically becomes a client comp components well there's just going to be a compiler looking at your import statement and it's not going to look at how everything is nested here in the in the render tree you could say right so here if I undo this this client component is just taking the children just passing it along and therefore the children can stay a server component no problem and it makes sense when you think about it because very often these context providers they wrap the entire app so here I'm doing is around the product component which is a server component but in practice we actually may even want to wrap our entire app with this typically you would have something like this in the root layout so the entire app is now being wrapped with this context provider so we actually have another children here these are basically just the pages of our app but those pages remember a page component is actually also a Sero component by default and this home component is a server component and now you may think oh I'm wrapping it inside this client component this provider here so the page now becomes a client component right and no that's not true it can stay a server component because this context provider component just takes everything that it gets as children here and just passes that along and that can stay a server component now it makes sense when you think about it because it would be kind of strange that if you use the context API like this which is very typical that you would automatically you know get rid of all the server components in your whole app and you lose all those benefits well that's not how it works right so if I undo this and go back to this so if you use that children pattern for the server component it can stay a server component despite being rendered within a client's component right so you can interweave them as they call it so you can have a server component within a client component right so just to drive home that point because I see so many people struggle with that my favorite button here is a client component so if I write it like this and here we have product here is a server component if I for whatever reason want to put it in there I want this to stay a server component I can do that but I need to open up this client component here I need to accept all that as a prop or children right children pattern and then I can just pass it along here if I do it like this for whatever reason well it's going look a little bit different now but this still works because react can keep that a server component and I can actually just create a prop called example here right I can pass a component and then here we can accept that as a prop example I can just output it right there so if I do it like this we get the exact same result right so you can pass a server component as a prop to a client component and it can stay a server component that way right so you can interweave them right so product is a server component is only running on the server but it's being rendered within a client component how reactor nextjs is able to do that behind the scenes for us is not that important to know from our developer perspective it just works right so a little bit tricky here so let me undo this now if you really want to master react and nextjs by the way I do recommend that you go through my react and nextjs course we start from absolute scratch and by the end we're building senior level Cutting Edge nextjs project so highly recommend you check that out as well number five trying to use State Management on the server side so if we take a look at that contact provider one more time I'm using use State here you may say Ah that's why we're using use client here but even if I remove use State here and let me just make this like a string so now I'm not using a react hook and you may think oh I can leave off use client therefore and the answer actually is no we will get a warning here because I'm trying to use create context and you can only use the context API on the client side right so if you take a look at this overview again here we have our client side here we have the server side so all of those State Management Solutions like the context API or two stand all of this only works on the client side so if I'm trying to use create context I need to add use client here and if I want to consume that contact somewhere I will have to use a react hook use contact this will also not work here on in a server component because this is a react hook react hooks only work in client components right so all of that State Management all of the context API all of these other ones all of that only works on the client side and it makes a lot of sense actually when you think about it the goal of State Management is essentially to keep track of something you cannot keep track of that on the server so for the server it's always about a request response cycle so there's an incoming request maybe it's for a server component or some of these other ones that we'll take a look at in a second next JS takes care of that for us there is some request the server does something with that request and then returns a response after that the server does not keep track of anything from that request so it kind of forgets about it now the browser can keep track of that right cuz the browser will be there for for the entire duration that the user is interacting with the website right so for the typical State Management Solutions like these three you can only use that on the client number six using the use server directive to make a component a server component so this is what I see sometimes so here we have our product component and here we're trying to use async we can fetch directly like this and perhaps we know that this can only work in a server component so what some people do is they try to make it a server component so they do something like use server because that's the the opposite of use client right use client is how you make something a client component and then they think use server is how I can make it a server component but you don't need to do that because everything by default here in the NEX ja app router is already a server component and it doesn't matter how I structure my folder structure here I like to have this components folder outside the app folder that doesn't matter everything in there is still by default a server component so I don't need to do this in fact what you're actually doing is you're creating a so-called server action which we'll talk about in a second those are two different things right so a server action actually exposes a post end point on your server side so this can actually become a security issue if you do it like this now maybe your intention was that this should always stay a server component it should never become a client component for example you may accidentally import it into a file with used client in that case it will become a client component right it will become a client's component as as well but because you're using async which is not possible in a client component you will get a warning anyway when you check your console you will see that warning now you may not see that warning immediately so in in the past I believe nextjs would pop up like an error message in here these days it's like a silent error that you get in the console so if you really want to make sure that this does not get imported into a client component there is another utility sort of that you can use so this is from the next as documentation as well so there is a package called server only so you may want to install that and you only have to write this one line and now if you would import this into a client component let's actually make the page a client component so if I do this now I get this error here right so you're importing a component need server only so now I can fix that mistake you don't need to use this this is not that common for a server component I would say right so typically you would just leave it like this we talk more about server actions and also that server only utility a little bit later as well all right number seven accidentally leaking sensitive data when you pass data from a server component to a client component let's say you're getting your user data from your database and let's say for sake of the example here there there's also a password there now you may pass that data as a prop to some other component and if that component turns out to be a client component so this favorite button is a client component it's getting that as a prop and let's say we're just logging it well now what happens is that that data is going to be visible on the client so here in the console we now see this object here with the password and this may of course not be the intention you don't want to leak the user password of course to the client so next you as apps ex racts away that Network boundary for you so when you pass something as a prop from a server component to a client component it will cross that Network boundary it's going to be visible on the client side so beware of that when you're dealing with sensitive data so you want to have some security best practices and so you want to Hash the passwords and you want to query the database so that you're actually not getting back the password in the first place you may actually want to have a separate data access layer those are topics for another day but it's good to be aware that you can pass data across the Network boundary with server and client components like this all right don't worry almost finished with these gnarly server and client components there's a couple more so number eight thinking that client components only run in the client so this one honestly is very tricky if I log something in a server component I could take the home or let's actually take the product here so if I just Lo console log something here hello from product component so this is a server component right so if I console log something your intuition may be to actually open up the console here in the browser so if I refresh here you may expect to see that here we actually don't see that and that's because this is a server component the component does not run in the browser meaning all of the statements in this function body here they do not run in the browser these statements only run on the server now the result of that render a so-called RSC payload very fancy word is sent to the client that's why we still see well this product title right this is coming from that server component but the actual statements in order to produce that result only runs on the server and so server component is easy it only runs on the server so if you want to see console log here you need to open up the terminal actually because this is where you log things on the server and so indeed here I can see my logs here right right so I bet that every nextjs developer actually made this mistake now this is still easy to understand right all right so now let me make it a little bit trickier so this is a client component so this favorite button I'm now also going to run a console log here so I'm going to say hello from favorite button component I'm going to close this okay so now I'm logging here and now you think ah use client this is a client component so now these statements in the component function body they run in the browser and that is correct right they need to run in the browser because we're trying to hook into that event click event right that happens in the browser so this this code and this changes the state right so this code needs to run in the browser so if I inspect that and if I do console log Let me refresh here indeed we see the log right here right so this works expected now the tricky part here is now if I open up my terminal here where we see the logs on the server side what do we see here we see hello from favorite butzon components which is a client component how is this possible why do we see the log here also here in the terminal for the server side well that is because next s by default will try to pre-render the entire page to HTML so everything that you see on the page and the page is just a component just a w component so in this case it's this home component next JS notice this is a page component because it's in a file called page. TSX which is a special file nextjs will automatically take a look at the default component in there and it will pre-render that to HTML at static side generation SSG you probably heard of these buzzword so it can already generate HTML out of this so then when a visitor comes to our website we don't have to render anything else the HTML is already waiting for them it can be placed on a CDN can even be closer to the user so it's very fast now in order to generate that HTML it has to run all of those component it has to render all of those components meaning all the statements inside the function body have to run right you have to get a result here so you have to run the statements in here so it will try to create HTML out of this so it's going to run the product components all the statements in here they're going to run and then here we have a client component and it will actually also run the statements in here and all of that is being run on the server side right so that's not running within a browser that's running on the server side right so it's just running that once and therefore initially one time this statement is also run on the server side that's why you also see this log here but only once right so as you interact with this component now you can see the state changes which will trigger a rerender of this component now all of these logs are only being displayed here in the browser not on the server side right so the server side is just once and then it's being shipped to the client where it will rerender over over and over again as we interact with the component and so actually really tricky right so nexts we'll take all of this here on the page we'll try to create HTML out of that it will send the HTML to the user and the user is just going to get a bunch of HTML but remember we need some JavaScript logic to make this favorite button actually work so react will take that HTML and it will hydrate it as it's called so it will go over all the HTML it has received instructions that that button should be hydrated basically needs to add that event handler it needs to add the actual JavaScript Logic for that specific button to make that functionality work right so once it's hydrated we can actually interact with it right so a little bit complicated but the takeaway is server components only run on the server client components in the client but also once on the server side right so hope you're still with me and we're almost finished here so hang in there all right so last one about the issues in client and server components so number nine trying to use the window object or local storage or any kind of browser API in the wrong way so we just saw that a server component only runs on the server right easy but a client component well it will run in the in the client right the browser it will run in the browser but also once on the server side because as an optimization nextjs will create HTML pre-render HTML out of this so then when a user comes to the page nothing has to be rendered the HTML is already ready to go so it can it can be served from a CDN it's just a static file HTML file right so the user will just receive the HTML here right so uses browser will receive all that HTML now of course some of the parts in that HTML need to be interactive right so that button for example when I click on it something has to happen the icon needs to be changed and that's what we're doing here we're changing the icon here when I actually click it right so there is some interactivity here so there needs to be some code running and so with the HTML also come some instructions for what's called hydration there will be an instruction for that button here and so react can go to that button can attach the event handlers in this one in this case only this one and so then the user can actually interact with it usually it's pretty fast and then the user can actually interact with it if the user clicks on it before hydration it will not work right but usually it's pretty fast and that's what people mean with hydration very fancy word and that's why the client component will run on the server side now the biggest problem with this usually is actually when you try to use a browser API so something that's only available in the browser like for example anything with the window object right so I can use window. local storage or just local storage you don't have to write window in front of it but it's still part of the window object right local storage is only available in the browser what we're discussing here goes for everything actually on that window object right local storage is just one example right so here in the browser under application here here I have local storage and here I can store some data in the users browser so this is only available on the client this is not available on the server and you think ah use client right so this is a client component so this will run in the browser right in the client so local storage is there so this should not be a problem right so maybe what we want to do is that when the user clicks on that we want to persist that in local storage so then the next time the user come backs we can check local storage and we can check if the user has already favored this item before and so we could do something like local storage. get item maybe we store it under the is favorite key then we know if the user has favored it before and then based on that here we can say yes or no right just a silly example the point here is we're trying to access local storage and as you you can see everything here looks all right we don't get any errors so this looks all right now what happens if I open up the terminal here for the server side if I open up my terminal we actually have some issues so here it says something about local storage is not defined well that is strange because this is a client component so this statement here where we actually try to access local storage should only run on the client right and that's actually not true as we just discussed right so a client component is also run on the server once what that means is that the statements in this function body are run on the server and here we are trying to access local storage this does not exist in that server side no JS environment so therefore here when we open up our terminal when you try to access local storage or actually anything on that window object right will not be available in that server side environment and so you're going to get this issue here so to solve that there are a couple of solutions I could simply rewrite it a little bit so here we could simply just check that when we run these statements in here we can check if the window is defined or not if it's not defined we're just simply not going to access anything on the window object or local storage right so only when it is actually defined now will we actually use this variable local storage and now if I open this up you can see it compiles without error now right so you can solve it with a type of window check another solution could actually just be using use effect so react will not run use effect on the server and so you can access the window object in use effect because remember use effect runs after right so everything here will run all the statements in here will run and react will render this and after that render use effect is is run now when react pre- renders this to HTML it will run all of this and then just stop once it has the HTML it's good to go it's not going to run use effect on the server side now you can actually also just leave it like what we just had so just without type off a use effect just leave it directly in here this will work if it would only run on the client so if you want a client component to never run on the server side it will not be part of that pre-render if it should only be rendered on the client side what you can actually do is use a dynamic import so here in nextjs they give you this Dynamic here and here I can say server side render should be false so then here I should also change this now this component will not run on the server side ever it will just be imported on the client side and will only run on the client side so then we can just access local storage because it's only running in the browser anyway all right so keep in mind nextjs will render client components on the server side as well part of that initial pre-render right so a little bit tricky it's okay if you confused these client and server components it takes some time to get used to them now don't worry almost finished with server and client components let's quickly finish it up here so number 10 uh getting hydration errors so this has to do with what we just discussed so remember nextjs will try to pre-render the page component on the server side this is basically like an optimization now we just saw that if you try using a browser API like local storage since this is running on the server you will get an error here with local storage because this does not exist on the server side this is something that exists in the browser but not on the server side so if you run this statement here this line of code on the server you will get that issue right so if I save here and if I refresh here if I open up my terminal you will see we get that issue and local storage is not defined on the server sign all right so we SED over basically three solutions for that we can pick any of those Solutions so one of the Solutions is to Simply check if window is defined or not right so here I create a variable and then in here we're actually going to access the window object or local storage you can actually write it without window right so now only if window is actually defined meaning we are running in the browser will we actually try to access it so when this runs on the server side here it will run discode it will actually run use State here will actually initialize it with false so is favorite will be false and then the server side creates this variable but then here type of window will be undefined right so here it will not go in here on the server side it will just continue with has been favored before right so it will just continue here without that variable having a value so you have favored this before so on the server side this will be falsy right so here on the server side what what eventually will happen here is we get HTML with the string no right because on the server side this is going to be false it's actually going to be undefined this variable and so we're going to get no here in the turnery so this page on the server what it will result in is HTML so if we actually just think about it here so the pre-rendered HTML they call it pre-rendering so here we're still going to have this H1 right my store right that's going to be in that HTML then whatever this product component produces that's going to be some product title and then in the favorite button we will have a button but we're going to have that uh let's see we have we will have this no here that's the pre-rendered HTML so now that HTML will be sent to the client right and on the client since this is a client component it will be hydrated as it's called because here we will need some logic right so this needs to add event listeners to make that work this HTML will be hydrated only this particular piece essentially this favorite button component will initially not work and so initially it's just some static HTML and then react will hydrate it so that you can actually interact with it it will actually work right meaning the icon will actually be changed so when it's hydrated this this component runs again right so now it's going to run on the client side so it will run here again and now window is not undefined so now we actually will go in here and if this item in local storage is falsy what we will get is no here as well right so let's say after hydration we get the exact same HTML essentially right there's no change so the problem here will start when scroll up a little bit so here what if there is actually something in local storage and we actually see that the user has favor it before so now it will give us true let's say so now this variable will be true so if I go down here it will still give us the same pre-rendered HTML from the server right because on the server side it will always be undefined right it it will always give us no on the server side but in here now in the browser it will now give us true so here in the browser you have favorited this before now it's going to give us yes in this Turner right so now what we will get after hydration is we will get yes here now react will give us a problem because it will say hey the HTML in the browser does not match up with what was rendered on the server side so now if I uh save here actually and I go back to our project here if I refresh you can see I'm getting an error here text content right here does not match server rendered HTML right so this is that hydration error that you get sometime on the server it got no on the client it got yes and so that's something you'll run into sometimes now it's basically a war warning for us as developers so we can double check if we made a mistake in this case we didn't really make a mistake so you may want to use suppress hydration warning if you really know what you're doing and you know it's not a problem this is actually maybe something that there's no way around you can just use suppress hydration warning and because sometimes there's no way around it sometimes for example also if you use for example new date you use new date well when this runs on the server it's going to give me some date and then later when it gets hydrated again on the client this runs again well that that's going to be a bit later so necessarily it's going to be different it will give you a hydration warning well that's there's no way around that so you may want to use well you may just want to suppress that warning you don't get warning anymore you will also get that Warning by the way when you're using incorrect HTML structure so for example if you're using a div in a paragraph even if I comment this out yeah so here I still get that issue here so this will also give you an hydration error and that's because the browser when it sees incorrect HTML structure it may actually try restructuring it autom ially for you and that's not going to happen on the server side so then you also have that mismatch and I would say incorrect HTML structure is actually pretty common now this is honestly the most complex mistake that I've seen so don't worry if you don't fully get it I I think even experienced developers are going to struggle with this all right let's wrap it up here with number 11 incorrectly dealing with third party components very often actually you're going to use a third party component let's say you installed some mpm Library react amazing Carousel so you import the component and then you want to use the component now maybe maybe this component is using a react hook or is hooking into events right on click on change just like we did here actually in our favorite button our own component here here we were using on click and here I'm using a react hook so that is only possible if it's a client component so what we did here is in our own component file we can just add use client now what you're going to see with many thirdparty components is they're going to give you a component like this and they're using react hooks but they didn't add used client to the file yet right very simple but they they just didn't do it yet or maybe they have some good reason for that so that means if you try using that in a nextjs application this component is using a react hook or event handlers without use client and so you're going to get an error now with your own component you can just open up the file right so favorite button it's using that as well I can just open it up edit here that's not what you do with a third party component I cannot just open up like the the source code basically and add use client right so here what the next as do actually recommends that you just create like a wrapper component here we actually don't need to create a separate component we can actually just export that as the default from this file because it's just based on the file actually so the only thing we have to do here is make sure we are importing that into a file with us client and then we can immediately export it as the default and then if you want to use that CA cell you import it from this file right so now I would import it like this so now since this component is being imported into a file with use client it will automatically become a client component as well so if it's using react hooks or event handlers you're not going to get an issue anymore so this is something you have to do with third party components sometimes times so that's if they're using react hooks or event handlers now what if they're using a browser API we just saw that there are some additional issues essentially in that case because this will run on the server side first so if that Carousel if it's using a browser API like local storage use client may not be enough because even client components are rended on the server right and I cannot just open up the S like like the source code of this component and change that so how do you deal with that well in that case you're probably going to have to do a dynamic import of that third part component so that's basically the only way to make sure it only runs on the client right so that's how you can deal with third party components properly in nextjs so that's pretty much everything I had to say for now about server and client components it's a new paradigm so there's a bit of a learning curve so don't worry if you're a little bit confused I have a complete react n nextjs course in case you really want to master the latest react n nextjs highly recommend you check that one out all right so next I actually want to talk about data fetching and data mutation so let's go back to our diagram one more time let's take a look so here we have our overview now your traditional data fetching what I mean by that is just get requests and in the latest nextjs most of these you want to do in your server component and then there are also so-called data mutations so these are basically your traditional post put and delete request most of these are now going to happen in your server action so what about these route handlers or or API routes what is the use case for them in the latest nextjs it's mostly not going to be these two right so I've seen some people they think you still have to create a separate API route well that's not the Cas you can just do that with a server actions actually much easier you can just write a function instead of spin up a whole API route and let me actually write this like this let make this a little bit bigger so a common use case for these route handlers is actually web hooks right so maybe you're using stripe and there's a payment stripe will send a request to your server so that you can update your database well you can have an API endpoint for those web hooks that's what you typically use this for but for your traditional data fetching or data mutations you typically don't spin up a separate API route anymore right so number 12 is actually the mistake of getting data by using these route handlers so for example traditionally if you want to get data from your database for example maybe you would create an API endpoint and then in there you would fetch your data let's say you're using Prisma as an omm so here you would allow a request and then you would get all the products from your database with Prisma as your omm let's say and then you would return that to the front end as Json data right and then if you actually want to hit that API endpoint maybe you would use fetch right and then you would do something like SL API SL products to hit that API endpoint and then you would get back a result and then here finally you would have your products now this technically works right so you could technically from your server component make a fetch call to your API endpoint and then it will return there but that's not necessary because a server component is also already running on the server side so what you're doing in a route Handler you can do in the server component directly you don't need to spin up a separate API endpoint for that right so what I'm doing here this call to my database I can do that directly in here right so I can replace all of that and I can just do it directly in the server component I can delete this API endpoint Al together I'm actually going to delete everything here and I can just do it directly here in the server component right so no need to use a route Handler for getting data you can do getting data directly in the server component here I'm using an omm I'm not using the fetch API but we saw before in this product component which is also a server component I'm actually using the fetch API here to get data from some external API and that's also possible and I could do the fetching in this component I could also do it in the page component here and then pass down the data to that component some people like to fetch the data in the page component because then you have a nice overview of all the data that is being used on the page but it's also nice to fetch the data in the component where you're actually going to use it so in this example we're doing it directly in the server component where it's actually used and we don't have to spin up our own route Handler to do that we can do these get calls directly in server components mistake number 133 thinking that it's a problem when you get the same data in multiple places so let me show you what I mean by that so here we're making a fetch call in our product component so here we're getting some product information we get the product information here and the only thing we're actually using here is the title so I may actually also should have called this component product title or something like that now let's say we have another component for the price right so here I added another component here if I open this up we can see it's also a server component async and here we want to output the price of that same product right so here we're outputting its title and here I want to Output its price I need to get the same data so I'm making the exact same fetch call in this component as I'm doing here and here I'm then outputting the price and so now I also have the price of this product here on the page so you may think uh oh what we need to do here is we need to pull it out of these components and you know we have to sort of lift it up right just like with you state when you have to lift up State here we have to lift up the data fening perhaps common ancestor here so that we only make the call in here perhaps and then we can just pass the data down with props and then here I can remove it from here as well so now we would only be fetching it in displ now actually you don't need to do this and this would also be a problem because well it's still a bit easy here but what if this price was nested in some other component you would have to do a lot of prop drilling to get the product all the way down there and remember you cannot use State Management on the server side right to solve that prop drilling we don't even have to do all of that we can actually just fetch directly in the place where you need the data so here in product if I need it here I can just make the fetch call and here in price I can make it fetch call now at first s this looks duplicative it's like we're making two fetch calls for the same product data this does not look optimal now I have some good news this is perfectly fine because there is caching for you behind the scenes actually by both react as well as nextjs so what react actually does is if you have a fetch call like this it will not run twice in the same render pass so let's say the Pages being rendered so react can actually already see that you make the same fetch call so it will only make that fetch call once right so this will only run once and the result of one of those fetch calls will simply be used for the other one as well in the same render pass as it's called now in addition to that there is actually also the nextjs data cache so nextjs will actually store the result of this fetch call in a so-called data cache and that may actually be the most powerful cache in nextjs because that will persist even across deployment now here I'm making the fetch call like this but often in practice you actually have utility functions for this so you may actually create a utility function called get product in which you do the actual fetch call and then you would use that one to get the actual data in here right so you would do this in here and then in here you would do right so I need to import it here and here as well but this doesn't change anything right so here now I'm using that utility function instead of the fetch directly in here but this doesn't change anything right but you do it through some function or directly use the fetch API in there that doesn't matter it works the exact same so this is perfectly fine as well so there's lots of caching done for you behind the scenes I'll have a separate video on that and one of the benefits of that is that you can fetch data directly in the place where you need it now that is the case automatically for you if you're using the fetch API so react and xjs will automatically cash fetch API calls now if you're using an omm that is not the case the idea being that those ORS may have their own caching Behavior so if you want to have that for the those or as well you may want to use the cache function from react which will D duplicate it for every server request but that's temporary right it's just for one server request coming in the server side will do something with that request right maybe multiple server components are trying to get that data so react will will cash that for all of them will only run at once and then the response is sent and then it's over it doesn't remember anything it just removes the cash but there's also that data cache from nextjs so at time of recording that's still unstable but you may want to use the unable able cache function in that case it will be put in an nextjs data cache a very powerful cache that persists even across deployment so then your omm calls are actually also cached right this is a bit of an advanced topic and I'll have a separate video on this and actually here I'm getting all the products from the database so a more appropriate name would be get products in number 14 getting waterfalls when you're fetching data so I modified the example again a little bit so now let's say we're actually fetching the data all of the data here in the homepage component instead of fetching the data in the product component I sort of lifted it up to the page component here just for demonstration purposes right so I created a utility function for this get product this is the exact same as I was doing in the product component before but very often on the page we don't have just one component that needs data we have well sometimes a lot of components that need different types of data for example here we may also have ratings we may have testimonials WR comment all sorts of different data could be on the page and here is for example where I'm making a another get request right get ratings and that is some other URL and I'm getting the data here and then I'm passing that to some component to actually render something and sometimes these components are nested inside of each other but for this example it's easier if I show you it like this so the problem is you may actually already see it before we can start fetching the data for Ratings we have to wait until the previous one is finished right await so with async a the way it works is this align will not run until this has been completed right so the way it works with sequential data fetching is that you have your first request here it would be that get product and then only after that once that is finished can we start making the next request right in this case get ratings right and if we had another one it would have to wait until that one was finished if they each take two seconds in total this would take 6 seconds 2+ 2+ 2 6 seconds in total and sometimes there's no way around it right if this data fch depends on some data from here right you need some data from here in order to make this fetch call there is no way around that now here that's not the case right so these are two independent data fetches right so this is also called a waterfall effect right so it looks a bit like a waterfall now I wish I could show you that in the network tab here in the browser but this is actually a server component so I don't see that in the network tab in the browser right so I can show you that that way so ideally if these fetch calls do not depend on each other they are independent ideally we can just start making them all at the same time right at at the beginning right so we don't want to have that waterfall effect we don't want to fetch them sequentially we want to fetch them in parallel right so all at the same time so now if they all Take 2 seconds well they all start at the same time so after 2 seconds they are also all finished so now the total time will be 2 seconds right so if you can try doing parallel data fetching so how would we do that here so what you could do is actually use promise. all right so instead we could do this right so promise that all and then here an array of all the promises since these are async functions they always return a promise so I just have to call them not await them in here this will result in an array of promises and those promises will all be run at the same time and then the results will be in here now one of the downside with promise.all is that for example if get product fails or rejects This Promise reject it will reject for the entire array here so get ratings would also be affected by that so some people will argue that there is another method here promise that all settled is actually a little bit better because this one will always resolve even if one of the individual ones reject the other ones can still resolve and those data can then still be used right so I think this is good to know when you're doing data fetching now by the way that waterfall with data fetching can also occur if you structure it a little bit differently so maybe you're not doing all of the data fetching directly in the page component here maybe you're doing that in the individual components so here in product maybe I'm fetching some data here right just utility function it's getting some data and we need towait for that and then here I have the other component of ratings which may also do some data fetching right get ratings just like what we saw before but now this is nested inside another component that's also doing data fetching so that fetch in there will not start until this one has been completed right so now you also get a waterfall effect right I'll actually have a separate video on this cuz it's quite tricky so you may want to restructure things so you want to be aware of how you're doing the data fetching so in this case to avoid the waterfall you may need to trigger that data fetch a bit higher and then if it's using fetch for example it will be cached the first time so then later you you can just fetch it wherever you want that's a little bit complex I'll have a separate video on that all right so what we just discussed was all for getting the data now let's talk a little bit about those other actions you typically want to do in your data you want to add new data update data delete data fancy word for these is called Data mutations so mistake number 15 is actually that people will try to submit data to a server component or a route Handler so first of all you cannot submit data to a server component so just to show you what I mean by that so here we have our page and I added a link here right so we still have our page here just like before but now I added a link also a component in nextjs has certain benefit right so on this page here we are getting data right so we are getting data so now what I did is I created another page where we can submit data so we'll have a form and I added this link here so we can go to that page right so the route for that page SL products so you can see here I created a products folder and another page. TSX file there so on this page let's actually go there and see what we have there here I have all product and what I want to do here is I want to be able to submit something on this page so what do we have on this page here we have all product and then here we are actually also getting data so I actually added a database in this case we're going to use Prisma to get all the products from our own database right so we're still getting data here as well and then mapping over that here but since there is nothing in the database here we don't see anything here but then what we can also do on this page we have a form here and we can actually submit data right and then ultimately I also have this link here to go back to the homepage so that's this page now here when you have a form with just one input and I want to add a product to my database right so if I add just some gibberish right test if I click on this typically what you want to do is you want to submit it to your back end and so you would say add products and when the form gets submitted you would do something like onsubmit and then you would do maybe a post right so something like API product method post right something something like this you would have your body and you would try to submit it right so in nextjs some people still do it that way and sometimes they want to kind of submit it to their page component or something like that that's not possible right so you're not going to get props from your that's not it's just not going to work like that sometimes they will try to submit it to a route Handler like just like what we saw before so you would have API products you would send the data to your route Handler and then your route Handler would add it to the database you don't need to create a separate route Handler because these days we have server action so with these server actions we don't have to create a whole API endpoint and then use Fetch and then awkwardly make sure we have the correct URL we can remove all of this instead of using onsubmit we can use the action attribute in nextjs and here I can just specify a well basically a normal function and I call that function add product and there's just some function here this is a so-called server action now I like to collect all of them here in an actions folder where I can have all of them in one place here is where I defined that function so here I have a folder for all my so-called actions I like to create a separate folder and then just one file usually with all my server actions so I have all of them in one place and this is basically just a normal JavaScript function in here is where I'm going to add something to my database right so here I have the use server directive this makes this function a so-called server action right so you don't use use server to make something a server component you use that use server directive to make a function a server action so now what I want to do when I submit data or when I update data or delete data usually you want to use these functions right so here if I specify a function for a form and I submit the form nextjs will actually give the data from that form as an input here to that function which I can then use to update my database and I don't have to create a whole API endpoint I just work with normal functions like you would normally already do in your app and nextjs once again is abstracting away that Network boundary so nextjs will make make sure the data actually goes to the server and is actually well you could say submitted to that server action and it's a function that only runs on the server and next you as well make sure that when the form is submitted actually submitted to that function running on the server and so we get that data right here and so we can update a database so Prisma allows me to inspect the database so right now you can see in the product table here you can see I have nothing yet that's also why here we don't see a list right so if I close this again if I go to products here this page here so here we are getting all the data as well and we're mapping that over here but you can see there's nothing in the database yet so we don't see anything let's actually first try to actually get the data from this form in my browser here to the server side right so let me actually show you how this would work so I'm going to submit now and since I specify that function for Action here it will get the form data just one input here which I call Title it will get that right here and I can immediately insert that here in the database and so let me show you how that would work if I just say test here if I click on ADD product and now I clicked here we don't see anything here but now if I go back to my database and I refresh here you can see there's a new row here with title is test right so pretty cool I think because we don't have to create a whole separate API endpoint nextjs abstracts away that whole network boundary nextjs will make sure that the data here from the form in my browser is actually submitted to the server a lot of people talk about server components but in my view it's actually these server actions that are the biggest Innovation also because that works that the way I specified this here this form would work even without JavaScript enabled so the fancy word is Progressive enhancement and it's also integrated with some powerful react hook so there is something called use for status so we can get the pending state so we can show a loading indicator for example use form state is typically used for an error State uh use optimistic for optimistic uis so very powerful actually and so this is what you want to use for those data mutations now by the way I have a separate file here with use server at the top you don't have to put these in a separate file it's just what I like to do technically you can also just specified directly in this file here where I would use it right so I could actually just create a function in here and then use it here as a server action and then actually you do need to add use server here at the top right so I could also Define it in the component like this you will see this sometimes but I think it looks a bit messy I think it's cleaner to separate this out into a separate file with use server at the top so in the previous example I added this one test uh to the database right that's what we see here in the database and so when I load the page now on this page we are getting everything from our database I can do it directly here in the server component and then I'm mapping over that here that's now what I'm seeing here now that's if I actually refresh here now when you add something you will not immediately see it here so this is mistake number 16 getting confused when the feud does not update after a mutation right so if I do another test here let's say test two if I add this product I just click and now if I inspect my database you can see that I added test two to the database now you can see it's not displayed here in the list yet okay all right now what happens if I go to the homepage and now I come back to that page again you can see it's still not displayed here in the list and that is actually because of caching right so nextjs will cache the result the render result of a server component and these pages are just server component so once this page has been rendered the result of that so-called RSC payload will be cached so the next time you come back actually nextjs will not make another Network call to render this page again it will actually just use that server component payload from the previous time which is actually a client side cach in nextjs I'll have a separate video on nextjs caching it's so complicated but the point is it's still cash from the previous time so if you want to make sure that you bust that cash when some data has been updated you want to make sure the updated data is actually displayed you can do that very easily in these server actions as well by using the revalidate path function that nextjs gives you right so you can see it's also coming from next cache so you can bust that cache after I have updated the database and the data has been updated I want to make sure that the view also gets updated and when I come back I can already see it but let's actually try this out so now if I say test three if I now click here and actually you can see I don't even have to navigate even when I stay on the same page nextjs will make sure that the view is updated properly I think that's actually a very nice user experience as well now you do want to be a little bit careful here with the path that you specify here so here I'm busting the cache for the/ products route so this page falls under that and so everything that's cached here will be busted by that if you're not careful and you would just do like something like this you would essentially bust the cash for your entire app which is not necessary because maybe we're only using the server action for one page right so here for example I would only want to bust this part of my app so you can be a little bit more granular mistake number 17 thinking that we can only use server actions in server components right so here we are using this server action in a server component right so we have products page which is a server component and here we have the form and here I'm using my server action so this works perfectly fine and in the server component you can use the server action of course right so this is also typically the examples that you'll see when people talk about server actions they'll they'll take a form as an example however you can actually also use server actions in client components actually works perfectly fine that's not a hack or something you can use these wherever you want let's take a look we have that all we have the homepage if we go back there we have this favorite button here right if you go here so here I have my homepage I have a favorite button here which is a client component now if I want when when the user clicks I can invoke that server action as well right so when I click I want to run a function and what do I want to do in that function well I want to let's say invoke that server action right so it's called add product and add product I can just import it here I could also pass it as a prop and I'm just going to import it here now what am I going to pass as an input but so now I'm not using it in a form so here we're not going to get form data I can just actually just pass the title of the product and then we can just use that directly in here right let me actually type that as well it's just going to be string so then here I can just say test 10 so now when I click I invoke the server action with some argument that's what we will receive here in the server on the server side right so next CH we'll make sure that this argument is passed from the browser to the server that we actually receive it here and then we insert it into the database so let's see if that works right if I click on the favorite button it should be infoed I'm going to click right now I click all right so now let's go back to products here and you can see we indeed see test 10 here as well and so you can inoke these server actions in client components as well and we can even get a pending State as well by using used transition actually and wrap it in a start transition but let me undo this for now so mistake number 18 is actually forgetting to validate and protect server actions all right let's go back to the form example one more time so here I have my form and I added this action here add product so here we will get the form data and we can then insert into our database so this form is here in my browser right so I will type something here test 20 and when I submit here nextjs will automatically make sure that this input here that I put in here is actually going to the server side to This Server action here and so we can insert it right here and I can actually show you that in a network tab as well and so here I have my network tab let's see what happens when I submit the form and the server action gets invoked let's see what happens I'm going to click right now all right so you can see some things happened we can ignore these but you can see here there was a fetch call actually if I click on the first one here you can see there actually was a fetch call I'm not making a fetch call myself it's nextjs doing that for us behind the scenes automatically and if I make it a little bit wider you can see there was a fetch call and it's actually using the URL on which that server action is being used so you can see we have a URL here/ products this is the location where the server action is being used and it's a post request right so we can see here that when you create a server action and you're using that you're sort of exposing a post API endpoint on the location where you actually use it right so you don't have to create your own API endpoint nextjs does that sort of automatically for you when you create a server action and so then when a server action is actually being invoked nextjs will automatically make a post request to that uh location but this is very similar and you may even say it's the same as exposing a post API endpoint on your server which means what we get here as data could be anything because other people may also send requests right somebody else could simply make a post request to this URL right and they could submit whatever data they want right and of course you as a developer or other developers could invoke This Server action in different places as well so the data you get here we are sort of assuming here it's going to be form data but it is not necessarily true right we already saw that if I actually use it outside the form it's not going to be form data it's going to be something else so before you even do anything with that input on your server side you want to be very careful you want to validate the incoming data right so you want to use something like Zod to validate that what you get here is actually form data so you may even want to use the unknown type in typescript which is a more accurate type in my view because we don't really know what this is going to be we I mean here if it's actually like this it will indeed be form data but if it gets invoked somewhere else or somebody else makes a request to this we don't know if it's going to be form data it could be anything actually since we don't know the proper type is unknown and therefore we cannot just assume that we can do do get on there and get a title we want to get certainty on the shape of the data also for security reasons we want to make sure that we're not you know doing anything with our database without exactly knowing what we're doing because these server actions are very similar now to just a normal JavaScript function that you can just invoke just like other functions right nextjs abstracts away that Network boundary so the other mistake that people make here is simply forgetting to add the authentication check and remember a server action is essentially just a post endpoint on your server right so other people could technically hook into that as well so you want to make sure that when that function gets called just like with your traditional API route Handler that you're actually making sure that the user is properly authenticated and also authorized right so here I'm using kind I'm actually a brand ambassador for kind it's a paid sponsorship but I think it's a wonderful solution for authentication and this would be an example of how you could do that check and so you can check if the user authenticated and otherwise you can redirect them so make sure you also protect your server actions mistake number 19 using the used server directive to make sure something runs only on the server so we just learned that if you use the use server directive you're creating a server action right so all the functions I would put in this file will become server actions which means as we just saw you're essentially exposing an endpoint on your server that other people can hook into and so you want to be a little bit careful with that and that also means that if you have let's say a utility function now let's say you have a get product as a utility function you use it in some places just as a utility this is just a utility for for getting data we're not updating data so it doesn't need to be a server action it's just nice to abstract away this logic here in a separate function right very standard very typical now you may say oh I only want this to run on the server so what some people are tempted to do is to say use server well that's not what you want to do because now this becomes a server action that's not intended like let's say you don't want to use this in a client component for example so you say well it should only run on the server what some people are tempted to do is to use the US server itive to make sure it only runs on the server so it's true that this will only run on the server and server action runs only on the server but it also exposes an endpoint essentially so that's not your intention here right if you want something to only run on the server you may want to use that server only utility and you may need to install that so mpm install server only this is basically like a utility mpm package that you can install and then just import like this now if you try using that in a client component you will get a warning and you can fix fix that and then you may also want to call the file in which you're using it not just utils but server util where you can put all of your utility functions that should only run on the server and it's the same with server components right so if you have a component and it should never become a client component what you may be tempted to do is say well use server right I've seen some people do this use server right so this has nothing to do with server components server components are already the default in nextjs so with you server you're now creating a server action right so again you may instead want to use that server only package to ensure that this does not get imported in some client component let's talk a little bit about Dynamic routes prams and search prams so mistake number 20 is actually misunderstanding Dynamic routes which will give you prams and then there's also something called search param so here I modified our project a little bit so here now I'm on a SL product slash4 route so this last number here is actually an ID and this is very common right where you have some kind of ID in the URL and based on that you well maybe you want to fetch data for that particular ID right so if I do number three here we get our men cotton jacket back if I do number five I get a different one if I do number six I get a different one as well right so this is called right so this is actually a dynamic route in nextjs it could technically be any number here right so this is more Dynamic so the way it works in nextjs if you want that you need to create SL products but if it can change you need to write that part in square brackets right so here I'm calling it ID I could could call that whatever I want and then here we have another page. TSX so this page will be used for all the different possibilities here right so if I use number 10 this page will be used if I use number five this page will be used if I use number three this page will also get used because it would be too much work if we had to create a separate page. TSX for every possible number here right so that's not how it works we just have one page. TSX and you specify this here to nextjs with square brackets based on what's in the URL we want to output something else right so we have to get access to that in that component here and we can get that with the params prop and so the params prop will hold the actual value from the URL you do not get this prop in other server component right so you get it here in a page component but not in for example our product component here this is a server component as well I do not get perams here right so next chance does not give me params here in this case only here in the page component now that will hold the actual number from the URL so if I want to get access to that number in the URL well I can just pass it as a prop I can I change this product component a little bit so now it's accepting an ID Pro so instead of always getting that number three like before now it's just based on what's coming from the URL so this would be a little bit more realistic right so let me actually just output that here on the page product ID params ID so now we can see it here as well right so now if I make it five it's five if it's six it's now it's do ID because that's how I named it here in square brackets but if I call this blah blah in square bracket record I can access that with DOT blah blah right so whatever name you give it here is how you should access it here there's also something else called search per Ram so here you can do question mark and then this is usually used for like different versions or variants or filters or sorting parameters so here on a product page you could have something like color is green this is nice to put in the URL because if I would copy this and share this with somebody else they can just paste that URL and they should also see the green version of of a particular product I have a separate video on this actually so we also want to get this from the URL now to get this from the URL you don't have to do anything with the file system you can just get it directly here as well and this is called search prams this is something that you also do not get in for example this product server component it's a server component but you do not get perams or search prams in here right so here you only get that here in the page component here right and then if I want to Output that you need to use search per Rams so then here we see green and then based on that I can do some logic or render some marker and so these are two special prompts that you do not get in any server component usually you're going to work with these with a page component and just to type them properly it always looks a bit clunky but this is an example of how you could type them all right now with these search prrams you can run into some issues mistake number 21 incorrectly working with search param so I changed the example a little bit I removed the params so we don't have a dynamic route anymore but we still have search per Rams here in this case we have the color here in the URL L and it's currently set to Red so this page here will receive search per Rams it will receive it right here and then we can just say search perams as color that's why we see red here now I also added this color component here and the only thing it holds is just these three buttons here right so here we just have three buttons and when I click on red we want to update the URL so let me actually make it a little bit wider so you can see color is red when I click red it should be red it's already red if I click on Blue it should become blue and we can do that in nextjs by using use router or the link component actually but let's use the use router here I can add something here to the URL right so I can say SL product then I can just well add the search pram like this color is blue right just a simple example here here color is green and so that's how I can change the url here you can use use router actually the use router hook update the URL or you can even use the link component actually to update the URL right so updating the URL is typically not the problem the problem starts when you want to get the search per Ram from the URL right so it's always about reading and writing right so writing here is not the issue it's reading the search pram that you may run into an issue so we can read the search pram by using the search prams prop in a page component that's what we're doing here the downside with this is since this page component is a server component it only runs on the server right this is a server component on the server side only so when the user changes something in their URL and you want to be notified of that or you want to work with that on the server side well you're going to have to send that to the server side so there needs to be a network request and that is actually what nextjs will do when you update the URL it will send a network request so that this page will receive the new search for Ram and again render a new result let me prove that here to you so here if I now open up my network tab if I click on green you can see there is a network request I'm not making this fetch call myself this is what nextjs is doing for me behind the scenes you can see there's a request URL with some RSC identifier and here in the payload it sends the uh query string that's so color green and it makes sense when you think about it because if you want to work with search programs here well this only r on the server yeah so it needs to be sent to the server right there's no way around that so the reason you may not want to do it like that is because you need to wait until you get a response back from the server right now here it's very fast because it's all local on my computer but when you push to production there could be a delay here right so when I click on red here it may take some time before you actually see the result because it needs to make that network round trip so when you're reading the search for Rams with the prop that's something that you need to keep in mind there is another way of reading the search per Rams which is with to use search per Rams hook if you need the search per Ram somewhere you don't have to use the prop actually you can actually also use this hook now remember you get search for Rams and then actually you need to use a getter like this and now we're getting an error because we're using a hook so this hook will actually read from the URL client side that's not possible on the server and so that's why in this case if we want to use it like this we have to make this a client component so this works as well but this will not send new network request right so here if I click you can see there are no new network request this is another way of reading the search per Rams in that case you do need to make it a client component typically not recommended for the complete page as we've discussed before so this is just a silly example but this is preferable in many cases over using the search for Rams right so we probably don't want to use this hook directly here in the page component you probably want to use it somewhere more deeply nested towards the outer edges of your component Tre so you're not necessarily making a huge part of be affected by this used client boundary now if go back one more time so this will send a new network request so there's an incoming Network request with the new search prams it will render a new result and since this is a server component that RSC payload and the result of this render will actually be cached it will only send a new network request if it's not in the cash right so initially you may have a lot of new network requests after you click around you can see there is no new network request so there is some caching so it's not the end of the world it is something to keep in mind let's talk a little bit about suspense and streaming they sound very complicated but as you'll see it's pretty straightforward it's also very Innovative actually so I think these are pretty cool features in the latest nextjs I changed a little bit so now we just have an H1 and we have a link now to go to the actual slash product route so here I have one SL product here right we have another page for that and now this is where I'm doing the data F right so I moved it out of that product component so let's actually go there so here you can see I have my product page here we still have that title and I still have my favorite button here right so I just moved it to/ product and I'm doing the data fetching in here but it doesn't matter just to make this example a little bit clearer nothing wrong here right it looks well pretty fast when I click there it goes pretty fast right so here if I click on go to product page it's pretty fast okay now it's fast because this is all local right so remember that when you're coding locally everything will necessarily be pretty fast because when there's a request to the server side well it's on it's on your computer right it's all being simulated on your computer essentially now in the real world when I go to product page there will be a network request to get that page page nextjs is actually just well a component it's just a server component here and that is the page right so this needs to be fetched and then it will be displayed here well that can take some time and then in here what we're doing is we're making another fetch call we're awaiting that and then once that's finished it will render something it will result into a so-called RSC payload and then it will be sent to the browser again so that we actually see it I but it's all pretty fast because it's all low go now let me actually add some delay here right so just Bas this is just a way of sleeping essentially in JavaScript just a 3sec delay we're awaiting that so we need to wait 3 seconds before we can move on to the next statement right so now if I go back here if I now try to go to the product page I will click right now and now I'm waiting and waiting and waiting and waiting and waiting and only now do I get a result this is more realistic this is mistake number 22 is you're forgetting to think about loading States because you're coding locally and everything is fast for you but that is not necessarily the case so what you want to do in this case is you want to use suspense okay so sounds very fancy right and the way to use that is actually with another special file so page. DSX is special but there's another special file and other ones as well called loading. TSX and whatever component you're exporting here as the default will be rendered while we're waiting there right so if I just say loading dot dot dot this component because I'm using loading. TSX and at the same level of that page this one will be displayed while we're waiting for that page file so if I try this one more time you can see now I'm getting loading dot dot dot for those 3 seconds a little bit more and then finally product page component has finished rendering and it will be streamed in right so if we have something else that will if we if we had like a header or footer on the page it will not be affected by that it will just be streamed in squeezed in between there the RSC payload will just be rendered like that and so then loading disappears again right so that is essentially suspense and streaming so that suspense is essentially just a react component but next you has ABX that away from you with this loading convention right so here when you use loading it will wrap your page at the same level on which you're using the loading in a suspense component here so page will be squeezed in there so that's a much better user experience so don't forget to think about the loading States all right mistake number 23 not be in granular with your suspense boundary so what we have right now is with loading you have a suspense boundary wrapping the entire page right so if I go to that page if I click on there you can see I'm waiting I don't see anything else I don't see this H1 I don't see the favorite button right so let's say that the reason that we're waiting for for it is actually because of this fetch call here and so let's imagine that the fetch call actually takes 3 seconds longer and we're waiting all the we're waiting all the time for this for this data here that that which we only need for this product component but meanwhile it's also blocking the rest of the page right so when I do one more time if I click now you can see I would like to see the H1 as a user it would be nice to show immediately that the user is going to be on the product page I think that would be a better user experience and it will also be nice to show the favorite button and other things on the page so in this case we are essentially only waiting here for this product here so what you may want to do is not fetch data in the page component you may want to move it down to just where you need the data so if I open this up and so let's actually copy all of this and put it directly in here and now we don't receive this as a prop we just have it more nicely encapsulated here we can remove this and now of course we still want to have a loading stage so I can wrap this individual component with a suspense component right so with loading the TSX next to S reps the entire page with your with a suspense component that's not what we want to do because it blocks the entire page and so I'm going to delete that I only want to have a suspense boundary I need to import this for this individual component and you need to specify what you want to show as a fallback while it's being suspended right so basically while we don't have a result yet and that's why we can have an async component right so we're essentially waiting for that promise to resolve you could say right so now if I go back here if I refresh if I go to product page you can see we immediately see the H1 and other things and then we just see loading dot dot dot just for that one specific component that actually needs a loading state right so we don't have to block the rest of the page in case you only we're waiting essentially for something that this individual component needs so you want to be granular with these suspense boundaries right so now when I load the page you can see we immediately see product page and other things and then it's just that individual component that actually needs some more time to fetch data that will show a loading state so this is a better user experience mistake number 24 putting this suspense in the wrong place so actually very common so you need to put it essentially higher up than where you're actually doing the awaiting right so here we are awaiting a bunch of stuff and this is sitting a little bit higher this is why it worked now if I would move it down into the component so I remove it from here and now you may think well I need to make it part of the component right it would be maybe a little bit better capturing it like that right then here I removed it from here so now wherever I use it it's always wrapped in a suspense boundary right so that's how you can view it maybe it makes sense when you think about it but unfortunately when you try doing that you can see I clicked here but I'm waiting for the entire page to load now so this unfortunately does not work because it's kind of sitting below where you actually do the awaiting stuff so it needs to sit higher than that right so you actually do need to wrap it like that when I click right now you can see we have loading dot dot dot mistake number 25 forgetting the key prop for suspend this is actually a tricky one and you'll run into this sometimes especially if you're working with for example search per Rams so I just changed the example again a little bit here so we are reading the search per Rams from the URL and that's what I'm passing to that product component right so then it can get the right title for that particular ID and I have nicely wrap this in a suspense right so just like we saw before still have my favorite button here here I have some links I could also use buttons with use router I'm using the link component this time doesn't matter I'm using the link component this time to to update the URL I'm using suspense here right looks good so now when I load the page we indeed see loading dot dot dot here while it's fetching that data right so here we're still fetching the data I actually Chang it to 2 seconds waiting that and this may also take some time so then eventually you get a result and that will be streamed in right that will be streams in here so in the meantime while we're waiting for that it's going to have a paragraph in the HTML okay so all of this is working when I load the page you can see it's working okay now what happens if I click on view product with ID is4 if I click now I just click nothing is happening right now nothing is happening only after a couple seconds does it get updated if I click on view product with id5 nothing is happening here and the reason is actually that is that react doesn't know when the ID changes that this suspense should be retriggered right so this suspense right now is only triggered and when we just load the page after that it's not going to trigger again you need to tell react hey when the search PR Rams are different we want to trigger suspense again so you should consider it to be a different product it's going to be a different product when the search for Ram is different so the way that you specify to react that something is different is with the key prop right so we also see the it often when you do like a loop in react to render something but here you sometimes you also want to use it to uh tell react that something is unique so here it's a unique by ID in the search param so when that changes it will re-trigger that suspend and so now when I load the page with IDs three we indeed see loading dot do dot but now what happens if I click on this one if I click on number four you can see it gets re-trigger if I click on this one you can see we see loading do do do right so this is actually really tricky one so don't forget to use the key prop in case you want to re-trigger the suspense let's talk a little bit about static and dynamic rendering so I changed it a little bit again so I have this homepage here that's just this one page nothing fancy going on just like what we had before and we still have a product page also nothing fancy going on just an H1 so these are the two routes I have right now now these routes that I have here we're not using Dynamic routing right so Dynamic routing is If part of the URL can be anything essentially right so we you use square brackets for that that has to do with routing right so Dynamic route now there is also the concept of dynamic rendering and static rendering let me show you that so here I can run a build what I can do here is I can say mpm run build and it will create an optimized version of my app and one of the things it will do you can see here generating static Pages it will go over all of your pages so in this case well we can actually see it here right so when you run mpm R build you get some useful output here actually so you can see my homepage has been there is that empty circle icon and that means here it shows you the legend here below it says static pre-rendered as static content so what that means is that this homepage here this homepage component it was run so this ran and it created HTML out of this which means that if somebody goes to the homepage now in production this component doesn't have to be rendered again because the HTML has already been rendered here as part of the build right that's optimal so the HTML that was created here and actually next chance we'll put it in a folder here in next so there's some HTML for that particular page in here somewhere we can actually put that on a CDN so every user that will go to the homepage will just immediately be served that HTML page this component here does not have to be run again right so that's static rendering which is actually what we want because that's optimal we can just run this once and then just serve it to everybody that comes there we don't need to run this again right so that's static rendering and we can see here that slash product is also static right you can see that symbol here so this page right isn't doing anything fancy so it makes sense that we can already create HTML out of this and then just serve that whenever somebody goes to SL product right so we can just serve the same HTML over and over again this does not need to run again right because we're not doing anything fancy here we can just generate HTML once out of this and just put it in the CDN and just serve it over and over again and so that's static rendering that is what we want and you can see actually by default next chance also creates a not found page but we can ignore that for now now there is also something called Dynamic rendering so what if we cannot just generate HTML out of this once maybe it depends on let's say the user who is logged in right so we may want to generate a different homepage maybe with like their avatar on top for the user who is logged in in that case we cannot just generate that once because it depends on who's currently logged in could be many different users right so we cannot just generate the whole page once in that case we have to do Dynamic rendering as it's called which means that when there is an incoming request we will not just give HTM immediately back we're actually just going to run this again so that it will be tailored to the currently logged in user which will take more time but there's no way around it so if it's possible you want to keep that static rendering because it doesn't have to run over and over again right so that is static rendering now the other option is dynamic rendering which means every time there is a request for let's say the homepage there's no HTML ready yet right so then it has to run this component again for everyone that make that's making a request it has to run it over and over again so if somebody goes to homepage or SL product there's a request when I press enter there and so here next CHS will run all of this again and that's Dynamic rendering this isn't rendered once it's rendered Whenever there is a request at request time as they call it so that is necessarily slower right so if you have static rendering you already have the HTML ready Dynamic rendering you have to do it over and over again so it's going to be slower and also costs more compute ideally if it's possible we want to keep it static so mistake number 26 is accidentally making it Dynamic so the the way nextjs works is that if you use certain features in nextjs it will automatically opt the route out of static rendering and make it Dynamic rendering so that is for example the case with using the search per Rams prop as soon as you hook into that search per Rams prop if I save here and let me type this properly so now if I use the search per Rams maybe I use it somewhere here right so maybe we expect there to be maybe some color in the search prams right so actually I don't have anything in the URL it doesn't matter it's just an example so now if I run another build let's see what we get mpm run build and so I added this to the homepage to the homepage component it's going to generate static Pages as you can see here and now when we look at this output here you can see we have another symbol here for the homepage it's now as we can see here it's Dynamic it's server rendered on demand which means every time there's a request for that Home Route there is no HTML pre-rendered it has to be rendered at that moment as the request comes in over and over again you can imagine that's not as efficient but that's what you get automatically when you use the search bar Rams prop right so be careful with that right so the other option you have is using that hook but then you have to make it a client component let me remove this as well so the other two common ways that you accidentally or maybe deliberately sometimes there's no way around it that you can opt your route into Dynamic rendering is when you use the cookies function that you get from nextjs or the headers function maybe you're using these for an e-commerce cart cart INF info in there or maybe the users preferred theme so be careful with this because whenever you use these two let me actually do it in the other page that we have let's actually do it in the product page just to prove it to you now I don't have them in the homepage anymore so homepage now should be static rendered statically rendered the product page should be dynamically rendered so I'm going to run the build again you can see generating static Pages all right so now we can see that indeed homepage is statically rendered again but the product page is now dynamically rendered which makes sense when you think about it because we don't know what the cookies or headers are going to be when we just when we just run mpm run build right now right so this depends on runtime information as somebody makes a request to slash product that's when we want to get the cookies and headers and so when you use these of course you're interested in the actual request that's coming in so of course this cannot happen statically right so this needs to happen during runtime and so that's why it's now dynamically rendered now when I show you this you're going to say oh yeah it's easy right cookies and headers when I use it in a page it's going to be dynamic okay makes sense and so this is still pretty easy now in practice you often actually have an even bigger risk because you're not going to use it in just one page you may actually use it in a header right so here for example I'm using cookies to get all the cookies from the incoming request and maybe we have some cards information in there so that we can show in a header perhaps how many items the user has in their cart and here I would output number of items in cart right just a silly example now here it's even more dangerous you could say because a header you're not just going to include in one page you're often going to include this app wide right so here in layout I would want to display this on every page so I would naively just include it like this in my layout here right so now I have header here and this header remember is using cookies this is a dynamic function Dynamic API as they call it which means that now every page will be dynamic we lose all of the benefits from static rendering because the header will be on every page right so here I have my header logo number of items and card on Home Route and then on the product route I also have this so now when I run a build let's see what we got generating static pages okay now you can see everything is dynamically rendered right just because of including this in one little component essentially but that component is included everywhere in my app so it's now all dynamically rendered now even that you could say oh I was using cookies the cookies function it's pretty obvious we were using that so it shouldn't be too hard to prevent that mistake now in practice you're often going to use third party libraries so for example if I'm using uh kind here for my user authentication uh I think it's a wonderful solution for authentication I'm a brand ambassador for them it's a paid sponsorship but I would also use kind for my own projects even if they weren't sponsoring me right so it would be something like this you get you get access to the user information in there and then you can maybe show the user's email in the header right or maybe the user's Avatar image that's something about the user and this header again I'm using I want to show that on every page everywhere app wide so I'm including that everywhere now here I'm not using the the cookies or headers function myself but that third party Library may use that under the hood not just kind any authentication solution is going to use that because they need information from the incoming request to get the user who is logged in they have to do that so if you're using some kind of authentication solution be careful with where you use it because if I now run a build let's see so you can see now it's still all dynamically rendered because here they are using cookies or headers under the hoo and they have to do that there's no way around it that's so as your developer your app it's sometimes a good idea to just run a local build so you can see which routes are being properly statically and dynamically rendered and sometimes there's no way around it but sometimes you made a mistake and a route is unnecessarily being dynamically rendered so right so you want to be a little bit careful with how you're structuring your application and because of this actually often you also don't want to do the authentication check right so here you could do it inside the page component now if I remove the header from my app you would think this page is going to be statically rendered again right right so something like this and then if I would run a build again you may think oh now it's going to be static again but you can see here even the product page it's still Dynamic now because here I'm doing my authentication check and it will it will need information from the cookies or header and so typically you actually do want to do the authentication in middleware and actually I have a complete video with authentication in nextjs with kind so check it out and of course I also recommend you check out my react in next ESC course in which we're actually building some projects from absolute scratch so you can see how everything fits together let's let's talk a little bit about working with secret so here I have a secret API key and I'm sort of hardcoding that here in this file I could also write it in the component but typically these constants you write it outside the react component and this is actually a bad idea in my view mistake number 27 is hardcoding Secret in your server components or outside of there in the same file I don't think this is a good habit to get into and let me show you why so here we have the price component I'm not using it anywhere right so now let's say I'm going to added to the page and so just added to the page component which is also a server component so now I have rise here now we have the secret API key doesn't mean that now since it's visible on the page that we also leaked this API key to the browser let's actually inspect here and let's go to sources here and then and then here I can actually search for that so here I don't see it here so it looks like so far so good now the thing with react components is of course that you could also use them in multiple places right typically you want to make them reusable and some sometimes you will actually reuse them in some other place let's say in this favorite button component which is a client component we have to use client directive at the top which means now if I use it somewhere in this file and I actually import it into this file now this also becomes a client component which means that its code will be shipped to the client right so now if I save here and I refresh here and now if I search it you can see I leaked my secret API key to the browser right so this is the danger of sort of like hardcoding it here right so instead you do want to use environment variable right so next ja actually works with a bit of a convention around this as well so if you read the documentation they actually recommend using. loal and actually they don't mention just simply EnV so maybe traditionally you were used to using this you can still use this but this one is not automatically get ignored right so here if you're going to use EMV you do want to make sure you add it tog ignore sometimes I use EMV because Prisma for example uses it and so it's easier to stick Tov I find but without Prisma I would probably just use. logo which is a bit like the default in nextjs this one is properly get ignored as we can see here so that's fine right so here I'm using kinds for the authentication examples so that's why I have this here now I want to put this secret API key let's see I don't need to use quotation marks here so now if I want to use this right so if I just remove this let's say I'm just uh let's say I'm actually just going to use something silly so now I can use process. do Secret API key and so now if I'm using it like this let's see if we can still find it in the browser so I'm going to refresh here and now you can see it can't find it anymore right so this is a little bit safer because nextjs will actually not include your environment variables when the code gets shipped to the client so this price is still included here in the client bundle but next as can see there's an environment variable in there so it will not send this if you do want to send it if it actually needs to be visible on the client you need to make that very explicit here so you have to tell next J sayy next public and then I also need to prepend that here to the name so now if you actually include this and refresh now you can see it has been sent to the client as well and so with these environment variables you get some additional protection you actually need to make it explicit that you want to make it public environment variables by default will only stay on the server right so don't do something like this use server we saw it before if you want to keep it on a server cuz this will actually create a server action right so if you want to keep a secret on the server you can just make it an environment variable and when you include next public is when it will be included in the client bundle meaning it will actually be visible in the browser and by the way if you make the environment variable actually part of the render output right so now actually put it here as part of the return statement then it will be visible so if you do this way you will actually make it visible in the browser because you you intend to display whatever you return on the page here right mistake number 28 not making a distinction between utilities on the client with utilities that should only be used on the server side so we just learned a little bit about how these environment variables they have some protection built in so we just learned a little bit about how you want to store your secret in these environment variables so now let's say I have some utility function to get data and so you can use it in multiple places that is typically why you create a utility function now I could use it in a server component right somewhere somewhere here but I could also use it maybe on accident in a client component right so if I would use it in a client component and on click I want to get data now remember this utility function is using an environment variable and we actually just learned that nextjs has some extra protection here so if you accidentally use it in a client component it doesn't mean that this that the secret will be sent to the client when you actually make it like next public right next uh public will it be sent to the client very often we don't want to show it on the client right we want to keep keep that on the server so we actually don't want to add next public here so what will happen is if you actually do use it on a client nextjs will not send this secret API key with it and therefore you may get unexpected results right so it's not so much that you're leaking the environment variable it's that you just not going to get the result that you're looking for because this URL will not include the proper API key on the client to prevent that this is actually where the next chance documentation recommends that you actually do use that server only package right so server only so this function now you will get an error if you try using it on the client side right so if I try using that here for example all right so now I will get an error you're importing it say a component but it's actually utility function that needs server only that only works in a server component right so here now in a client component I get that ER I can fix my mistake oops U mistake is fixed so this is now only usable on the server and actually to make it clear you may actually also change name of this function into server UT Tails so it's clear for every developer working in the project that this these utilities are only meant for the server side and so the server only package is probably more common to see with utility functions than with actual react components right so this is also what the nextjs documentation shows you all right last one mistake number 29 using the redirect function from nextjs in try catch so very often when you're doing some kind of data fetching for example whether it's with a fetch API or with your om Prisma lots of things can go wrong actually so very often people will wrap it in a try catch Now product is not defined here so I do have to change this a little bit and then if there is a problem we will just log it right so so far so good and typically actually you would do the data fetching perhaps in the utility function I'm doing it directly here in the server component it doesn't matter here I I'll just leave it like this so so far so good now now pretty often actually what happens is for example if there is no product maybe you want to redirect the user right so here I can use redirect here from next navigation only works on the server side and so this will not work uh on the client side and what we can do here is we can say well if there is no product we want to redirect the user to let's say not found perhaps or maybe we have a special page no product page or maybe maybe the user needs to create a product when there is none at something like this the point here is I'm trying to redirect the user now this is super tricky but this will not work as expected because what nextjs does with the redirect here is it will actually throw an error right so it's basically like throw a new error this is what nextjs does under the hood and since we are in a try catch block when you throw an error it will simply be cut here right so it will not stop execution here the execution here in a server component it will just be cut here and then we go into this block right we log some error and then we just continue actually which is not our intention right so let me actually show that to you if I actually because there is actually a product here so just to let this run here if I save here and refresh you can see I'm not being redirected here even though well here there is a there is going to be a product so we should be redirected it's because I'm catching it here and so if you actually want to redirect a person here you need to do it outside a try catch right so make sure you use redirect typically outside a TR catch so if I save here now you can see I was actually redirected right so now if I go to the homepage you can see I'm being redirected to create product so now the redirect actually works right so if you do something like this it won't work and sometimes you're not going to use the redirect function yourself you're using a third party Library like maybe for authentication right maybe you're using kind maybe you're using next off and those third party libr may actually also use redirect for example redirect to log in if there is no user in some request right so make sure in that case that you are aware of this issue with redirect very tricky well done for making it all the way to the end you're probably a little bit confused about some parts that's totally normal there are a lot of new things in next Jaz lot of new paradigms and it will take some time to get used to that so hopefully this video helped you out a little bit I want to thank SE for for sponsoring this video I'm Wesley by the way I'm a brand ambassador for kind it's a paid sponsorship but great solution for authentication and I'm the creator of the professional react and nextjs course so in case you really want a master react and nextjs highly recommend you go through that course really high quality course some amazing projects my best work so far highly recommend you check it out as well so in any case thanks for watching and I hope to see you the next one bye
Info
Channel: ByteGrad
Views: 48,202
Rating: undefined out of 5
Keywords:
Id: 5QP0mvrJkiY
Channel Id: undefined
Length: 105min 10sec (6310 seconds)
Published: Wed May 01 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.