DEV Community

Discussion on: What is the difference between Library vs Framework?

Collapse
 
peerreynders profile image
peerreynders • Edited

From your point of view, React would have to give you control over the VDOM trough functions that you'll call to "be a library", which is kinda ludicrous.

I fail to see how that is in any way ludricrous. Call it a VDOM framework then.

What exactly does the JSX <p>{count}</p> do? It desugars to:

React.createElement('p', null, count);
Enter fullscreen mode Exit fullscreen mode

So a React (functional) component's return value is a ReactElement.

2005 Martin Fowler: InversionOfControl

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.

So while functional components have eliminated the need to subclass React.Component, functional components are "plugged into" React because that is how React creates the component tree and each and every functional component returns a ReactElement - a type that is specific to React and created by React via React.createElement. And the relevant location for that ReactElement is determined by the location of the component instance within the component tree.

A simple working example:

<!doctype html>
<html lang="eng">
  <head>
    <meta charset="utf-8"/>
    <title>React is a Framework</title>
  </head>
  <body>
    <main class="js-root"></main>
    <script src="https://unpkg.com/react@latest/umd/react.production.min.js"></script>
    <script src="https://unpkg.com/react-dom@latest/umd/react-dom.production.min.js"></script>
    <script>
     (function () {
       // https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts#L276-L279
       //
       // function createElement<P extends {}>(
       //   type: FunctionComponent<P>,
       //   props?: Attributes & P | null,
       //   ...children: ReactNode[]
       // ): FunctionComponentElement<P>;
       //
       //
       // https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts#L158-L160
       //
       // interface FunctionComponentElement<P> extends ReactElement<P, FunctionComponent<P>> {
       //   ref?: 'ref' extends keyof P ? P extends { ref?: infer R } ? R : never : never;
       // }
       //
       const render = ReactDOM.render;
       const h = React.createElement;
       const useState = React.useState;
       const useEffect = React.useEffect;

       // --- BEGIN user supplied component oriented application
       function App(_props) {
         const count = useCount(0);
         return h('p', null, count);
       }

       const MS_PER_COUNT = 1000;
       const START = document.timeline.currentTime;
       const increment = (value) => value + 1;

       function useCount() {
         const [_dirty, setDirty] = useState(0);
         // Base `count` on a fresh timestamp
         const count = Math.floor((performance.now() - START) / MS_PER_COUNT);

         useEffect(() => {
           const refresh = () => setDirty(increment);
           // Base `delay` on a fresh timestamp
           const delay = (count + 1) * MS_PER_COUNT - (performance.now() - START);
           const timeoutID = setTimeout(refresh, delay);
           return () => clearTimeout(timeoutID);
         });

         return count;
       }

       // --- END application
       // "React is your Application": handing over application to React
       render(h(App), document.querySelector('.js-root'));
     })();
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

That last render statement is where the "inversion of control" kicks in. render is the framework function that "plays the role of the main program".

Contrast that to µhtml which is a library:

<!doctype html>
<html lang="eng">
  <head>
    <meta charset="utf-8"/>
    <title>µhtml is a Library</title>
  </head>
  <body>
    <main class="js-root"></main>
    <script type="module">
     import { render, html } from 'https://unpkg.com/uhtml?module';

     const MS_PER_COUNT = 1000;
     const START = document.timeline.currentTime;
     const root = document.querySelector('.js-root');

     function update(timestamp) {
       const elapsed = timestamp - START;
       const count = Math.floor(elapsed / MS_PER_COUNT);
       render(root, html`<p>${count}</p>`);
       const refresh = () => requestAnimationFrame(update);
       const delay = (count + 1) * MS_PER_COUNT - elapsed;
       setTimeout(refresh, delay);
     }

     update(START);
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

html is a tagged template which returns an object that is designed to produce something that extends HTMLElement a platform type (not a framework type). render is a convenience function that attaches that DOM element instance to the indicated platform location.
In terms of the script the final statement invokes a user function (not a framework function) - so the user code is always running the show - so there is no framework in control here.

Interestingly µhtml is the foundation for µland - a React-style framework:

<!doctype html>
<html lang="eng">
  <head>
    <meta charset="utf-8"/>
    <title>µland is a Framework</title>
  </head>
  <body>
    <main class="js-root"></main>
    <script type="module">
     import {
       Component,
       render,
       html,
       useState,
       useEffect,
     } from 'https://unpkg.com/uland?module';

     // --- BEGIN user supplied component oriented application
     const App = Component((initialState) => {
       const count = useCount(initialState);
       return html`<p>${count}</p>`;
     });

     const MS_PER_COUNT = 1000;
     const START = document.timeline.currentTime;
     const increment = (value) => value + 1;

     function useCount() {
       const [_dirty, setDirty] = useState(0);
       // Base count on a fresh timestamp
       const count = Math.floor((performance.now() - START) / MS_PER_COUNT);

       useEffect(() => {
         const refresh = () => setDirty(increment);
         const delay = (count + 1) * MS_PER_COUNT - (performance.now() - START);
         const timeoutID = setTimeout(refresh, delay);
         return () => clearTimeout(timeoutID);
       });

       return count;
     }

     // --- END application
     // Handing over application to µland
     render(document.querySelector('.js-root'), App(0));
    </script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode
  • note how the user code is wrapped in a framework specific function type (via Component)
  • the final statement uses render, a framework function, exercising "inversion of control".

you have actual frameworks like Angular.

Why is it that people associate "framework" with size and complexity? The criteria for categorizing software as a "framework" were established long before either Angular or React were created. While the statement "React isn't an application framework like Angular" may be correct that in no way implies that React isn't a framework in its own right.

Why is it that people act as if the sky is going to fall on their head if they were to utter "React is a framework"?

Some comments have been hidden by the post's author - find out more