Reactivity with SolidJS

Signals & Side Effects

Ryan Carniato

Ryan Carniato

SolidJS Creator
Reactivity with SolidJS

Check out a free preview of the full Reactivity with SolidJS course

The "Signals & Side Effects" Lesson is part of the full, Reactivity with SolidJS course featured in this preview video. Here's what you'd learn in this lesson:

Ryan explains the relationship between signals and side effects. Signals are the state exposed to the application through getters and setters. When a signal is used inside a side effect, the effect will re-execute.


Transcript from the "Signals & Side Effects" Lesson

>> We're gonna start today looking at signals. Beginning of this is gonna be a little bit cold lecture heavy just so that we get some concepts out but we will get some code examples and see what's going on. Yeah, let's take a look at what a signal is.

This is our basic primitive. In Solid, we call them signals but in other frameworks they are known as observable, or, ref, or atom, or behavior. And it basically is a getter and setter that holds a value. This is not a magical example here. Essentially it's almost too simple where in Solid, we return a tuple.

But essentially there's a count and there's a setCount variable that comes out of our createSignal call. And the count variable when we call it as a function, it just returns the value and then we call the setter with the next value. Then you can just read it. This on its own is not too crazy, but this is kind of a good way to familiarize yourself with the syntax.

And in fact, if you look at other frameworks, they have different syntax here but kind of similar. Something like Vue, where they use the refs, they access the value by calling count.value, or they set a value by also using count.value with the setter. But what this is really doing is just calling functions in the background like if I was to try and implement Vue's ref in Solid, all I would be doing is using a getter and a setter to basically return a function and set a function.

I just want to point out that the key to this mechanism is actually that there's functions behind under the hood that are actually intercepting the get, the reads, and the writes, all right. And even I can take this further when I look at something like Svelte, because I mentioned before that they were using a compiler and it's kind of similar.

They might use an assignment call here and they might just read a variable as normal. But behind the scenes, their compiler is actually turning their set calls or turning your assignments into $$invalidate set calls. So there's actually under the hood very similar kind of concept here in terms of how the mechanics work.

Because signals on themselves don't do that much, I'm gonna introduce this the next primitive. I'm gonna skip over computed values because they probably the most complicated of the bunch and just get right to the side effects because signals on their own would not do anything of interest. Side effect, also known as reactions, or autoruns, or watches, or in some frameworks, even computeds, are basically why we do all this.

It's funny, we always use console log in these beginner examples, but really, it could be anything in there. Essentially the trick to these effects is that they run once executing all the logic inside. And then at any point in the future, when you update the value of something that was read under that effect, the function runs again.

So essentially, a simple example like this where we create a signal that is has a value of 0, we run this effect and it just console log 0 as you kind of expect. But then when you set it to 5 later, then it immediately logs 5, or you set it to 10, it immediately logs 10.

This is the a equals b plus c that I was talking about earlier. Essentially, it ensures that it's always in sync, always up to date no matter what changes. And it does this, as I've kind of already alluded to, from this concept of dependency tracking and automatic dependency tracking actually, and this as I mentioned is based on using functions.

That way, we can intercept all the accesses so we know what happens. These functions can be out in the open, they can be getters, they can be proxies, it can be under a compiler, but it's the same kind of mechanism. I've created a very simple playground, and I just wanted to kinda emphasize this.

This example is the exact one we did but it doesn't really, I put some extra console logs just to kind of see the timing but it is actually immediate, right? When we create our signal and then we run the effect the first time it does, immediately do the count.

We set the count, immediately sets it. It doesn't matter what we set this to, we can do this as many times as we want and kind of magically or not magically get our update. And in fact, we could probably, we can listen to as many of these as we want.

I'm gonna make a count and a count2 here just to get that in. Maybe we'll start count to 5, and now if we log both of these in the console log. And let's change some of these around a little bit, let's set count2 to10 or whatever. This actually set count2 to 10.

Then you can kind of see our function reruns, count goes from 0 to 5. And then the first count stays at 5 when we set the second count to 10. Essentially we can have as many of these signals being listened to by these effects. And this is kind of the core mechanic behind reactivity.

You can define as much variable state as you want, create as many effects as you want and just have a system that kind of stays in sync.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now