Using the Liskov Substitution Principle (LSP) in React

Using the Liskov Substitution Principle (LSP) in React

With Code Example

Introduction

React, a popular JavaScript library for creating user interfaces, places a focus on following software engineering principles to create extendable and maintainable applications. One such rule is the Liskov Substitution Principle (LSP), which makes sure that derived types can interchange their base types without negatively impacting the behavior of the application. Using the Liskov Substitution Principle to increase flexibility and reusability, we will examine how to implement a search input component in React in this post.

Understanding the Liskov Substitution Principle (LSP)

In object-oriented programming (OOP), the Liskov Substitution Principle is a fundamental idea that encourages the creation of replaceable and consistent components. According to LSP, derived types should be able to replace their base types without introducing unexpected behaviors or breaking the contracts set out by the base types.

Now, let us build a Search Input Component in React with the Liskov Substitution Principle: Let's have a look at an example that illustrates how to implement a search input component in React while maintaining the Liskov Substitution Principle.

LSP/index.tsx

import React, { useState } from 'react';
import SearchInput from './SearchInput';

const LSP = () => {
  const [value, setValue] = useState('');

  const handleChange = (e) => {
    setValue(e.target.value);
  };

  return <SearchInput value={value} onChange={handleChange} isLarge />;
};

export default LSP;

LSP/SearchInput.tsx

import React from 'react';

const SearchInput = ({ value, onChange, isLarge, ...restProps }) => {
  return (
    <div className="flex w-10/12">
      <div className="relative w-full">
        <div className="flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none">
          <svg
            aria-hidden="true"
            className="w-5 h-5 text-gray-500 dark:text-gray-400"
            fill="none"
            stroke="currentColor"
            viewBox="0 0 24 24"
            xmlns="http://www.w3.org/2000/svg"
          >
            <path
              strokeLinecap="round"
              strokeLinejoin="round"
              strokeWidth="2"
              d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
            />
          </svg>
        </div>
        <input
          type="search"
          id="default-search"
          className={`${
            isLarge ? 'text-3xl' : ''
          } block p-4 pl-10 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500 outline-none`}
          placeholder="Search for the right one..."
          required
          value={value}
          onChange={onChange}
          {...restProps}
        />
      </div>
    </div>
  );
};

export default SearchInput;

In the provided code example, we have a LSP component that renders a search input component called SearchInput. Let's examine how LSP is applied in this example:

  1. The SearchInput component acts as the derived component that extends the base input component provided by React. It accepts props such as value, onChange, isLarge, and any other props passed through the ...restProps spread operator.

  2. By using the ...restProps spread operator on the <input> element, the SearchInput component can handle additional props that are not explicitly destructured. This allows for seamless substitution of the SearchInput component for the base input component, ensuring compatibility and adherence to LSP.

  3. The LSP component uses the SearchInput component and manages its state through the useState hook. It passes the value and onChange props to the SearchInput component, enabling controlled input functionality.

  4. The optional isLarge prop in the LSP component demonstrates how derived components can introduce additional functionality while maintaining compatibility with the base component. In this case, the isLarge prop adjusts the size of the input field by adding a CSS class to the SearchInput component.

Benefits of Applying LSP in React

Applying the Liskov Substitution Principle in React components yields several advantages:

  1. Code Reusability: LSP promotes the reuse of code by ensuring that derived components can substitute their base components without altering the application's logic or expected behavior.

  2. Flexibility and Extensibility: Derived components can introduce additional props and functionalities while honoring the interface of the base component. This allows for flexible customization and extensibility without breaking the component hierarchy.

  3. Maintainability: Adhering to LSP enhances the maintainability of React applications. Derived components can be modified or extended without impacting the existing codebase, promoting modularity and ease of maintenance.

Try it in the Code Sandbox

https://codesandbox.io/p/sandbox/lsp-react-demo-fnpr4r

Conclusion

By implementing the Liskov Substitution Principle (LSP) in React components, we can create flexible and reusable code. In the example of the search input component, the derived SearchInput component seamlessly substitutes the base input component while introducing additional features. Adhering to LSP ensures code reusability, flexibility, and maintainability in React applications. Embracing LSP empowers developers to build scalable and robust React components that can be easily extended or modified, leading to more efficient development processes and high-quality applications.

Did you find this article valuable?

Support Adeesh's Software Engineering Insights by becoming a sponsor. Any amount is appreciated!