Skip to content

Instantly share code, notes, and snippets.

@peerreynders
Last active August 22, 2024 08:46
Show Gist options
  • Save peerreynders/b1e30a4950ca7eed9b2f547f1bf2f151 to your computer and use it in GitHub Desktop.
Save peerreynders/b1e30a4950ca7eed9b2f547f1bf2f151 to your computer and use it in GitHub Desktop.
React is a (view component) framework

"Art prior" to React:

Martin Fowler: InversionOfControl (2005-Jun-26)

Inversion of Control is a key part of what makes a framework different to a library. A library is essentially a set of functions that you can call, these days usually organized into classes. Each call does some work and returns control to the client.

A framework embodies some abstract design, with more behavior built in. In order to use it you need to insert your behavior into various places in the framework either by subclassing or by plugging in your own classes. The framework's code then calls your code at these points.

The litmus test:

  • If your code calls it, it's a library.
  • If it calls your code, it's a framework.

Looking at the React tutorial Starter Code ReactDOM.render() is the only part of React that your code calls. The rest, i.e. the majority of your code, is called by React.

Ipso facto - React is a framework because it is in control when most of your code runs.

https://reactjs.org/

A JavaScript library for building user interfaces

Calling itself a library is diluting (and undermining) the meaning of established software engineering terminology. At best it's evidence of ignorance of prior art, at worst it's propaganda (i.e. marketing).

At the time AngularJS already had established itself as a client side application framework which appealed to the enterprise market with its propensity to favour (complex) "batteries included" products and tools. By calling itself a library React excused itself from being directly compared with AngularJS based on feature set while at the same time presenting itself as a lighter weight solution with an API that can be "learned in a weekend".

More accurately if one accepts that AngularJS is an application framework, React can be described as a view component framework. This reflects a difference in design philosophy. Both were originally designed to operate within the constraints of a single thread within the web browser.

