3 React Patterns for Reusability Everyone Should Know (Custom Hooks)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
everyone there are three important ways to do reusability in react and I came across this some time ago I don't know who the original author is so I can't take credit for this but I will try my best to explain it right so if you want to reuse jsx or markup logic create a separate component if you want to reuse simple JavaScript logic create a utility function if you want to reuse logic with react hooks in there create a custom hook I don't know who the original thinker was but I think that's a very clever way of thinking about things and throughout the video I will use this trackback project as the example so this is one of the projects actually from my react and nextjs course a lot of people enjoyed it a lot let me zoom in a little bit so you can see what's going on here so people can just list the things they want to take for vacation let's say so that they don't forget it I can also add an item like this and I can delete them all right so in a project like that we may have some kind of item list component and we may actually also decide to add some kind of theme toggle at some point so that the user can switch between light mode and dark mode right we've seen these everywhere it's very standard now what you may want to do at some point is you may want to allow the user to reset to a default so we may have a button here let's say that is something like this right so just a button reset to default with some background color with some styling here and in this component we may also want to have a button that allows the user to just reset to the initial or default value right so now I also have a reset button right here and in an application you want to be consistent with your Styles so this button actually has the same Styles as this button here because they are both reset buttons it makes sense that we use the same styles for reset buttons throughout our application and as a result of this we actually have some duplication now and this is actually very common you're going to have duplication in your jsx so whenever you have duplication in your jsx or mark up you may want to consider extracting it out to a separate component so you can easily reuse this button whenever you need some kind of reset functionality right so components are meant for reusing jsx or markup essentially so let's actually do that let's quickly create a reset button component so I'm going to take this button and I'm actually just going to paste it right here now I put this jsx this markup in its own component and now I can use this component to reuse the jsx or markup whenever I want a reset button right so instead of duplicating myself here I can just Swap this out with a reset button component right and then also here I don't want to have duplication in my jsx I'm going to extract it out into one component and now whenever I want to reuse that jsx I just use that component right and of course we can make this with the children prop right we can make it fancier than this but the point here is if you want to reuse jsx or markup you can just simply create a component so that's one way of reusing something in react all right so then for the second one let's go here typically in a list like this you don't hardcode these Lis typically you are keeping track of these items in some array perhaps in state right so here we could have use State let's say right so then here you have all your items and you would just map over them here right so this would be uh very typical right so you just map over each item and then you would create an Li for each one of them right so let's say an item is just a string and maybe we want to uppercase the first character of the string so you cannot just do that with CSS because with CSS you're going to uppercase every word we only want the first word so it turns out this is actually a little bit tricky to do you need you need some JavaScript magic here so you need to take the first character and then we can uppercase that and but that's only the first character now we need to combine that with the one and this is how you could do that I'm ignoring the TP script here it's not important but you can see the syntax is not great here and we may actually want to do something similar here in theme toggle so we may want to say something like current theme and maybe we are also keeping track of that in States right you state here current theme and then we just want to Output a theme but you can see it's lowercase here maybe I also want an uppercase but if but only the character of the first word so if it happens to have multiple words I don't want to do that right so let's see if co-pilot is a genius today no maybe not now yeah so now you can see we have the same logic here right so now we also have duplicate logic again we have now a way of essentially upper casing the first character of a string so in react if you have some logic that you want to reuse throughout your application you may want to put it in a utility function or helper function and not a custom hook right so custom hook we'll get to that in a second that's for when you are reusing logic with react hooks in there right but here we are not using react hooks right so for this type of logic we don't want to create a custom hook we just want to create a utility or helper function so typically in your folder structure you would probably you would have some kind of Library folder and then in there we can create a utils file or helpers file and then here we can put all of the logic that we want to reuse throughout our application and the logic here would not use react hooks right so this is just plain JavaScript logic you could say so let's actually extract this out into a separate utility function so we could call that capitalize let's say and we need to be able to call this with our string right so I would like to replace all of this with just something like capitalize and then passing in the theme right so this is how I would like to use it so then here I need to accept some string that is actually of type string and just to make it clear we could also just call it Str Str and then we want to return that string whatever the user is passing in capitalized but only the first words right so we would do something like this so now we have encapsulated that logic here within one function now we can use this function to reuse that logic right so we're centralizing the shared logic in this function here now I can use it like this I do need to import it but you can see this is how I would then use it so then here I could come here I can replace all of this nasty code here with just one clean function and just pass item like that right so now you can see I can reuse this logic throughout my application very easily if I ever need to make a change I know where to look right that's one of the benefits of extracting it out into a separate function like this is if you do want to make a change you only have to change it in one place and it will automatically be applied in all the instances where you're using it so in react if you just have some plain JavaScript logic that you want to reuse just create a utility function don't create a custom hook because here we are not using any react hooks like use state or use effect all right so then number three here let's say we want to store the items in local storage that's actually what we're doing in the project as well and in the course we are actually using two and two makes it super easy to persist in local storage but even without two it shouldn't be too difficult right so the reason we want to put it in local storage is so that if the user leaves our app here right so if I refresh here we still want to keep the items we want to persist it right so if I refresh you can see they are still here no matter how many times I refresh if I close that Tab and I go back here again you can see I still have my items right here how do we Implement that so let's say we have our items here let's say we are keeping track of them here in use State how do we make sure that when items change so let's say when I add something to the list that I'm actually persisting that in local storage so we actually need to do two things we need to add something to local storage and then when I come back we need to get it out of local storage again and actually just to show you how that looks like here so you can go to application and then here there is local storage right so you can click here and you'll see whatever is in local storage right so you can see here local storage has one key it has items and the value for that is just an array with all of those items right good mood passport and phone charger right whenever the user adds an item or deletes an item basically whenever this array gets updated we want to persist that in local storage so what you can do is you can use use effect right so here you can say whenever there is a change in the items array we want to persist that in local storage right so that's the first part data local storage right so we can just do local storage. set item we need to specify under what key right so here we want to store it under items right so the key here is what we see here we're going to store the value under this key right and this is just a simplified example of the actual project right so we're not actually running this code this is just the example so then the actual value for items and so here then you need to specify the actual value for that key and that should just be the items array now in local storage we need to store it as a string so we can actually just make it a Json string we can say json. stringify because items is actually an array so we're going to stringify that and then we'll put it in local storage under the items key so now whenever this items able changes we are persisting that in local storage so now the idea is that when I refresh or when the user comes back that we can pull it out of local storage again so the second part is getting data from local storage so how do we do that well you can actually just directly access local storage in here so what we could do is we could do something like initial items uh local storage. get item well which one do you want well we call that items here so that's the one that we want and so then here when you load the app this will run for the first time and it will get the items from local storage and that's what we can initialize state with here the downside of doing it this way is that now whenever this component reenders and it may render for whatever reason you're going to access local storage and then get item and this is not great for performance ideally we only run this once when the component first mounts right when the app first loads essentially we don't need to run this whenever the component renders so we actually have another option um here with use State a lot of people actually don't know about it you can also instead of specifying you know an empty array or or a variable for the initial value you can actually also specify a function here and this function will only run once when the state is first initialized right so here you can make sure that it will only run once so whatever you return from this that will be the initial state right so we can actually just do the same in here and then this will only run once right so this is how we are getting data from local storage now the data that we are getting is actually in Json format because here you can see we are stringifying it so whatever we get here we do need to par par that back to a normal JavaScript format so we're just going to say json.parse now typescript will warn us here because we are trying to get items from the local storage it's technically possible that there is nothing there the user could have cleaned their browser data or there could be something else there could be simply no data there so here what you would get back is null you cannot pass null to json. par so that's why we get this issue here we're going to ignore typescript here for a second just so I can get the point across so now we have a way of setting this as well as getting data from local storage now that's for the items but we may actually want to do the exact same for the theme as well you can imagine that if the user sets the theme to dark mode if they set it to dark mode we don't have the theme toggle here but imagine that there is a toggle here for dark mode when the user comes back we still want to make the app dark mode right so we also want to persist the theme and we actually want to reuse that logic here right so what you could do is you could copy and paste that right so here you could copy and paste all all of that and then of course we wouldn't have items I would have a theme Here set the theme right so I would replace everything here with theme and let me import use effect here so now I'm doing the same for the theme as well and now you may say aha we have some duplication here we want to reuse this Logic for local storage you may want to create a utility function just like we did for capitalize well that's not what we want to do because here we are actually using react hooks we're using use State and use effect so here we actually want to create a custom hook because when you're using hooks these hooks they come with some constraints you cannot use them after a conditional they have to be at the top level of the component right so those are the rules of hooks and a normal utility function can be used anywhere and any time so a normal utility function does not have that constraint so instead of creating a utility function for this here we actually want to create a custom hook so what you could do is very typically you could just have a hooks file so hooks. TS we could call that uh use local storage it's actually a very common hook so I think it's good to learn how this is implemented as well and now we can try removing it from here and actually putting the logic in here notice that a custom hook always starts with the word use this is to indicate that this is not just a normal utility function this is using react hooks under the hood as we'll see right so now let's see if we can actually extract this into a reusable hook the benefits of that will be that we can easily reuse that logic but also it will simply clean up the component as well as we can remove all of this logic out of the component we can put it somewhere else and so the component will look much cleaner as well so typically what I do is I take one of the instances of that logic I just copy everything and I put that here in my custom hook I will import use state right so I'm using react hooks here under the hood so now I copied that theme example in here but the goal of this Hook is that it's reusable so we took this one instance and we put it it here but now we also want to use it for other instances so we need to make it more General right so that's how I always approach this so here instead of theme well it could be any value not just a theme it can also be items it can be something else as well so here you want to change the names to something more General right so here we can have some value right so we can just make it a more General name and set a value right here we are still using theme well that's should just be value same for this one here set item okay now here we have the string theme still well this is that key in local storage so we cannot just do value because then it would always have literally value here right so for the key in the local storage that needs to be determined when you actually use the hook so if I replace all of that you can see how much cleaner it looks I can just import this hook here and then well we we need a way to specify the actual key so that actually does need to be something that we specify when we when we call the hook right so here you can imagine that I would like to call this with theme in this case and then for our item list we can also replace all of this you can see how big of a difference that is and here the key I think we called that just simply items right let me import this as well now we get a problem here because right now our Hook is not accepting an input right so here we do need to specify an input right do not do something like this like destructuring uh the props of a component this is just a JavaScript function so we just have we just have a parameter name like this and key needs to be a string right so we can type that as a string right so then when we set data in local storage here in the hook it cannot be literally it it should not be theme it should be whatever the key is that the user of this hook has specified right so we need to replace this with key and we also when we get it then from local storage we need to specify the key right so then here it should be whatever the key is um and then here we also need to add it to the dependency array okay so now we have our reusable hook you can see how much it cleans up the component here and and we can now very easily reuse this whenever we need that local storage persistence including in other projects right so over time you actually build up a nice library of these reusable hooks now let me actually remove this because I don't want to see any red quickly lines here let me actually remove the previous examples here as well let me just remove this entire thing here as well as these Imports right so now we are not using use effect and use State anymore in this component not directly at least right we are still technically using use effect and use state in this component but it's just written somewhere else right so this is the exact same as just literally writing it here right so it doesn't really change the behavior of anything we can literally write use State and use effect all that logic still here in the component but we have just put it somewhere else but it works the exact same so a custom Hook is also bound to those rules of hooks right so you cannot call it after condition or in some Loop or in any block it always needs to be at the top level of the component and that makes sense when you think about it because what you when you use this it's the exact same as using use State and use effect directly in there and you cannot use these in some if statement or after a condition either right so the the rules stay the same now here of course we should get the value back from the hook as well because if we still want to use that theme like before let's say current theme well I may actually still want to use it like before right so where am I getting the theme from now well this hook should return that right so this hook should still return whatever value is in here right so I can return it as a so-called tle here in typescript it's called a tuple when you have an array with a set number of values right it's just an array essentially and then to use that it's actually very similar as the use State hook you can do destructuring here with an array and you can actually immediately call that whatever you want so we are actually renaming this as we are destructuring we can do that with an array right so here the array is returning something called value and set value however we can actually already call It theme and set theme when we get this from here so then we can just use theme same with items here we may actually still want to Loop over the items right items. map where are we getting those items from well we're getting it from this hook so how do we get it from that hook well it's the same right and this Hook is returning value and set value but we can immediately give it the name that we want here so we can say I items and then set items right so here I'm returning the values as an array here the benefit of returning it as an array is that you can immediately use the name that you would like to use so you are essentially renaming it as you are destructuring it right so this is actually the same as with use States the downside of this is that you do need to get the order right right so here if I if I misremember the order and I I'm going to call it set theme here and then theme for whatever reason set theme will not be that function actually right so it will not be that Setter function set theme will actually be the value right so this can cause some gnarly bugs so that is the main downside with returning it as an array you can also return it as an object of course so here I can return it as an object and then here when you use it you need to destructure it as an object Now with an object you can use any order you want but when you are destructuring an object and you want to rename the value you you do first need to actually use the same name so here I would actually first have to actually explicitly say I want to use the value here and then I can rename it as a theme here and here I have to D structure set value explicitly and then I can rename it to set a theme right the benefit of doing it as an object is that the order does not matter right so you can so if you get the order wrong that's not a problem the downside is that the renaming isn't as nice now here use local storage is actually very similar to the use State hook that you get in react so here I think the odds of getting the order wrong are small because because it's it works the same as with use state so here I would actually use an array so let me actually return it as an array all right so this this is now a nice reusable hook whenever we need to persist data and local storage you can just take that hook you can just use it in any component so that's good for reusability but as you can see it also cleans up the component and we have removed a lot of the logic and also we know what the logic is doing now right the name of the custom hook tells me what kind of logic is being implemented here right before if I just had all of this stuff directly here in the component yeah of course I wrot I wrote down some comments here but let's say you don't have those comments you just have this well I don't really know what's going on here I really have to sit down and parse this stuff here to understand what's going on here not only does it look messy it actually takes some time and energy to understand what kind of logic is being implemented here so this so with a custom hook you are essentially also just applying a label to the logic that is being implemented so it's very easy to understand what's going on in a particular component right so if you want to reuse jsx or markup logic create a separate component if you want to reuse simple JavaScript logic create a utility function if you want to reuse logic with react hooks in there create a custom hook I don't know who the original thinker was but I think that's a very clever way of thinking about things now one thing here is we did cheat a little bit here with typescript so here when we get data from local storage we don't know if there's actually going to be something there so it's possible that get item actually returns null and we can actually not has null to json. pars so pars does not accept null so in case get item actually returns null we may actually also want to specify some initial or default value but what should it be actually so if we want to start off this state with some initial value if there is nothing in in local storage well what should it be should it be an array well not really because if we are using this for the theme let's say theme is not an array it's just a plain string right so here I don't want to have a default value of just an array in in fact it should probably it should be up to the user of this hook to determine what the value should be if there is nothing in local storage right so here we can expose another parameter here we can say initial value and that's simply what it should be if there is nothing in local storage now this is actually being pared as Json so we we should probably make it a Json string so it doesn't interfere with that now the initial value here is getting pared as Json right so it is assuming that this is um we we may want to turn this into a Json string so we can say json. stringify so it will be correctly parsed right so now we have this okay so now the user needs to pass in the initial value in case there is nothing in local storage yet so here the initial value for theme would probably be light right let's say the default is light mode and then here let's say if there is nothing in local storage we probably just want to start off with an empty array right so you can see I'm using an array type here and here a string so then um here for that parameter how should we type that actually right so here I cannot use a string here if I do this you can see that here it works right because this is a string but here we actually have an array right so this is actually a little bit tricky so you could say okay we'll make it we'll make it some array type right so you can say oh make it some array type or something like that but you can imagine that we may actually also want to use an object right so we could use all sorts of types here so instead of going down this route you may think oh I'm just going to type it as any it could be anything well typically you don't want to use any but the major downside of using any is if you do it this way now if you hover theme it will not be correctly typed as any we will not be able to get the correct type which is which should be string here right and here for items it should be some kind of array because we are typing it like this we will not be able to get it right so in this situation where you could be specifying multiple different types we may actually want to use a so-called type parameter or generic right we're going to turn this into a generic function and this is a little bit Advanced so it's okay if you don't fully follow along here I just quickly want to show you how these typescript generics work in custom hooks because very often with custom hooks you will actually use uh generics you may want to type it as some T right so here we can specify T here now if you have a type parameter you always have to specify that up front here so here just to specify to tab script hey I'm going to use a type parameter here I'm going to call it t and that's what I'm using here okay so now I just told you that now when we hover theme we should be able to get the correct type here for the value that we get back out of there but as you can see we are still getting this any type so here what we also want to do to get that correct type for the user of the of the hook is we also want to specify what the return value will be right so here we are returning something and and we can specify the type of that here so you do it with colon after the list of parameters you specify the types for the value as well as the set value here if I save here it gets formatted a little bit differently we can use the T again so here we want to encode a relationship because whatever the type is of what we pass in so for example here I'm passing in the string light that's also the type that you get back out of it here right as the first uh as the first value so that lets typescript know that if I pass in a string here the first value that you get back out of there is also a string right so now you can see we are getting the correct type here same with item list if I pass in an array here we just specified that whatever type you pass in that's the exact same type that you also get as the first value here first value here is the same type as the initial value here so if I pass in an array here now if I over this you can see we are we are also getting some kind of array here it's of type never because we haven't specified yet what type of array this is but you can see at least it's some array right so this is the power of typescript generics I have other videos about typescript including generics but one of the major use cases for it is to specify a relationship right so here there is a relationship between what you pass in as the initial value as well as what you get back out of it and the same with the other value here we are actually passing the setter function here that we get from UST State here so that's actually just a function that takes in something but that also has to be of that type right so here basically this function here set theme if we call set theme somewhere well we cannot call this with an array or something like that right so this also needs to be the same type as what we pass here as the initial value right so this can only be a string uh and we can encode that relationship with this type parameter right so you can see we have all these we have all these T's here there's a relationship there which is that they are all the same type so here if a hover set theme you can see set theme in this case is going to be a function that takes in a string it takes in a string not any and here if I if I hover set items here you can see it takes in something of type array right so a little bit Advanced here you don't have to understand that but I think it's uh good enough now because with custom hooks you're often going to see these typescript generics so if you set it up like this here we still have that array of never what you can then even do is you can specify the type yourself just like you could do with use State you can even do something like this that's going to be an array of strings you can specify directly like that so then here that will be the T so then what you get back out of that that will be the same type so then what you get back out of it items here is indeed an array of strings but I have to say this is already pretty Advanced so it's okay if you don't follow along here we do talk a lot about typescript in my react and nextjs course as well we start from absolute scratch in that course and we build everything up step by step so I highly recommend you go through my professional react and nextjs course if you want to master the latest react as well as the latest nextjs including the relevant typescript in that course we actually build some other custom hooks as well for example in the remote def project we are actually also creating custom hooks for data fetching right so here I'm using use job item because we're fetching some job item data and here we are also using the use debound h hook so this is actually also a very common hook and we actually implement this also from scratch step by step and it actually also happens to use a type parameter so the value here is the same as what you get back out of it and here actually we also use the use local storage hook and we also have a hook here for use on click outside so if you click outside a model or pop over let's say this is uh you may want to close the model or pop over and you can see actually this hook does not use use state it only has this use effect in there right so you don't always need use state in a custom hook you can actually use any react hook sometimes it's only the use effect and actually another good use case for custom hooks is when you are using the context API so to consume the context you may actually want to create a custom hook for that I have a separate video on that but that's another good use case for creating a custom hook as you can see we have quite a few of them and of course there are also websites that actually show you some custom hooks out of the box so you don't have to create those common custom hooks from scratch you can see there is actually already somebody that has created that for you check out my react and nextjs course if you want to master the latest react and nextjs it's my best work I highly recommend you check it out thanks for watching this video hope it was helpful and I hope to see the next one bye
Info
Channel: ByteGrad
Views: 18,990
Rating: undefined out of 5
Keywords:
Id: 397259iiZ6M
Channel Id: undefined
Length: 28min 8sec (1688 seconds)
Published: Tue Feb 13 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.