logo

Understanding React Components and Hooks Through Object-Oriented Thinking

Oct 29, 2025 · 1602 words

If you are just starting out with React, you might feel some confusion regarding how to use components and Hooks. In the world of React, it feels as if tools are scattered around randomly, and you are told to try and piece them together into complete pages and applications. Without careful attention, you can easily end up in a chaotic situation where states and functions are flying everywhere.

As a programmer with a background in backend development, I recently started trying to build complex, large-scale applications with React. During the development process, I gradually realized that the key to understanding React might lie in understanding the role of "Custom Hooks." Furthermore, this concept can be understood through the lens of Object-Oriented Programming (OOP).

If you share a backend background and find React concepts confusing, this article might provide you with some helpful perspectives.

The Relationship Between Components and Hooks

What is the relationship between a component and a Hook in React? The common understanding we see is:

Components are responsible for the view (UI display and interaction), while Hooks are responsible for the logic (state and operations).

This statement makes sense. Let's look at a simple counter example:

// useCounter.js (Custom Hook)
function useCounter() {
  const [count, setCount] = useState(0);
  
  const increment = () => setCount(count + 1);
  const decrement = () => setCount(count - 1);
  
  return { count, increment, decrement };
}

// Counter.js (Component)
function Counter() {
  const { count, increment, decrement } = useCounter();
  
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
}

In this example, useCounter encapsulates all state (count) and operations (increment, decrement), while the Counter component is only responsible for using them to render the UI. This seems to perfectly validate the idea that "components manage views, Hooks manage logic."

However, we can go a step further to hit the essence: is there really only "view" inside a component?

Even though the logic is placed inside the useCounter hook, the component uses this hook. In other words, by managing the hook, the component indirectly manages the logic.

This view can be confirmed from another angle: we could completely take all the code from useCounter and write it directly inside the Counter component, and the functionality would remain exactly the same.

That's right—a component is actually an independent building block that encapsulates both UI and logic.

This aligns with the philosophy of modern frontend frameworks like React: instead of separating HTML, CSS, and JavaScript, they perform a vertical slice. A component is an independent business module with UI structure (HTML), presentation (CSS), and interaction (JavaScript) capabilities.

In actual coding, we decide whether to write a custom Hook based on the situation:

  • If the logic in the component is simple, with only one or two states and a few operations, it can be written directly inside the component.
  • When the logic becomes complex, or when business logic needs to be reused, we extract the logic into a custom Hook. In this way, the component delegates the management of logic to the Hook and focuses itself on assembling the view.

To summarize in one sentence: Components manage both view and logic; when logic is complex, we extract it into custom Hooks so that the Hook manages the logic, and the component uses the logic indirectly through the Hook.

Thinking of Custom Hooks as "Classes"

Since custom Hooks are used to manage complex logic, where are they most commonly used in a project?

Naturally, they are used in places close to business requirements, architecture, and models.

For backend developers, these concepts might look familiar. The Object-Oriented design often used in the backend is essentially modeling business requirements.

Now, I have good news for you: you can completely use the concept of a "Class" to understand custom Hooks. Their core ideas are exactly the same.

Let's use Java as an analogy. A Java class (People) looks like this:

class People {
    private String name;

    // Constructor
    public People(String name) {
        this.name = name;
    }

    // Method
    public void run() {
        System.out.println(this.name + " is running");
    }
}

// Instantiation
People p = new People("Tom");
p.run();

In React, a custom Hook (usePeople) looks like this:

function usePeople(initialName) {
   const [name, setName] = useState(initialName);

   const run = () => {
      console.log(name + " is running");
   };

   // Return public interface
   return { name, run, setName };
}

// "Instantiating" in a component
const p = usePeople("Tom");
p.run();

Compare the relationships between them:

  • Class attributes correspond to Hook state (state)
  • Class methods correspond to Hook functions (operations)
  • The class constructor corresponds to the initial value in useState and the object returned by the Hook

Amazing! We have linked Hooks to something we already know. Let's discard the official React documentation's definition of a custom Hook: "A custom Hook is a mechanism to share logic between components," and replace it with a definition we can understand: "A custom Hook is similar to a class in Object-Oriented programming; it encapsulates state and operations to manage complex business logic."