An application framework which takes control of that single main thread takes on the responsibility to support the requirements of the entire client-side application. AngularJS was first released in 2010. JavaScript always had async callbacks but a lot of the AngularJS developer API had a distinct synchronous feel about it (previously much of Google's Closure Library felt like it was engineered to feel more familiar to a (synchronous) Java developer). It was only in 2011 that jQuery 1.5 introduced deferred objects. By the time React released in 2013 browsers were getting pretty close to supporting promises natively, making asynchronous programming (and design) just a bit more ergonomic.

Given this shift a view component framework prioritizes the runtime needs of the view logic over the needs of the application logic. That single thread is the UI thread ("don't block the main thread"). So the client-side "application logic" only gets a chance to process anything when it is given an opportunity by the view component framework (or indirectly by the browser via asynchronous processing).

Neither the application or view component framework approach is inherently better, they are just different. There are types of use cases and applications where one is a better fit than the other and there are operating environments that can shift the balance in either direction.

However presently the demands on that main thread have come to a point where something has to give (evocative of "The Free Lunch Is Over"):

As to "ignorance of prior art". Just some examples:

Point being, while software engineering is relatively immature compared to other earlier established engineering disciplines there already is a lot of knowledge (and terminology, likely more than a single person can know) that is relevant to this day that predates the existence of React (2013), JavaScript (1995) and the World Wide Web (1989).


Addendum in response to https://medium.com/@attilavago/i-read-the-full-post-1340a3f338a9

though I feel it should not just be based on ReactDOM.render().

That isn't the core argument. Fowler references the 1988 Johnson & Foote paper:

One important characteristic of a framework is that the methods defined by the user to tailor the framework will often be called from within the framework itself, rather than from the user's application code. The framework often plays the role of the main program in coordinating and sequencing application activity. This inversion of control gives frameworks the power to serve as extensible skeletons. The methods supplied by the user tailor the generic algorithms defined in the framework for a particular application.

ReactDOM.render() is simply the entry point so React can "play the role of the main program in coordinating and sequencing rendering activity" and behave as a framework.

Again Fowler stated:

you need to insert your behavior into various places in the framework either by subclassing or by plugging in your own classes. The framework's code then calls your code at these points.

The starter code even demonstrates this - the Game component extends the framework class React.Component.

  • it's React which calls Game's constructor to create an instance of the component.
  • it's React which calls the render method (or any of the lifecycle methods)
  • render returns framework specific types - react elements (somewhat obfuscated by JSX).
  • Apart from browser supported async processing your components cannot make a move without React.

All of the above are characteristics of a framework.

One could argue that jQuery is consuming my code at some level too, yet we still consider it a library.

jQuery for the most part is used as a layer between your code and the browser. Your code calls jQuery to fullfil some objective - and when it's done, it's done. jQuery doesn't do anything until your code calls it the next time. Some jQuery code may run due to being referenced in an event handler or because of an async callback but that is just in the nature of browser operations. jQuery as such isn't in control, your code is. jQuery is called a library because it's simply a collection of useful helpers; after you call each method your code is firmly back in charge.

With ReactDOM.render() your code hands over control to React, past that point React is in full control and your code only runs when React decides to run it. React isn't a layer that your code calls to deal with the nitty-gritty of the browser but an environment that isolates your components from the browser and uses your components when it deems it necessary - which is exactly what a framework does.

Now maybe because callbacks are omnipresent in JavaScript, the "Hollywood Principle" becomes more difficult to spot:

"Don't call us, we'll call you" Relevant when you are writing a class/component that must fit into the constraints of an existing framework. You implement the interfaces, you get registered. You get called when the time is right. This requires a distinctly different way of thinking from that which is taught in introductory programming where the student dictates the flow of control.

  • React calls your components when it needs to create React elements and it manages component state outside of your component.
  • Your code calls jQuery methods to fiddle with the browser's DOM.

but I feel that React essentially still does the same as jQuery, at a different level — the VDOM.

It's the inversion of control (IoC) that makes all the difference. Granted React isn't a full fledged application framework the way Angular is but the way it uses IoC makes React a framework in the general sense. If you want to call it a VDOM framework, fine.

And exactly because React takes almost full control of the environment it has to provide the sort of infrastructure you typically see in application frameworks to make it possible to build applications. i.e. Context and Hooks.

Then there are those patterns that hint at building full fledged applications by splicing "the rest" into or in between the visual components:

So both jQuery and React stand between your code and the browser('s DOM) but your code's pattern of interaction with them is very different.

  • jQuery is a collection of helpers that your code calls whenever it needs to.
  • React on the other hand calls your code - "The components supplied by the developer tailor the generic rendering algorithms defined in React for a particular application" (paraphrasing "The methods supplied by the user tailor the generic algorithms defined in the framework for a particular application." ; from Designing Reusable Classes).

Update 2021-07-23

The flawed logic behind "React is a library because it isn't an application framework":

  • Library vs Framework
  • Application frameworks are frameworks
  • React isn't an application framework because it isn't a "batteries included" solution
  • Conclusion: React is a library

Compare this to:

  • Reptile vs Mammal
  • All species of whales are mammals
  • A mouse is very different from any species of whale. It is much smaller than any whale and lives on the land while whales live in the water.
  • Conclusion: A mouse is a reptile

See the problem?

@vibecode
Copy link

vibecode commented Apr 8, 2021

Thanks for this, I can't stand people arguing that React is a library just based on how many features it has out-of-the-box or how many things it does. The difference between frameworks and libraries is not quantitative, but a conceptual one. And Inversion of Control is exactly the right criteria to see that we are dealing with a framework.

@Rockson
Copy link

Rockson commented Jul 16, 2021

The only weird thing is React's docs stating that it's just a library. Maybe a commercial move since people tend to stay away from the word framework

@peerreynders
Copy link
Author

peerreynders commented Feb 7, 2022

Buried somewhere in HN comments from early 2017 [1]:

Last time I had the library vs framework argument (1996), I concluded with this definition:
You call a library.

A framework calls you.

I don't know React, so can't say which it is.

(acemarke [2]):

Yeah, I would agree that in that sense, React is a framework. You call ReactDOM.render(), but from there it instantiates your components and calls their lifecycle methods as appropriate.

On the flip side, it's nowhere near as all-encompassing as Angular or Ember. No built-in AJAX handling, no complex data model manipulations, no preferred project architecture. So in that sense, it's much closer to the library side of things.

😏

Pete Hunt - React: Facebook's Functional Turn on Writing JavaScript 2016:

The component is a fundamental building block on top of which we've built our own internal framework.

@peerreynders
Copy link
Author

I distinguish between a library and a framework by looking at the Inversion of Control. When I use a library, I slot the library into my code and call into the library in the appropriate places. A framework, on the other hand, makes itself the center of the universe and offers slots for me to slot into. It’s the Hollywood principle: You don’t call the framework, the framework calls you.

Offramp: For me, this is one of the benefits of libraries vs frameworks. Especially at a larger scale, you start by using a framework, but at some later point in time, you find yourself having outgrown the framework (or the framework has stagnated for too long), and you want to switch. This can be really hard, because frameworks shape your code, and each framework is different, so there is no easy migration path. The contact surface with libraries, on the other hand, is often very small, making a switch from one library to another a much smaller task, with a low blast radius.

"The cost of convenience", 2022-06-17

  • because frameworks shape your code

i.e. frameworks by their very nature are opinionated.

@peerreynders
Copy link
Author

Jack Franklin – Abstractions, complexities and off-ramps – All Day Hey! 2023

When we write code, we can either be in control of it or we concede control over to the code that we're relying on.

So, either our code is in control—or typically on a framework, the framework is in control.

Give a practical example of what this looks like:

If I'm writing code and I'm in control, I will change some data and tell the code to do something. Re-render, update, whatever it may be.

If I'm working with a framework, what I will instead do, tell the framework I have done something and it will do the rest for me.

In React, you set states, but you yourself are never going to tell React to re-render your website.
React is going to do it for you.

You are hooking into what the framework is doing. The framework is controlling your website at this point in time.
This theory is known as the inversion of control.

This is actually a really good way to think about dependencies and the whole libraries versus framework debate.

As Surma puts it in his blog post, the cost of convenience, a running theme, libraries and a frameworks can be distinguished by looking at the inversion of control.

  • If you're using a framework and hooking into the life cycle, its way of working, and abstractions, it's in control.
  • If you're using a library, typically you tell it what to do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment