DEV Community

Cover image for The React hook pradigm
Eckehard
Eckehard

Posted on

The React hook pradigm

The first thing you learn about React it the class based approach:

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}
Enter fullscreen mode Exit fullscreen mode

which at first glace may be confusing new users. Why do we need to create a new class for every single function? Well, this is the way to let your function become part of the React Ecosystem.

There is a similar approach creating WebComponents:

class PopUpInfo extends HTMLElement {
  constructor() {
    super();
    // write element functionality in here
    ...
  }
}
Enter fullscreen mode Exit fullscreen mode

This is similar, but different, as WebComponents feature an object oriented approach. You need to extend HTMLElement or one of its decendats to let your new Component be part of the HTML-ecosystem, but usually there is only one class for a more or less complex object that containts the whole functionallity and state management.

For React, things are different.

In the-functional-side-of-react we find a comprehensive explanation of the concepts behind react:

However, under the Object-Oriented dress, React hides a functional nature. The main constraint for a React component is to implement a render() method. The render() method returns a React element, that is the component’s markup defining its appearance. In other words, React is requiring that any component must have an output... (So)... you can think of React components as functions.

So, while react uses class based objects, it applies some constraints to the concept to use classes as first class functions.

The functional programming paradigm aims to avoid the use of the state in an application. React’s development guidelines promote the creation of stateless components, that is components not using the state property. This should grant that the output of a component only depends on its props. A stateless component looks a lot like a pure function, and indeed it is.

So, while React uses classes, should not make use of the ease of state management, that objects provide. Instead, it follows the functional approach:

This strategy corresponds to the pattern that asks the developer to use the state in the higher component in a component hierarchy. In other words, a component hierarchy should have in its root a stateful component, while its descendants should be stateless components.

So far, the concept seems to be clear, while in the react documents we find lot´s of examples where things are not that clear:

You can use stateless components inside stateful components, and vice versa.

What about Hooks

Using a functional paradigm, the most imporatant rule is to prevent side effects: Using pure functions we can isolate the state management from the functional logic.

From react -> hooks-overview we find:

The Effect Hook, useEffect, adds the ability to perform side effects from a function component

This is precisely what we find here:

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Here we just grab a state from outside a function not as a parameter, but as an external reference.

I really tried to find the clue of this concept, but it more seems to be dirty hack than something following any paradigm. Maybe we should call this the React Hacks?

Any illumination is very welcome.

Discussion (3)

Collapse
peerreynders profile image
peerreynders

I really tried to find the clue of this concept, but it more seems to be dirty hack than something following any paradigm.

The claim made by some of React's advocates that React embraces a "Functional Approach to UI" is quite misleading - which you have now discovered for yourself. The claim is largely based on the fact that a single function (pure (stateless) or impure (stateful - with hooks)) manages the life cycle and rendering of all of it's component instances. However "components are objects".

Even before functional components there was something odd about this.props, this.state and setState():

setState() enqueues changes to the component state

I'm not even sure that statement is accurate.

React Components, Elements, and Instances:

React takes care of creating an instance for every class component, so you can write components in an object-oriented way with methods and local state, but other than that, instances are not very important in the React’s programming model and are managed by React itself.

In my understanding the correct statement should be:

setState() enqueues changes to the component instance state.

The documentation is pretty clear that neither this.props nor this.state belong to the MyComponent object. That's not surprising given that it is not unusual for frameworks to supply classes that have to be extended - so this.props and this.state belong to the underlying React.Component object, right?

My current understanding is that this.props and this.state belongs to (or is a copy of) the component instance that is currently being managed by the MyComponent object - i.e. one single MyComponent object is potentially managing many component instances each with their unique props and state.

Now stateless functional components were straightforward about this one-to-many relationship - a single function could clearly serve many component instances - but only via props arguments. state couldn't be handled that way because change of state is responsible for the component (instance) being re-rendered (re-activated).

To understand how hooks work I direct people to Deep dive: How do React hooks really work?. After understanding that article it becomes clear:

  • Classes: this.props and this.state are set by React from the current component instance object (a separate object from the actual component object) before it calls a method on the component object. From the component perspective the instance data doesn't need to be actively "fetched".
  • Hooks: React sets up the current execution environment (in a closure) to align with the component instance to be processed before the function component is invoked - at which point the component has to actively "fetch" (and configure) component instance state via hook functions from the execution environment.

So component instances traded "objects" for "closures".

Quote:

The venerable master Qc Na was walking with his student, Anton. Hoping to prompt the master into a discussion, Anton said "Master, I have heard that objects are a very good thing - is this true?" Qc Na looked pityingly at his student and replied, "Foolish pupil - objects are merely a poor man's closures."

On his next walk with Qc Na, Anton attempted to impress his master by saying "Master, I have diligently studied the matter, and now understand that objects are truly a poor man's closures." Qc Na responded by hitting Anton with his stick, saying "When will you learn? Closures are a poor man's object." At that moment, Anton became enlightened.

i.e. "objects" and "closures" are duals of one another - one is explicit in its nature, the other is implicit.

So the only thing that really changed:

  • Class components: separate methods on the component object represented separate responsibilities with respect to component instance management. In a way the component object is just a "map" of functions that interact with the data of any number of component instances.
  • Stateful function Components: All those separate responsibilities are now complected into one single function - not good news for "separation of concerns" and "decoupling".

Redux's Prior Art states:

Elm is a functional programming language inspired by Haskell and created by Evan Czaplicki. It enforces a “model view update” architecture, where the update has the following signature: (action, state) => state. Elm “updaters” serve the same purpose as reducers in Redux.

Elm Wiring:

  • The view function, which is responsible for converting a model into HTML for Elm to render to the UI. It also maps all possible user actions to the appropriate messages.

That describes a "Functional Approach to UI" and the Elm community has come to the conclusion that components don't work in a functional UI.

React uses functions, closures, objects, and classes but it doesn't use object-oriented components or functional view functions - it's using its own brew of function managed component instances.

Collapse
peerreynders profile image
peerreynders • Edited on

Another perspective I recently ran across, in particular:

I think that React is actually doing something that it was never really intended to in the first place …
… also React which said hey keep your state management system but will manage all of the view state for you and the only reason why React had any state management system at all was because each component could be a smart component …
… React was never meant to be the state manager and then we got hooks and hooks were close enough to being a state management system where we kind of looked over the fundamental flaws

The bulk of that video pits SolidJS against React.


Interestingly Soild's project founder Ryan Carniato joined EBay's Marko team in 2020.

Unlike mainstream front end frameworks Marko was designed back in 2013 to focus on server side capabilities first - and by 2017 also included client-side VDOM. Now Marko is integrating client-side reactive capabilities as an alternative to client side VDOM (Marko: Designing a UI Language) - with partial rehydration intact. Mainstream frameworks tend to "bolt on" SSR after the fact - Marko is a server side solution that "bolted on" (and integrated) client-side rendering.


For a pro-hooks examination see: React Hooks: Has React Jumped the Shark?

Collapse
artydev profile image
artydev • Edited on

I really don' know why they did not used closures instead of state hooks !!!