The Best Pattern for Conditional Hooks in React

19.81k views3050 WordsCopy TextShare
Cosden Solutions
Try Brilliant Free for 30 days 20% Off Premium Membership → https://brilliant.org/CosdenSolutions ...
Video Transcript:
So in React, hopefully we all know this by  now, but hooks have rules, right? You can't just go around and use hooks in any way that you  want. It's not going to work, it's going to throw errors, and you really have to follow what is  called the rules of hooks.
Now, one of those rules states that you can't use a hook conditionally,  which means that you can't put a hook inside of an if statement, for example, or you also can't  put a hook after a return statement that may or may not return based on some condition. Now,  while the reasons that React has for not letting you do that are perfectly valid, that's not what  I want to focus on for this video. In this video, what I want to focus on is the fact that in a  lot of cases, you actually do need to run hooks conditionally.
You need to run the function, the  logic inside of the hooks based on some condition. And in this video, I'm going to show you how you  can do that. I'm going to show you a really nice way that you can break the rules of hooks and  actually get around this and run any code that you want in any hook conditionally in a way that  is super simple and super efficient.
And it's actually going to teach you a little bit about  memory in React and also a little bit about how to watch out for unnecessary extra renders in React.  I'm super excited. Let's get into the video.
All right. So let's begin. Now, this pattern over here  that I'm going to show you, I'm actually going to be adding in my existing design patterns document  because it's really such a cool pattern.
And it's also important as a React developer. And by the  way, that design pattern document is actually a list that I compiled of ten of the most important  design patterns that you need to know as a React developer. If you're interested, it's completely  free.
Just join the import React newsletter. It's going to be linked in the description. As soon as  you join using that link, you're going to receive the design pattern document.
And you're going  to see that this one is going to be added to it as probably I think the 11th design pattern.  I'm just going to keep updating that design pattern document because it's really important.  And it's going to be a great resource for all of you React developers.
So again, completely free.  Check it out in the description. So over here, we have a dialogue component, which is basically  like a model, something that pops up full screen, right?
This is a very simple representation of it.  And this one takes in and is open property from the parent, which is a Boolean, and then an on  close function, which is a function that returns for it. Then what we have here is we have a ref  that we call element ref, this is a diff ref, we're passing in here to this hook.
And we're  also passing it to this diff over here so that we can uniquely identify the diff. And this use  outside click, essentially what it's doing is it's just going to detect clicks outside of this  diff, right? Because this is going to be a model, it is not going to be full screen, but it is going  to go over everything on the screen, it is going to detect clicks outside of the screen.
And if  we're clicking outside of the screen, we're just going to close the model, right? Pretty simple.  This is the actual code for the use outside click.
So we're passing here the ref, and then we're  passing the callback over here. And then we have a use effect, which essentially all that it does is  it just attaches a click listener to the document. And then here, we'll actually check if we're  not clicking the diff.
So if we're not clicking the actual element, then we're going to call the  callback and just again, close the model, right? So pretty simple, nothing really fancy here. Now,  here's the thing.
Currently, this hook is not being called conditionally at all. So this hook  is going to run every single time that this dialog component is rendered. And even if the dialog is  not currently open, because there's nothing that is telling this hook that it shouldn't run when it  opens, which means that every single time that the user clicks on the application on anything, this  code is going to get run.
Now, this is probably fine, because the only thing that is going to  do is try to close an already closed model. But still, this is calling functions unnecessarily.  And if we have any state or anything else in this that might change because of it, we're also going  to be causing re renders in our application, which is not a good thing, right?
So that's the problem,  right? We don't want to run this every single time that we have a click in our application  that's inefficient, and it's going to be even worse if we have a lot of these dialogues in our  application that are completely hidden, right, they're only get to shown once, for example, if  you're trying to like, delete your account or change your password, how often does that happen  in application, but still, every single time that we click as many dialogues as we have in our  application, we are also going to have clicks in our applications and potential re renders. So  that's not good.
And we need to fix that. Now, before we continue, I just want to take a quick  moment to really think about what it is that we're actually doing in this video, because what we're  doing is we're following something that is called learning by doing, right, you're not just watching  a traditional theory video, you're actually seeing me implement the pattern, doing it in front of  you so that you can learn better, which is great, because that's exactly what brilliant the sponsor  of today's video is also doing. So brilliant is a platform where you learn by doing you have  1000s of interactive lessons in various topics such as math, data analysis, AI, and of course,  more importantly, for us programming, brilliant has a platform that is designed to be uniquely  effective.
Their first principles approach helps you build understanding from the ground up. Each  lesson is filled with hands on problem solving that let you play with different concepts, which  is a method that has been proving to be six times more effective than watching traditional lecture  videos. Plus, all the content on brilliant is crafted by an award winning team of researchers,  teachers and professionals from places such as MIT, Caltech, Microsoft, Google, and so much  more brilliant literally helps you build your critical thinking skills through problem solving  instead of memorizing.
So while you're building real knowledge on specific topics, you're also  learning how to become a better thinker. They have some wonderful courses, one that I really like is  called thinking in code, which pretty much follows what we're doing in this video and teaches you  solid foundations for computer science that is going to directly help you as a react developer  to try everything that brilliant has to offer for free for a full 30 days, visit brilliant. org slash  causal solutions, scan the QR code on the screen, or simply click the first link in description. 
You're also going to get 20% off an annual premium subscription. Thank you once again to  brilliant for sponsoring this video. And now let's get back to implementing the conditional  hooks rendering pattern.
Now, how do we fix that, right? Because ideally, we wouldn't want to run  any of this code at all, right? Because this also creates a subscriber, right, it actually adds a  listener to the document, which is a little bit of a memory performance overhead, right to have this  for all of these components, when they're not open is something that ideally, we will try to avoid. 
But we can't do anything like this. So we can't do if and then condition, let's just put false  like this, right, we can't put a hook outside of a condition. Actually, let's do if it's open, right,  this makes a lot more sense.
We can't do this, we can't make a check for is open, and then render  the hook conditionally based off of that. Because again, this breaks the rules of hooks. And there  you go, react hook is called conditionally react hooks must be called in the exact same order every  single time, right, there we go.
So this breaks, so we can't do that. Now, this might seem like a  stupid example. But if you're learning react, this is something that you would totally think to do,  right?
If it's open, just run all of this code, but it doesn't work, it breaks the rules of hooks.  So we can't do that. So what else can we do?
Well, another option that we have is we can come here  inside of this callback over here. And because we have access to is open over here, we can check for  is open before running the function. So we can do if is not open, then we're just going to return  right and not do anything.
And then only if is open is true, are we then going to actually call  the on close function, this will fix the problem. But it's also not the best solution. And the  reason why it's not the best solution is because yes, we're checking is open over here.
And then  we're not calling the function if is open is not there. But what we're still doing is we're still  running this ad event listener, we're still attaching the listener, we're still doing all that  work. And we're still calling this function over here, this handle function, we're still calling it  right, this is actually still going to get called every single click, and we're still going to be  calling the callback function, right, just because we put is open over here does not prevent the rest  of the component, the rest of the hook rather, of running all of its code, the only thing that we've  done is we've stopped the actual callback function of running the on close function.
But that's not  enough, because here, we're wasting memory, we're attaching all of these things here, when we really  don't need to be attaching them at all. Now, this is really important, because it's not really  that obvious that this isn't necessarily the best solution. There's a lot of developers that would  actually do this and call it a day and think that the problem is solved.
Because on paper,  theoretically, it is right, we're not going to be calling the on close function, that's totally  fine. But we're neglecting the actual memory impacts of running all of this code over here that  is still going to run, even if is open is actually false, we're still going to add all of these  listeners. And again, we're going to be wasting memory here, not probably the differences are not  going to be that impactful, that's totally fine.
But generally, you want to be aware of these  things. And you want to be aware that doing all of this is often not enough, and you need a  better solution. So what's the solution?
Well, the solution is actually the pattern that I want  to show you in this video, it's the whole point of this video, the solution is to actually get rid of  this open over here, and instead adopt a pattern that you may want to adopt for most of your hooks  in your application. And that is going to be to come into the hook over here, and actually add  as a first argument, a enabled prop like this, that is going to be a Boolean like this, that is  going to allow you to determine at the hook level, if it should run or not, if it is enabled or not.  And this is better than just putting it inside of the function over here, because now this is part  of the entire hook, which means that you can use it in the entire hook and not run any of this  code based on that condition if it's not enabled, right, so we can come in here and inside of  this use effect, we can do if is not enabled, then we're just going to return here as well,  right.
And now we're going to have to also pass it here, enabled inside of the dependency array,  right. So now, if enabled is not true, we're not even going to run any of this code, we're not  going to attach any handlers, any listeners, we're not even going to define any function over  here, because enabled is false. And that is going to allow us at the hook level to control whether  or not this hook should run all of its code or if it shouldn't.
And another benefit of this is that  now because we have enabled here in this hook, right, we can actually put it here if we had  another use effect, for example, useFor some other functionality, we could also in here write  check for enabled. So we can do enabled as well. And we can also do if is not enabled, then we're  just going to return as well, right?
We could also do this. Why is it complaining over here?  What's the problem?
Unreachable code detected. Ah, I put it wrong. It should be here.
There you go.  We could have another useEffect over here. Or we could have, for example, function, do something. 
And this can be a function as well. And we can also take this as well and have it do something.  What is the problem over here again?
What's wrong? I had a typo. There you go.
Function. There we go.  Right.
So now we can also use this function and check the enable property inside of here as well.  And also, if you now think about it, now that we have more stuff in this actual hook, the solution  that we had before of putting everything in here, if I can just undo it, this wouldn't even work  anymore. Because all of this would do is only apply to this callback function in here.
All  of these effects over here would still run, right? If we don't have this enable property, like  we had before, this function, if it was called, would still run as well, even if it shouldn't be  even if is open was false, right? So the solution over here doesn't actually work.
But passing  here instead is open works because now again, this is available to the entire hook and whatever  the hook has, it can use that. And it can just run or not based on this property. So now what  we have is we have a much better solution, we have this hook over here, right, it takes  in and is open, which is the enable property.
And then all these other properties  as well. And then based off of that, it knows what to do or not to do. This is way more  efficient.
This is very good on performance. This is very good on memory as well. And we're not  running any code unless we explicitly want this code to run.
And this is again, a way for us  to get around conditionally rendering hooks, right? We're not conditionally rendering the hook  technically, but we are disabling all of this functionality based on condition, which we can do,  we're allowed to do and this is the only way to break the rules of react. Now you may be wondering  why we don't put the enabled flag here at the end, which we could do because if we do that, then we  can also even default it to for example, true, right, so it always runs even if we don't provide  it.
But in that case, the only thing that I don't like about this is now we're going to have to put  is open here at the end. And I just don't like the way that this is formatted. It's a little bit  stupid, but I don't like the formatting of this, we have the actual ref here, then we have the  function and then it's open is all the way at the bottom.
And even if I mean, it's fine. But if  we it's not actually no, because we still need to pass is open, right? If we didn't have to pass  it, then it's probably fine.
It looks like this, you know, but if we do have to pass it,  it's going to look like this. Instead, what I like to do is just put it back how it  was before. Now, you always have to provide it explicitly for this hook and any other hook that  you want to apply this pattern to.
And now your formatting looks a little bit better, because it's  always going to look like this no matter what you do. And this is also a pattern that you can apply  to more hooks in your application. Essentially, any hook that is based on some condition that  needs to run some code based on some condition, use this pattern pass this enable property as  the first argument, or if you prefer pass it as the last argument, it's totally fine, right? 
Just pass it as an argument. And then all of the code in here is not going to run based on  that argument. And you can just use the hook directly past the enable property over here,  whatever it depends on, and everything works, you've solved the problem, you have no memory  problems, you have no rendering problems.
And this is a simple, elegant and efficient solution  to conditionally rendering hooks in react.
Copyright © 2025. Made with ♥ in London by YTScribe.com