Developing reactive interfaces from the ground up (3/3)
We have discussed issues relating to reactivity, worked with the signal-oriented approach, and have completed the setup here.
Custom Signals and Events
Let’s add our component-specific signals and event-listeners.
All signals that our counter component will respond to
All events that will be fired by the respective elements of the counter component
And finally, we wire-up the entire setup in init()
The init() function
One thing to note: towards the end of the demo (specifically after 1:48), you might have noticed that sending the ‘set’ signal repeatedly updates the span even though the state value is the same. This is true for all signals, because we have not incorporated any bail-out functionality wherein we can skip a render when the previous state value equals the updated state value. Although this can be trivially written by keeping a sort of dirty context object in the component and referring to that during render.
Certain aspects have been deliberately omitted:
- What about nested components and passing data to children and/or accessing data by the child from the parent, if this architecture is to be followed?
- What about sharing/passing data across adjacent components?
Well, to be honest, at this point in time, my job is not to replicate behaviours of established libraries and frameworks, but to create a structured environment that helps me. I feel that I can write pure HTML and see the output at a glance, only then will I start adding functionalities in the form of signals to one single big component, on a per requirement basis. For sure when one crosses that limit of one single component, maintainability becomes an issue (or nightmare).
Sharing data across components can probably be done through custom events with respective components subscribing to such events. I believe this can also be extended to nested components as well. Events will keep all components loosely-coupled. But again, I haven’t yet implemented these thoughts.
Also, on reaching the end of the article you may have thoughts about this entire architecture not adding any value because:
- We have to split the components into each file to maintain isolation
- If we then have to add each component script one by one like in the old days, won’t dependency management fly out of the window and throw a runtime error on the final page load?
- What about code-splitting?
True. These are issues that really cannot be neglected, not at least in the way modern web apps are written and deployed. Still, first and foremost, I’d request you to not view this approach as a total comparable solution to what libraries/frameworks and package management tools provide you with. With that being said, let me help you out as much as I can:
- Can we take the help of bundlers (or plain old shell script) and package them into one file?
- To a reasonable extent, if an entire library or an entire framework runtime had to be fully loaded first before it could even start executing your app: can the act of replacing that imaginary entire bulk with our consolidated app script not make sense?
- Point number 2 above should always be seen in the light of a reasonably sized library/framework bundle size (approx. upper limit of 2 MB on a slow internet connection)
- If none of the above works, well I’d kindly request you to either re-iterate and/or refine the above approach of final deployment or go back to using the library/framework and the package management tools that work for you.
Hope this article has shed some light on demystifying reactivity and also provided a point-of-view on the process of realising a declarative approach from an imperative approach, displaying how things happen under the hood.