darusuna.com

React Hooks: A Critical Examination of Their Design Flaws

Written on

Understanding the Issues with React Hooks

In recent times, a concerning trend has emerged within the JavaScript community, especially among React developers. There's a growing perception that established best practices can be disregarded without consequence. This isn't merely the opinion of a few individuals on platforms like Medium; it's a mindset that has infiltrated significant projects, including React and Redux. Consequently, these frameworks have strayed from the foundational principles that have historically supported the development of scalable and maintainable software.

This shift has resulted in a chaotic environment reminiscent of the past, where View components indiscriminately access and manipulate data from various sources. Developers may find themselves spending considerable time tracking down data changes caused by seemingly random fragments, only to struggle further when attempting to implement fixes within a tangled web of tightly-coupled code.

This discussion will delve into how React Hooks contravene the SOLID principles derived from Object-Oriented Design (OOD). You may be thinking (before fully engaging with this content) that React, when using hooks, doesn't adhere to OOD. However, it's important to recognize that while React's syntax might not be strictly object-oriented, it doesn't fully embrace functional programming either. The essence of functional programming lies in the simplicity of pure functions—where identical inputs yield identical outputs. This simplicity is what led many developers to favor functional languages, as they minimized state management in favor of function passing.

React once thrived with this approach through Higher Order Components (HOCs), yet the community's enthusiasm shifted dramatically towards the hybrid model that Hooks represent.

Examining the complexities of React Hooks

The Complexity Beneath Hooks

A closer examination of the React Hooks code reveals that React maintains an extensive registry to track the state of each component. This resembles Redux, albeit without the capacity for sharing state effectively. If we define an "object" as a collection of related state and methods, what we have with hooks is a transient function with a collection of states attached.

While we might hesitate to classify it as an object, this detachment from conventional object management principles leads to chaos in code structure. Let's consider the SOLID principles:

  1. Single Responsibility Principle: Each component should possess a singular purpose or reason for change.
  2. Open/Closed Principle: Code should be extendable without requiring modifications to existing code.
  3. Liskov Substitution Principle: Different implementations of the same interface should be interchangeable.
  4. Interface Segregation: Interfaces should be specific to clients, rather than broad and unwieldy.
  5. Dependency Inversion: Code should depend on abstractions rather than concrete implementations.

These principles were conceptualized by Robert C. Martin (Uncle Bob) to enhance software maintainability. Let's explore how these principles are violated in the context of functional components using hooks.

The Erosion of SOLID Principles

Single Responsibility Principle

Not too long ago, JavaScript developers were excited by the introduction of architectural concepts such as MVC (Model View Controller) and MVVM (Model View View Model). These frameworks encourage the segmentation of code into distinct layers: data handling (Model), user interface (View), and the mediator (Controller). This organization is crucial for maintainable code.

Critics often point to the boilerplate code required by Redux as cumbersome, yet this structure allows for a clear separation of dependencies, enhancing the focus on rendering and user input handling.

To illustrate, consider a data-fetching example using hooks. At first glance, it may seem like the responsibility for data retrieval is well-defined. However, hooks are inherently tied to the View, obscuring the implementation details without offering true separation of concerns. The reliance on a URL within the View makes it difficult to adapt to changes in the backend, ultimately compromising reusability.

Open/Closed Principle

This principle can be perplexing when applied to functional components. Uncle Bob posits that systems should be extendable without modification. The essence of functional programming aligns with this principle, allowing behavior alteration through function arguments or returns.

Conversely, hooks often necessitate changing the component structure when swapping hooks, which defeats the purpose of extensibility.

Plugin architecture in React

Liskov Substitution Principle

Using the earlier matcher example, substituting functions adhering to the same Typescript type is straightforward. However, in a hooks-based component, dependencies are directly accessed, making it impossible to interchange implementations without significant refactoring.

Interface Segregation

Hooks typically sidestep issues related to interface size, as they often eliminate the need for passing dependencies through properties. However, directly accessing concrete implementations negates the benefits of interface specificity.

The importance of interface in programming

Dependency Inversion

Dependency Inversion emphasizes the importance of programming against abstractions. In the previous data-fetching example, the App component directly relies on the useDataApi hook, creating a rigid dependency. Should it become necessary to switch to a different data-fetching method, the entire component would require alterations.

To mitigate this issue, Dependency Injection can be employed, allowing dependencies to be provided externally and promoting flexibility in implementation.

Conclusion

The SOLID principles emerged from a need to address specific software development challenges. These challenges persist, regardless of whether one employs Object-Oriented or Functional Programming paradigms. Hooks, in their current form, often lead developers to create avoidable complications by encouraging violations of these foundational principles. Future discussions will further explore how hooks align with React's design goals and their implications in production environments.

In Defense Of useEffect - React's Most Dangerous Hook

This video critically examines the useEffect hook, discussing its potential pitfalls and offering insights into its proper usage.

You're Doing React Hooks Wrong, Probably

In this video, common mistakes made while using React Hooks are addressed, along with best practices to follow for effective implementation.

Share the page:

Twitter Facebook Reddit LinkIn

-----------------------

Recent Post:

Unlocking Your Potential: 10 Steps to Transform Your Life

Discover ten transformative steps to guide you on your self-improvement journey for a more fulfilling life.

Understanding Psychology's Insights for Better Living in 2023

Discover the latest psychological findings in 2023 that shed light on social isolation, self-compassion, and personality traits linked to longevity.

generate critical insights from Uber's latest data breach

Analyzing the lessons learned from Uber's recent breach and how they can improve cybersecurity measures.