Why React Hooks? Uncover Functional Patterns Beyond Class Components

This article explores the motivations behind React's Hooks API, contrasts it with the traditional Class API, delves into functional programming concepts, demonstrates practical implementations with Redux, Mixins, HOCs, custom Hooks, TypeScript type inference, codata theory, and compares React Hooks to Vue's Composition API, providing code examples and visual diagrams throughout.

Taobao Frontend Technology
Taobao Frontend Technology
Taobao Frontend Technology
Why React Hooks? Uncover Functional Patterns Beyond Class Components

Why Hooks API?

Hooks API has been visible to developers since 2018, yet many still struggle to understand its design patterns. This article examines why developers should move from the Class API to Hooks, highlights the functional programming core of Hooks, and presents alternative perspectives for learning its architecture.

TL;DR

Differences between Hooks API and Class API

Functional programming within Hooks API

Hooks API and codata/Algebra

React Hooks vs. Vue Composition API

Functional Programming

The core of Hooks API is functional programming; most APIs are expressed as functions. React’s immutable model uses JSX to map state to a virtual DOM, and state changes are triggered via setState. Redux also follows functional principles, using actions and reducers to produce new state records.

interface State {
  count: number;
}
const state: State = { count: 0 };

const INCR = (state: State, payload: number = 1): State => {
  return { count: state.count + payload };
};
const DECR = (state: State, payload: number = 1): State => {
  return { count: state.count - payload };
};

Redux’s time‑travel debugging shows the sequence of actions, but the functional approach can be hard for those unfamiliar with mathematics.

Logic Abstraction in Class API

Class components use this.state and this.setState, which works fine for simple UI updates but becomes cumbersome when abstracting reusable logic. Two common abstraction methods are Mixins and Higher‑Order Components (HOC).

Mixins

import React from "react";
import ReactDOM from "react-dom";
import { Row, Col, Button } from "antd";

const counterMixin = {
  getInitialState() {
    return { count: 0 };
  },
  incr(increment = 1) {
    this.setState({ count: this.state.count + increment });
  },
  decr(decrement = 1) {
    this.setState({ count: this.state.count - decrement });
  }
};

// Deprecated since React 15.5.0
const Counter = React.createClass({
  mixins: [counterMixin],
  render() {
    return (
      <Row style={{ width: 150, textAlign: "center" }}>
        <Col span={24}><h3>{this.state.count}</h3></Col>
        <Col span={12}><Button onClick={() => this.incr()}>INCR</Button></Col>
        <Col span={12}><Button onClick={() => this.decr()}>DECR</Button></Col>
      </Row>
    );
  }
});

Higher‑Order Component (HOC)

import React, { Component } from "react";
import ReactDOM from "react-dom";
import { Row, Col, Button } from "antd";

function CounterComponent(WrappedComponent) {
  return class extends Component {
    state = { count: 0 };
    incr(increment = 1) { this.setState({ count: this.state.count + increment }); }
    decr(decrement = 1) { this.setState({ count: this.state.count - decrement }); }
    render() {
      const countProps = { count: this.state.count, incr: this.incr.bind(this), decr: this.decr.bind(this) };
      return <WrappedComponent {...this.props} {...countProps} />;
    }
  };
}

const Counter = CounterComponent((props) => {
  const { count, incr, decr } = props;
  return (
    <Row style={{ width: 150, textAlign: "center" }}>
      <Col span={24}><h3>{count}</h3></Col>
      <Col span={12}><Button onClick={incr}>INCR</Button></Col>
      <Col span={12}><Button onClick={decr}>DECR</Button></Col>
    </Row>
  );
});

Hooks API

Hooks enable function components to hold state. The basic custom Hook pattern looks like:

import React, { useState } from "react";
import { Row, Col, Button } from "antd";

function useCount(initCount = 0) {
  const [count, setCount] = useState(initCount);
  const incr = () => setCount(count + 1);
  const decr = () => setCount(count - 1);
  return { count, incr, decr };
}

function Counter() {
  const { count, incr, decr } = useCount();
  return (
    <Row style={{ width: 150, textAlign: "center" }}>
      <Col span={24}><h3>{count}</h3></Col>
      <Col span={12}><Button onClick={incr}>INCR</Button></Col>
      <Col span={12}><Button onClick={decr}>DECR</Button></Col>
    </Row>
  );
}

When using async/await with Hooks, the updated state may not be immediately available, unlike the Class API where awaiting this.setState yields the new value.

TypeScript‑Driven Functional Programming

Two basic function types are introduced: identity functions where input and output types match, and mapping functions where they differ. These concepts are illustrated with diagrams and a Lodash‑style data‑flow example.

Codata and Algebra

Codata is presented as a familiar mathematical concept akin to algebra. The article uses the circle area formula S = πr² to demonstrate how unknown parameters (π, r) can be treated as abstract values that become concrete only during rendering.

React Hooks vs. Vue Composition API

Vue 3 introduces a Composition API similar to React Hooks. The article shows a side‑by‑side example where Vue’s setup function returns reactive values, while React uses custom Hooks. Both approaches separate composition from rendering, but Vue’s composition runs only once, offering different performance characteristics.

import Vue from "vue";
import VueCompositionAPI, { ref } from "@vue/composition-api";
import Antd from "ant-design-vue";

Vue.use(VueCompositionAPI);
Vue.use(Antd);

const template = `
  <a-row id="app">
    <a-col :span="24"><h3>{{count}}</h3></a-col>
    <a-col :span="12"><a-button @click="() => incr()">INCR</a-button></a-col>
    <a-col :span="12"><a-button @click="() => decr()">DECR</a-button></a-col>
  </a-row>`;

new Vue({
  template,
  setup() {
    const count = ref(0);
    const incr = (increment = 1) => (count.value += increment);
    const decr = (decrement = 1) => (count.value -= decrement);
    return { count, incr, decr };
  }
}).$mount("#app");

Conclusion

The article encourages readers to view Hooks not merely as a syntactic change but as a functional programming paradigm that aligns with concepts like codata and algebra. By understanding these deeper ideas, developers can reduce the steep learning curve and write more predictable, composable React code.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

frontendReacthooks
Taobao Frontend Technology
Written by

Taobao Frontend Technology

The frontend landscape is constantly evolving, with rapid innovations across familiar languages. Like us, your understanding of the frontend is continually refreshed. Join us on Taobao, a vibrant, all‑encompassing platform, to uncover limitless potential.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.