I'm going to simplify it even further here for demonstration purposes, but it all starts with signals like we saw. And at its core, you just view a signal as a getter and setter function pair that close over a value. Of course, there's a little bit more to it than that. And for that, we're going to need subscription.
So let's update our signals, do a bit more. Now on read what we want to do is check if there's a current observer. And if there is, we're going to add it to a new subscriber set that we create when we create our signal. On right, we update our value still, but now we actually iterate over those subscribers and call them to basically notify them that something has changed. And that something that needs to be notified are our effects, which are the other side of our equation.
Here you can see the implementation for get current observer. What we have is a stack. This context is just an array, global context. And we just grab whatever's atop the array to see what's currently running. For our effect itself, when it's created, it's executed immediately. And then it goes through the cycle of clean up dependencies or subscriptions, push itself onto that stack, so that when we execute the provided function, it's there and can be added to the subscriptions. And finally, it pops itself off the stack. I'm gonna put the code side by side, so you can kind of see this better as we go over our example. Essentially, we create our signal, like our name signal, and it returns our read and write functions. Then we create our effect. It executes, pushing itself onto that stack. Then it runs the function and it reads from our name signal, at which point it sees the current observer, which is that effect, and adds it to its subscribers. Then it logs it to the console and the effect finishes running, popping itself off the stack. Sometime later, our signal is updated, which sets the new value and then executes our list of subscribers. In this case, it's that effect, which executes it again, cleaning up the dependencies and we just start the whole cycle all over again. And that's really it. From there, we can build a foundation for other primitives. A lot of them are not essential. They can be used as needed, but an example of a few important ones that ship with Solid are createMemo, which can be used to cache expensive computations, createStore, which is a proxy which enables deep-nested reactivity, and createResource, which is our first-party primitive for data fetching and suspense. But enough on reactivity for now. Let's get back to our example.
Comments