Why Signals Are Better Than React Hooks

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
I have a LoveHate relationship with hooks in react and if you've been using them for any amount of time you probably do too I mean I love how powerful they are and how easy it makes it to do certain things with reactivity in your website but I hate how complex they can be and how easy it is to ruin your application with hooks there's so many rules you need to know and there's a lot of special techniques that are very specific to hooks that you need to understand in order to make sure your application is as performant as possible if you don't follow these rules which is quite difficult to do you can really kill the performance of your application and it's just super hard to work with this is why I really like the idea of signals because what they do is all the same powerful stuff as hooks but they make it incredibly easy to use there are no complicated rules to worry about and performance is out of the box by default so you don't even have to worry about it welcome back to web dev simplified my name is Kyle and my job is to simplify the web for you so you can start building your dream project sooner and to get started I have a really simple to-do list application built out to kind of show you why signals are so useful and some of the problems that they solve this is a simple application you can see I have a Navar a to-do list and a sidebar and in all of my components I actually have a console log just saying that we've rendered that component so we can see what the rendering looks like in our application our naad bar super straightforward it's just this top section you see here our sidebar also super straightforward it's this right hand sidebar you see right here common stuff you would see in a normal application and then our to-do list is a bit more complicated you can see that we have this to-dos value stored in state and it's also persisted inside of local storage and we have a function for adding a to-do a function for toggling so when I toggle this for example and refresh you can see all of my data persist all this is happening with this use effect here and then I just have all the different jsx for this form as well as the to-dos being rendered out down here and if I add something in you can see it shows up and persists when I refresh my page now this is about the most basic form of application you can get and in this particular scenario using state or signals it really doesn't matter they're both pretty easy to use and it's doesn't really make a difference which one you use because it's so simple the application that we're building and you can see if we inspect our page here I'll bring this over and we look at the console you'll notice if I just clear this out whenever I like toggle one of my to-dos or something like that you can see that the only thing rendering is my to-do list nothing else in my application is being changed but now what happens my application gets a little bit more complex and now I want to show the completed to-do count inside of this header as well well I need to get all of this to-do State I need to remove all of this from my to-do list and I need to move over into my app instead so it would need to be inside of here like this now the reason that I need to do it this way is because I need access to this to-do State inside of my app because my app is a parent of this Navar so obviously if I want to pass my state to the Navar I need to have access to it inside of the parent component now I just copied over the code to actually make this work and as you can see inside the app we now have all the code related to our to-dos and we're passing our to-dos into our nav bar and then we're passing all the information for adding toggling to-dos and so on into our to-do list so if we look at our to-do list you can see it's very very simple there's almost nothing in here because it's just dealing with this one form input and you can see in our Navar it's actually getting the completed to-dos and you can see up here the completed number is one and when I toggle you can see that this is properly updating now if we look at how the actual rendering of our application works if I clear this you notice when I toggled this it's actually rendering my app my Navar my to-do list and my sidebar and that's because I'm storing this state in my application so in my app right here which means I need to render my app anytime that state changes and when you render a parent component you must also reender all of the children inside of that so my Navar renders my to-do list renders and my sidebar renders even though in reality when I toggle this laundry check boox my actual app doesn't change like the actual you know HTML being generated for the app portion doesn't change my sidebar obviously doesn't change but those things are being rendered unnecessarily now this honestly isn't a massive deal especially on a small scale application like this but as your application grows and grows and grows and your state becomes shared across all of your different application it's very common that a lot of your state ends up inside of your app component or some other really high level component or maybe you move it into context but you still get the same problem where your app is just wrapped by like seven different context you have all these extra renders you really don't need so that's the first thing that signals are trying to solve and in my opinion it's one of the smaller things they're solving they solve this performance by making it performant by default and you don't have to worry about doing a bunch of things like memoizing or react. memo and all that stuff that you would need to do to actually make this as performant as you can the real place where signals shine is that they get rid of all the rules related to hooks for example with hooks you need to know that you can only use your hooks at the top of your component you can't use them inside of like an if statement you can't use them other places they must be used only in components and custom hooks there's a ton of rules around like how you use a use effect making sure you have all your dependencies in here all of that is a thing of the past with signals because they handle all your dependencies for you you can use them wherever you want in a component outside a component in a loop in a function it doesn't matter it's so amazing how powerful they are and this entire signals library that I'm going to be using for this video is going to be the preact signals library and you don't have to be using preact for this they have libraries for spelt preact react normal JavaScript it doesn't matter and they have this amazing blog article with I'll link in the description for you that goes over their entire thought process behind why they implemented signals and why they did it the way they did this is an amazing article to look at they even have some performance metrics here and you can see that they've actually increased the speed time of this page from 2.6 seconds to6 seconds just by implementing signals which is absolutely crazy so in order to show you how signals work I've taken our code and I've reverted it to exactly what had before where everything is still inside of our to-do list if we go back to our code you can see we no longer have that completed section here I'm going to show you what it would look like implementing this using an actual signal instead of using a hook inside of react so to use this signal Library we first need to install it so npmi at preact SL signals react so we'll run that to install the library and now we can start using signals and signals allow us to replace all of our use States as well as our use effects and in doing so we can replace almost always our used memos and use callbacks because because that all of that is kind of taken care of force memos and callbacks are just really there as a way to add performance to your application and signals just do that by default so in order to understand how a signal Works let's take a look at creating a signal right now so we can just call this signal function so we're going to get that from signals react so we're just going to say signal just like that we're going to make sure that imports from the react Library there we go and all this signal does is take a value so for example I could just give it the string of Kyle and I could say that this signal is going to be a name signal so we'll say const name equals signal file so now I have this name variable and if we just console log what this name variable looks like we'll go over to our application we'll give it a refresh make sure I rerun the application first and we'll just look at our console to see what this looks like and you can see if we scroll to the very top I get this thing all the way up here and you can see it has kind of a lot of complicated information going on behind the scenes but the most important thing is it has this value property right here which always returns to me whatever the current value of this thing is that's the only thing I really care about for this signal all this other complicated stuff is just to make sure everything works behind the scenes cuz it does a lot of really cool stuff so if I want to access this value I could just say name. value and now if I refresh and I look over here you'll see that it should print out Kyle at the top of my screen just like that there we go now the real power of this comes in the ability to actually make sure everything that uses this signal automatically updates anytime my signal changes so for example if I just say name. Val is now equal to Sally all of the code that uses this signal is going to get updated with this new signal value which is incredibly amazing so I'm just going to put this inside of set interval for now so I'll say set interval and we'll say that every half a second I'm going to update the name to something else so we're just going to say math. random oops math. random there we go we're just going to convert this name to a random number and I'm just going to put that inside of my jsx so here we're just going to put that number so we'll say name. value so as you can see I'm not using state I'm not using anything at all all I'm doing is I just have a name value here and I'm just changing the name every five 00 milliseconds now if I save you can see every 500 milliseconds my application is updating with that new value inside of it and I'm not doing anything related to state or anything complicated at all and if I look at my code to see what's rendering if I just close out of this you can see the only thing rendering is my to-do list because that's the only component that's using these updated things so really if you look at a signal all it is is a way for you to store a value and then whenever that value is changed to update everything that relies upon that Signal's value which is really really powerful it already solves a lot of the use State stuff we need so if I wanted to convert what I'm doing with use State down here to a signal I could create a to-dos signal we'll say that's equal to a signal and I'll also just create a function that essentially encapsulate all of this code inside of here for getting my value from state so we'll just say like get to-dos is going to return these values right here and then we'll just call that inside of our signal to get our default value there we go so as soon as my application runs it calls this gets to-dos function and it just gets it from local storage now we have our to-dos so we can remove all this code right here for setting our to-dos we don't need to worry about any of that and here where we're setting our to-dos we can just directly set the value variable for our to-dos so we can say here our to-dos doval is going to be equal to taking our current to-dos doal you know going over that and then adding a new to-do into that super straightforward same thing here I can just say to-dos Dov value is equal to and all I want to do is just take my current to-dos Dov value map over it and get the new information so I don't have to worry about any of that setting stuff worrying about what happens when I have an old version of it to do a new version of it Todo you know how I actually do my setting is it the function version or not I don't have to worry about any of that you can see if I give that a quick save and I actually use that to-dos so I remove this name section here and I'm using my to-dos Dov value down here you can now see I have my information in my list and it looks like everything is pretty much working as it is before you notice right now nothing's being stored in local storage cuz my use effect is not working because right now it's never updating since my to-dos never actually changes but we can get around and we can fix that this is because also this signals library has use effects essentially built into it by the effect function so this effect function all you need to do is anything that you want to update based on a signal value you put inside here so in our case we're updating our local storage every single time our to-dos change so every time our to-dos thatv value changes I want to update the information in local storage and the really crazy thing about this I don't need to pass a second dependency array into here since I'm using my to-dos that value in this function the signals library is smart enough to look at that and say okay I am using to-dos inside of this effect so every single time my to-dos changes I'm going to rerun this effect so let's get rid of this code that we had down here now you'll notice we're not using use state or use effect anywhere you can see I can essentially completely remove this technically we are using use state right here but we could change that if we wanted it really doesn't matter but you can see we have no use effects or anything but now when I add something to my list you can see I have these four items refresh it's all persisted I uncheck these everything is persisted so now I have everything being persisted I have no rules to worry about I mean all of this code is not even in a react component I could put this code anywhere at all it doesn't matter and it's amazing that it's just all working out of the box without having to do any extra work and the best part is this is incredibly performant because of the next thing I'm going to show you so we want to put the completed to-dos in the navigation bar well I can just export this signal right here for to-dos I can use that other places so let's go into my nav bar I'm going to come in here and I'm going to import that to-do information so I'm going to import to-dos from that too list and now what I can do is I can actually get whatever the value is going to be from my to-dos so in my case I would need to filter it and so on so let's create a div and this is going to say completed and then inside of here we're going to take our to-dos we're going to filter our to-dos and we only want to get the to-dos where that completed property is true there we go and I specifically want to make sure I do the value for my to-dos there we go give that a quick refresh and actually I need to make sure I get the length of this if I want to just get a number so we'll just come in here with the length so now you can see I have two completed todos which is pulling from this value and now you can see it's down to one and zero and so on but the really cool thing that's happening here if I go to my console I just clear everything out when I change this for example you notice only my Navar and my to-do list are changing because those are the only things using this signal and if I update this state right here you can see it's only the to-do list changing but down here when I change this I'm only updating those two components that actually use this information which is incredible now one important thing to note is if you are using signals built from signals you should generally use a computed signal for example if I wanted to use this in other places throughout my application I could turn this into its own signal that has all the same properties but it would be computed from those other signals which just means it's going to automatically update when my signals that depends on changes to show you what I'm talking about we're going to use the computed function we're going to get that from the signals react library and we're going to come in here this works pretty much exactly the same as effect but inside of here I'm actually just going to return so in here I'm going to return this right here this is essentially going to give me that information and this is my completed to-dos count there we go let me make sure I spell that right and now this gives me a brand new signal that has its own value property on it so I could say value and so on I can use this inside of effects I can use it in other computed signals I can pass it all over my application to make sure everything auto updates properly if I wanted to use this in other places and now I can just place that into my jsx down here give it a save and I'll get the exact same response as you can see up here this completed is properly rendering when I'm changing my values here and it's only rendering the two components that change even though they're completely separate from one another this is a really great way to pass information between multiple different components now another thing that's really cool about these signals is inside of this Library there's actually hooks built in so if I wanted to use my signals inside of my to-do list component I can come in here and I could use the use signal hook or the use signal effect hook these both are going to allow me to use a signal or an effect inside of my actual component and it's going to work with react properly but a lot of times when you're dealing with signals you don't actually need them inside your components you can pull them out of your components so they can be used in many different places now a lot of you may notice if you're looking at this code that it's not 100% optimized for testing and the reason for that is is because if we look at my app here my navbar doesn't have any props being passed in but it's pulling in data from another file this makes it very hard to actually test this instead it would be much better if I passed my to-dos into my Navar so that it's a lot easier for me to test my nav bar so instead of actually poting it in like this I pass it into my nav bar like this so it's going to work now the problem with this is I need to rewrite my code a little bit but signals make this incredibly easy and this is actually how the preact signals Library recommends you do things with signals is you extract out the creating of your signals into its own file or section and then you pass those down props just like you do inside of normal react you still get all the same performance gains but it's much easier to test this as well so what I'm going to do is I'm going to go into my to-do list and all this information for creating all this state I'm actually going to pull all of this out I'm going to move it into my app instead I could create a separate file for this if I wanted to be extra diligent with clean code but for our cases this is simple enough code we can just paste it directly into here and I'll make sure that I import this signal Library so let's just get the signal Library being imported just like that we'll get it from that react library and we'll do the exact same thing down here with effects as well so we have all that being passed in and now in my to-do list I can pass down my to-dos and in my nav bar I can pass in my to-dos as well just like that so I'm passing things down just like I would in normal react it makes things for testing a lot easier now if I go into my to-do list I can remove all this signals related code and I'm getting my to-dos in from my props and now if I save you'll notice magically everything is working just fine I can add a new to-do my completed props up here is updating and if I look at the actual components that are being rendered by just clearing out when I toggle you'll notice again only the components that depend on that state or rendering even though I'm storing the state technically in this app component and it's being passed down from the app component is not rendering everything cuz it's only rendering the places it's actually used in and everything works just like normal react I can easily test this component by passing in my own to-do signal into here without having to worry about importing from different files so all this works just like you're used to with normal react now I've really only scratched the surface of what you can do with signals so you can see the power and hopefully it's got you excited about them and if you want to see a full crash course on signals let me know if I end up creating one I'll link it right over here for you and with that said thank you very much for watching and have a good day
Info
Channel: Web Dev Simplified
Views: 441,676
Rating: undefined out of 5
Keywords: webdevsimplified, react signals, reactjs signals, react useSignal, react hooks vs signals, react hooks
Id: SO8lBVWF2Y8
Channel Id: undefined
Length: 16min 30sec (990 seconds)
Published: Tue Oct 31 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.