Episode 23 - Building a minimal reactive framework - Episode Artwork
Technology

Episode 23 - Building a minimal reactive framework

In this episode, Minkou Gegef explores the fundamentals of building a minimal reactive framework, focusing on concepts like signals, state management, and component composition. Listeners will gain in...

Episode 23 - Building a minimal reactive framework
Episode 23 - Building a minimal reactive framework
Technology • 0:00 / 0:00

Interactive Transcript

spk_0 Welcome to the programming podcast.
spk_0 Here you can learn about computer science concepts in a brief and accessible way.
spk_0 I'm your host, Minkou Gegef.
spk_0 Hello everyone.
spk_0 In today's episode I'm hoping to give you a high level intuition on how reactive frameworks work.
spk_0 This episode is inspired by a blog post that I wrote about a week, a week and a half ago,
spk_0 on how you can implement your own very simple reactive framework with fine-grained reactivity and
spk_0 signals in only 200 lines of code. And this implementation includes the components model of the
spk_0 framework. It allows you to build components. It includes the rendering as well as the
spk_0 signal's implementation itself. So it is pretty simple and it will enable you to build pretty much
spk_0 any application out there. Okay, this is going to just give you an intuition. This is not exactly
spk_0 how frameworks such as Angular, Solid or React work. They have a variety of different
spk_0 reactivity models and variations of these reactivity models. But I'm hoping to be close enough
spk_0 so that you can understand some of the essential differences between the different
spk_0 underlying concepts in a web framework. So just let's say dynamic and static parts of the view,
spk_0 reactivity systems states and so on and so forth. So today we're going to look at a couple of
spk_0 concepts. First we're going to make a very quick recap of signals and put them into the context
spk_0 of a web framework. After that, we're going to briefly talk about state management and how
spk_0 signals can support us in managing state inside of our components. We're going to briefly discuss
spk_0 static versus dynamic parts of the view because this is something that many frameworks such as
spk_0 Angular, Solid.js, they create a distinction between these two. And we're going to briefly touch on
spk_0 Trollflow and how we can implement it just by using signals. So first, let's make a very quick
spk_0 recap about signals. If you haven't listened to the previous episodes that was entirely dedicated
spk_0 on signals in its only 10 minutes, I'll recommend you to have a look at it. Just listen to it.
spk_0 But if you haven't, well, the signal is just a wrapper around a primitive or non-primitive value.
spk_0 That's pretty much what a signal is. We can get this value or we can replace it with a new value.
spk_0 We can set it. Additionally, we can use a concept called effect. And effect is just a function that
spk_0 accepts a callback. When we read a signal inside of this callback, the effect remembers that we
spk_0 are interested in this signal or the signal remembers that they're interested in this effect.
spk_0 So anytime when we update the signal, we're going to invoke the callback that we have passed to the
spk_0 effect. That's all you need to know about signals. That there are wrappers around values. We can
spk_0 set them. We can read them. And when we read them inside of an effect, every time when we set
spk_0 their value, the effect will be invoked. That's all. Now something cool about signals is that they can
spk_0 be really great containers of the state inside of our applications. Imagine we have a toggle component,
spk_0 like a component which allows us to toggle its content. We can let's say make it visible or invisible.
spk_0 Or we can represent this very easily using a signal, which is a Boolean value. Let's say visible,
spk_0 which by default is, let's say true. And when we toggle the value, we're going to update the signal
spk_0 and make it invisible. If we read the signal inside of an effect, every time when we toggle the value,
spk_0 the effect is going to be invoked. So we can perform a certain action. This action could be anything
spk_0 you want. It could be some complicated calculation or it could be just updating the DOM.
spk_0 So inside of this callback, inside of this effect, when we read the visual state or the visibility
spk_0 state of the content, we can perform an action. Let's say we have the content of this component.
spk_0 When we read the visible signal, if the visible signals value is true, we can just set the inner HTML
spk_0 of the host element or the element of our component and visualize this content. When the value
spk_0 of visible is false, we can just delete it or like set its display in none or do whatever we want.
spk_0 So that's on a high level how we can take advantage of signals in order to manage the state
spk_0 in our applications and make the framework reactive. What does a web framework consist of?
spk_0 Well, web framework consists usually of components and we can compose these components in order to
spk_0 create the user interface of our applications. Inside of this components, we'll keep state and we
spk_0 would wrap the state in signals so that we can notify the framework when the state has changed.
spk_0 And from there on, the framework can use an effect in order to react to this change and update the view.
spk_0 Something interesting about the views is that they need to be composable. You need to be able to
spk_0 compose components into more complicated components. Let's say you are building a scheduler.
spk_0 Well, in the scheduler, you most likely need a bunch of buttons. You'll need tables in order to
spk_0 visualize the different events that are happening throughout the week. You need variety of different
spk_0 components that you need to compose together. This is the composites design pattern that we have
spk_0 from the book of the Ganga 4. And it is an important property of any component model out there.
spk_0 We can compose components by building them into one another. Additionally, we can use
spk_0 control flow or some kind of like special more privileged components that are coming directly from
spk_0 the framework. In different frameworks, we have the control flow being either a native feature
spk_0 of the templating system or the language, for example, in JSX. The control flow is just part of
spk_0 the language. You're just reusing the JavaScript control flow and very often using the standard operator.
spk_0 In framework, such as the Angular or Svelte, the control flow is part of the templating system.
spk_0 See a very first class citizen in the framework functionality. And usually the reason for this is that
spk_0 the control flow needs to have some special understanding of your application.
spk_0 If we're building a web framework from scratch just by using signals,
spk_0 we may want to embed the control flow instead of our framework as well. Let's look at a very
spk_0 simple example of how we can take advantage of the control flow. So if we have an if statement
spk_0 within our templating system, it is going to work very similarly to this toggle component that I
spk_0 described just a couple of minutes ago. If the condition of this statement is true, this means that
spk_0 we would like to render a particular part of the view. If this falls, we would like to remove it
spk_0 from the view. Meaning that we can implement if statement very easily, we can implement it just
spk_0 by using effects and assuming that the condition of this statement is a signal. Instead of the effect,
spk_0 we can read the result of the effect and we can respectively render or remove this particular part
spk_0 of the view. Other parts of the control flow such as let's say a four statement would work very
spk_0 similar. We would read the collection, which we're assuming is coming to us as a signal. And once we
spk_0 get this collection, we're going to trade over the individual items and render them one by one.
spk_0 Real real world web frameworks would not work exactly that way because we can't re-run
spk_0 the collection every time when we receive an update. Very often, we update only one or just a couple
spk_0 of items from this collection. It's not worth just destroying the whole world and re-randering
spk_0 the collection from scratch. What we would do in framework such as Angular, React, and others
spk_0 is to implement some kind of a different logic. That's why often the individual items in our
spk_0 collections, they have keys or track by in Angular, which allows you to give the two different
spk_0 collections, figure out what exactly changed and only re-run the real differences. But the basic
spk_0 implementation of control flow can just use signals and effects. And that's pretty much it.
spk_0 There is one more piece that I'd like us to look into. And it is how do you update individual
spk_0 properties or individual, like let's say text by using signals in a reactive framework?
spk_0 You can approach a problem in a very similar way. If you would like to update text, there is
spk_0 some dynamic value that could change. Let's say the user name or we have a counter and on every
spk_0 next iteration who would like to update this counter with its next value. All you need to do here is
spk_0 just use a text note. You can just wrap reading the signal that is representing the counter instead
spk_0 of an effect. And every time when the counter changes, we would like to update the value of the text
spk_0 note just by setting the value of the text note, which means that we will need to have the text
spk_0 note available within the effects function. Updating a property or an attribute of a particular HTML
spk_0 element will work exactly the same way. We just need a reference to this HTML element. We need to
spk_0 know which property or attribute will be updating and when the effect, excuse me, when the signal
spk_0 that we have bound to this particular attribute changes, we'll just get its value, read its value
spk_0 in the effect and update it. I know this tool may sound a little bit too abstract. That's why I
spk_0 have provided this very simple implementation to the framework that I mentioned on just about
spk_0 200 lines of code that you can review on your own. I promise implementation is probably
spk_0 significantly simpler that you don't anticipate. We have just one render function that knows how to
spk_0 render these individual notes in the view. And for some special notes that rely on signals,
spk_0 such as control flow, it creates effects so that every single time when we change the value of
spk_0 the signal, we can react to this change and update the view. So in the last couple of minutes,
spk_0 I'd like to discuss how we can implement the rendering functionality in this hypothetical
spk_0 framework because it is a pretty interesting algorithm and it shows us how exactly we separate
spk_0 the static versus dynamic parts of the template. Let's say that in our component, we have a bunch
spk_0 of different HTML elements and inside of one of them, we have a binding. While these HTML elements
spk_0 are going to be the static part of the view and the dynamic part of the view is going to be this
spk_0 binding, this expression that is coming from JavaScript. Additionally, inside of the
spk_0 view of this component, we need to be able to compose different components, which means that
spk_0 we're going to create a tree-like structure. We're going to have a component tree, which is the
spk_0 composition of all the components, and inside of every single one of these components, we're going
spk_0 to have some kind of a view or a template that is a composition of different notes. They could be
spk_0 HTML elements or text notes or anything else. Actually, that's pretty much the option. They could
spk_0 be HTML elements, text notes, comment notes. They could be just different types of DOM notes.
spk_0 Meaning that our rendering algorithm needs to be recursive. It needs to know how to render a tree.
spk_0 So it's going to start from top to bottom and for every single node, we're going to render the
spk_0 node and traverse its children. And for each one of their children, we're going to render them using
spk_0 the exact same algorithm. The nodes could be of different type. They could be just static HTML
spk_0 notes, or they could be dynamic notes, such as let's say conditional statements or iterators or
spk_0 like some kind of four loops. They could be also in between. We can have static HTML nodes that
spk_0 have some dynamic parts. Let's say individual attributes that could be dependent on the value of
spk_0 a signal. So in this case, we're going to render the individual static parts just by using
spk_0 document.create element, specifying the name of the element, and that's it. Let's say
spk_0 though that the content of this specific HTML element is dynamic. Let's say it's text content is
spk_0 dynamic. Or in this case, we can create an effect inside of this effect. We can
spk_0 hold a reference to the HTML element and we can read the value that the element's content
spk_0 depends on. So every time when we change the value of the signal that the content of the
spk_0 DOM node depends on, we can update the inner HTML or the inner text of this particular DOM node.
spk_0 We can apply the exact same thing to attributes as well. Let's say we have dynamic styles.
spk_0 We can use CSS in JavaScript and just have a string that represents the styles of this particular
spk_0 DOM node. Well, we can keep a reference to this DOM node inside of
spk_0 an effect. And every time when the signal representing the styles of this DOM node changes,
spk_0 we can just use elements.styles equals to the string that is produced by this particular signal.
spk_0 This is pretty much how a reactive framework would work by using this very simple primitive code
spk_0 signal. We're going to keep the state inside of our application within signals and we're going to
spk_0 propagate changes in the state with effects. In this particular model, we are using signals for both
spk_0 notifying the framework that something has changed and also telling the framework where exactly
spk_0 the state that changed this, which attributes was affected or which part of the view.
spk_0 In many other systems, we have an alternative approach. Let's say in systems such as React,
spk_0 you would notify that something has changed and from there the framework is responsible for
spk_0 figuring out how this thing changed. In Angular nowadays with signals instead of
spk_0 getting blind notification that something has changed potentially in the application,
spk_0 now go figure out what signals are notifying us that something changed in this particular
spk_0 component. Go check this component, update its view so that we can propagate the changes and
spk_0 synchronize the view state with the view. That's pretty much everything that I wanted to share today.
spk_0 We cover a lot in about 10-15 minutes. We discussed briefly what signals are,
spk_0 because these wrappers allow us to track changes in the Rob values over time. We discuss how we can
spk_0 build a very simple framework by using signals and effects, tracking the changed values
spk_0 instead of effects from there taking them and updating the corresponding DOM nodes. That's pretty
spk_0 much how it is. We discussed that composition of components. It's what represents our view model
spk_0 and we briefly touched on a DOM on a component rendering algorithm that is recursive and can
spk_0 track the dynamic and static values. The dynamic values that correspond to certain bindings
spk_0 that we can implement with signals and effects and static values that are just simple DOM nodes
spk_0 that we render into the browser. Well, I hold this episode was useful and if you would like to
spk_0 learn more about how you can implement your own simple framework, make sure you check my blog.
spk_0 You can find all the resources at podcast.mgachive.com. Thank you and until next time.
spk_0 You can follow me on social media at mgachive.mgchtv.
spk_0 For resources and recordings are also available at podcast.mgachive.com. Thank you for listening.