When OOP Design Principles Meet Hooks

Since Hooks can be compared to "classes," do the familiar OOP design principles apply? Let's look at them one by one.

1. Encapsulation

Hooks embody encapsulation perfectly. They package internal state and operations together. The component only cares about what the Hook exposes, not the internal implementation (such as how the internal state is updated).

2. Inheritance

This is the biggest difference: Hooks do not have inheritance.

In OOP, we might have an Athlete class inherit from a People class. In React, we don't do that. React's answer is "Composition." One Hook can call another Hook to extend its functionality.

// Base People hook
function usePeople(initialName) {
  const [name, setName] = useState(initialName);
  const run = () => console.log(name + " is running");
  return { name, setName, run };
}

// Athlete hook extends the capabilities of People hook
function useAthlete(initialName) {
  // 1. "Inherit" People's capabilities
  const { name, setName, run } = usePeople(initialName); 
  
  // 2. Add its own capabilities
  const train = () => console.log(name + " is training hard");

  // 3. Return a "subclass" instance
  return { name, setName, run, train };
}

useAthlete reuses the capabilities of usePeople by calling it and adds its own train logic.

3. Polymorphism

Since there is no inheritance, Hooks don't have polymorphism in the traditional sense. However, for a dynamic language like JavaScript, we can achieve the same effect using duck typing.

function usePerson() {
  const work = () => console.log("Person is working");
  return { work };
}

function useRobot() {
  const work = () => console.log("Robot is working");
  return { work };
}

function Worker({ useWorker }) {
  const { work } = useWorker();
  return <button onClick={work}>Work</button>;
}

function App() {
  return (
    <div>
      <Worker useWorker={usePerson} />
      <Worker useWorker={useRobot} />
    </div>
  );
}

4. Instantiation

Just like the relationship between a class and an object in OOP, every time you call usePeople() in a component, you get a completely new, independent instance of state.

It is just like calling new People("Tom") and new People("Jerry") twice; you get two different objects whose states (name) do not interfere with each other.

A New Development Approach: Model with OOP, Implement with Hooks

During my learning journey, I took a detour: I used to think custom Hooks were something very advanced and difficult, which led me to delay learning and using them.

However, from the discussion above, we can see: Custom Hooks are not an advanced feature, but a necessity for organizing complex business logic.

This is also a common mistake I see in many frontend projects: piling all business logic (asynchronous requests, data processing, side effects) into components, making the project difficult to maintain.

Even if the business logic is later extracted into Hooks, because the development was UI-oriented from the start, the resulting Hooks might focus on "technical reuse" rather than "business modeling." This bottom-up abstraction method does not perform well when facing complex business logic.

A more appropriate abstraction method is top-down. Backend developers should be familiar with this; we can fully utilize the similarity between Hooks and classes to implement this method in React.

The overall development process looks like this:

  1. Object-Oriented Modeling: When facing complex requirements, don't think about the UI first. Instead, use OOP thinking for modeling and design. For example, for an order system, I need an Order model with certain attributes and methods.
  2. Translate to Hook Implementation: Translate the Order model into a corresponding custom Hook, namely useOrder. Attributes and methods become states and functions within the Hook.
  3. Build View Components: The last step is writing the components. The components use useOrder to obtain state and operations and bind them to UI elements.

React's official UI = f(state) philosophy is functional, and this philosophy itself is great because it makes view rendering predictable. However, in macro-architectural design, functional thinking can leave beginners at a loss.

Our strategy can be: Use OOP thinking for high-level architecture (business modeling) and functional thinking for low-level implementation (building UI). These two do not conflict; combining them can be clearer and more practical.

Summary

This article has described a new way to understand and use React: treating custom Hooks as classes, thereby applying Object-Oriented thinking to React development.

One thing must be noted: viewing Hooks as classes is just a perspective, or a "mental model." Its purpose is to help us understand, not to replicate OOP design one-to-one in the React world. React Hooks differ significantly from "classes" in their underlying implementation and many details.

During the process of React project development, you can boldly use OOP thinking to model business logic, integrating backend concepts with frontend technology. Your potential will be higher than 99% of professional frontend developers.

I hope this article helps you eliminate your fear of Hooks and gives you more confidence in using them to organize and manage business logic when facing complex requirements.