Introduction
Let me preface this article by stating that my opinions in this article are based on what I learnt about frontend development within a span of last 9-10 months. I am not an expert on anything and the article below is more of a collection of my own thoughts at this stage I hope to revisit and revise in future. That said, I think some of it might interest people who work with react. Hopefully, I would get some feedback and in the process learn something new.
I think it is also important to contextualize the article by stating some facts about myself and how do I approach new subjects.
I try to think from first principles as much as possible.
While I didn't know anything about development, I wasn't
completely new to programming when I started.Since, I don't have any production experience yet, so some of what I am going to say could be disputed on pragmatic grounds.
I learn new technologies by understanding the core fundamentals of a technology and building its mental model before building projects with it. This is probably counter intuitive but it works for me.
With that out of the way, lets start!
My Web development Journey
My first attempt at learning front end development started by searching for a good tutorial online, but ended up wasting a significant amount of time before deciding on Freecodecamp . My plan was to learn HTML, CSS and JavaScript in order. However, even after going through Freecodecamp's sections on HTML and CSS, I still felt like I didn't learn anything by typing commands inside placeholders and by the time I completed the section, I had forgotten most of CSS properties. The search for yet another course led me to the Odin Project. Their foundations section finally gave me a high level overview of what HTML, CSS and JavaScript are and how they fit together to deliver interactive user experiences. After the first course, I did not continue with the Odin project. Beyond this point, my learning was highly non linear and chaotic.
Around this time, I started developing toy games like tic tac toe, rock paper scissors etc. with HTML, CSS and JavaScript but unexpectedly the complexity of code started growing disproportionately with number of features and soon I found myself writing lots of nested event listeners, managing complicated global states and having to sync DOM node with global state. Tt is important to point out I didn't know about frameworks just yet. At that time, I thought about a lot of abstractions which could simplify my development such as these:
A reactive API in browsers to bind JavaScript variables to any property of DOM node(s) as well as JavaScript expression(s) recursively. For instance, denoting dependency by "->",if we declare A->B(A+1) ->C(B+2), then changing A triggers update on B which triggers updating C.
Primitive building blocks to construct self contained components having local state which could be composed together hierarchically to build larger components. In hindsight, it was looking for something similar to web components because I believed anything I would make would not be as efficient as native browser's api.
These ideas emerged separately and I didn't spend time refining them or thinking about how would both of them play along with each other. After searching for and failing to find such browser apis probably owing to the phrasing of my google searches which were pretty uninformed at that time, I spent a lot of time on YouTube watching videos on development in general to get a broader perspective on development and this is how I got introduced to React.
React
My first reaction about React was literally Holy Shit! I wish I had known it sooner, not specifically because of react but the main theme that the idea of building reusable components instead of imperatively managing all DOM nodes at the same time was common across all frameworks. Before delving into react I looked for similar frameworks in order to evaluate which one would be more suitable. I was comparing Angular, Vue and React at that time. I didn't go with Angular because it was criticized heavily in a lot of front-end communities. I tried Vue but I got intimidated due to larger API surface. In the end I chose React because it seemed to do one thing and had a smaller API surface. I started with React hooks right away instead of class based syntax because that was the newer syntax. With React at my disposal, I realized I could suddenly build comparatively larger applications rather quickly and kept building small widgets with it.
Problems with react
To cut the story short, after spending some time with react I realized I disagreed with React's reactivity model on a fundamental level (or so I think at the moment). For instance I don't get these aspects of React:
The Context API
Just stare at it for a few seconds.
function App() {
return (
<Provider 1>
<Provider 2>
<Provider 3>
<Provider 4>
<components/>
</Provider 4>
</Provider 3>
</Provider 2>
</Provider 1>
);
}
- It is unpleasant to look at.
It is inefficient by default. Whenever the context changes, React will rerender all the consumers of Provider instead of only rerendering components which need to be updated.
Trees are a natural DSL to describe parent child relationships, and here it suggests Provider 1 is in some sense a parent of such as contains Provider 2 which is neither true nor makes sense.
React exposes the interface used for managing local state of components for managing context as well (useState, useReducer..) which can have different requirements because it is a different object. Furthermore, global states/context are something which exist alongside the component tree, not a part of it but React represents them (Providers) as a component in the component hierarchy.
The problem of Unnecessary Rerenders and its solutions:
React works by keeping an in memory representation of DOM tree which is made up of React components. After each state change, React re runs components which includes all computations performed within the components, finds out which parts of DOM needs to be updated by comparing its virtual DOM with the state changes and updates those parts. The problem with this model is unnecessarily re running all computations within components after each state update. It can also have performance implications.
UseMemo/Usecallback owes their existence to circumvent performance issues which might arise out of re running expensive computations repeatedly. These APIs offer us a way to memoize the result of expensive computations which are only re computed only when their dependencies change. However, it can get tricky because now each re render React compares if the dependencies have changed instead and if the comparison requires deep equality check, it can potentially take more time compared to re computing the memoized values!
As I see it, the mechanism a framework chooses to implement a feature isn't important, what is important though is that details of implementation should be completely transparent when using that feature. Applied to front-end frameworks, whether it uses virtual DOM or not isn't particularly important as long as its transparent to us when we use it. In the case of React we have to learn about it when we get unnecessary rerenders or/and then look for useMemo/useCallback as a remedy.
Manual tasks which should be automated by framework:
Having to explicitly declare dependency array in useEffect and do timer and event listener cleanups on unmount is a routine task which should be automated by the frameworks, especially so if a framework aims to be declarative.
The functional React
Admittedly this is subjective so you can ignore it if you want.
React components are modelled as functions in modern React but this interface is confusing and difficult to reason about because these components have persistent local state and attached life cycle events which can mutate this state.
As an aside, these components seem to behave more like actors rather than functions or classes. For instance Actors have the following characteristics which make them or something similar a suitable choice for modelling components.
(i) Actors have local state.
(ii) Actors can send and receive messages and update their behavior according to them.
(iii) Actors can spawn new actors recursively.
Components have similar structure.
(i) Components keep a local state.
(ii) Components update their behavior in response to new events which can be modelled as messages.
(iii) Components create and manage new components (child components).
We can have different kinds of actors as well for dealing with different activities such as data fetching and
caching, batching up updates to UI, Routing and so on. This model could also make use of web workers and upcoming WebGPU seamlessly to improve performance on some computationally expensive tasks.
Would love to know people's thoughts on this line of thought.
Final Remarks
Despite these inconveniences, React has one thing going for it, a large Community and a mature ecosystem around react (open source libraries, docs, tutorials). Consequently, it is easier to find people who already know react which can be a deciding factor for choosing React over relatively unpopular frameworks like Elm or Svelte.
Let me know what do you think in the comments :)
Top comments (0)