Rethinking React Hooks: Functional Programming, TypeScript, and Cross‑Framework Insights

This article explores why React moved from class components to the Hooks API, explains its functional‑programming roots, compares Hooks with Redux, Mixins, HOCs, Vue's Composition API, and demonstrates how TypeScript type inference and codata concepts can deepen understanding while providing practical code examples.

Taobao Frontend Technology
Taobao Frontend Technology
Taobao Frontend Technology
Rethinking React Hooks: Functional Programming, TypeScript, and Cross‑Framework Insights

Why Hooks API?

Hooks have been part of the React ecosystem for nearly two years, yet many developers still struggle to grasp their design patterns and underlying implementation.

TL;DR

Differences between Hooks API and Class API

Functional programming in Hooks

Hooks API and codata/Algebra

React Hooks vs Vue Composition API

Functional Programming

The core of Hooks is functional programming; most APIs are expressed as functions. React’s immutable model is driven by JSX, which maps state to a virtual DOM via the setState function.

Redux, also built on functional programming, uses actions and reducers to manage state, enabling time‑travel debugging but raising the learning curve for those unfamiliar with functional concepts.

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 };
};

Class components rely on this.state and this.setState, which become cumbersome when abstracting logic such as counters.

Logic Abstraction Methods

Mixins

Mixins combine logic via React.createClass, but they are deprecated and prone to conflicts.

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 Components (HOC)

HOCs wrap a component and inject logic via props, offering more flexibility than mixins.

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, decr: this.decr };
      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 and side effects, simplifying many patterns.

import React, { useState } from "react";
import ReactDOM from "react-dom";
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, state updates are not immediately reflected, unlike class components where await this.setState works.

Type‑Driven Functional Programming with TypeScript

Two basic function types are introduced: identity (input = output) and mapping (input → different output). These concepts underpin many web‑development scenarios.

I don’t know the data – it’s a parameter

Utility libraries like Lodash exemplify this idea: functions operate on unknown data while the logic remains fixed.

I don’t know the behavior – it’s a parameter

Examples include abstracting AJAX requests ( useRequest) or queuing async actions ( runTrack).

const { run: fetchPosts, loading } = wrapRequest((authorId: number) => fetchPostsService(authorId));
fetchPosts(123);
const statusText = loading ? "Loading..." : "Done";

Codata and Algebra

Codata, a concept from PLT theory, mirrors algebraic structures: unknown values and algorithms are treated as abstract entities that become concrete only during rendering.

By modeling UI as functions F<π, r> and F<r>, we can compute derivatives with respect to radius and π, similar to Redux’s state‑derivation philosophy.

React Hooks vs Vue Composition API

Vue 3 introduces the Composition API, which separates the setup (logic) from the template (render), aligning closely with codata’s compose‑and‑visit model.

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({
  name: "App",
  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");

The Composition API’s single‑execution setup reduces unnecessary recomputation compared with React’s per‑render Hook execution.

Conclusion

The article encourages readers to view Hooks through the lenses of functional programming, type inference, and codata, offering deeper insight beyond surface‑level tutorials and suggesting that understanding design philosophy can ease the steep learning curve.

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.

frontendReactVuehooksComposition API
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.