SOLID implements in React Project

Introduction

SOLID is a popular kind of design principles that are used in object oriented programming. SOILD can not only be used in backend which is just like jave or nodejs, but also be used in frontend. We use those principles to design our component and function, to make our codes and business logic cleaner and better for readability, easier to scaled and maintained.

So what's the concrete means of SOLID priciples?

SOILD stands for five key design priciples, we should code with conforming each of those. Though. sometimes some of these principles may look similar but they are not targeting the same objective.

Explain SOLID

S (Single Responsibility Priciple)

A class should have a single responsibility, such as User class, Log class and so on...

If a class has many responsibilties, it increasees the possibility of bugs and the complexity of code maintenance, because changing one of its responsibilities could affect the other ones unexpectedly.

This principle attempt to separate behaviours so that if exceptions arouse by changing, it won't influence other irrelevant behaviours.

O (Open-Closed Principle)

Class should be open for extension, but closed for modification

In jave. we typically create a new class by inheriting existing class to implement other diffrent functionalities instead of modifying directly

Make it simple, if we want a Class to peform more functions, the informed approach is to add the functions that already exist, instead of changing them.

This principle aims to extend a Class's behavior without changing the existing behavior of that Class. This is to avoid bugs wherever the Class is used.

L (Liskov Substitution Principle)

The object of Child Class can replace the object of its base Class.

That can cause bugs When a clild Class can't perform the same actions as it's parent Class. It's a child Class that should be able to do everything which it's parent Class can do.

This principle aims to enforce consistency so that the parent Class or its child Class can be used in the same way without any error.

I (Interface Isolation Priciple)

使用多个专门的接口比使用单一总接口要好 Clients should not depend on methods that they do not use at all.

It's wasteful when a Class is required to perform useless actions. that may cause unexpected bugs.

This principle aims to split a set of actions into some smaller sets so that only executing when it is required

D (Dependency Inversion Priciple)

High level modules should not depend on low level ones. Both should depend on abstraction. Abstractions should not depend on details, details should depend on Abstractions. It's a little difficult to understand it.

In a nutshell,we should programe oriented interface. Abstracting into a interface makes the implementation of each class independed of each other and loose coupling.

Overall, Class should not be fused with the tool it uses to execute an action, instead, it should be fused to the interface that will allow the tool to connect to the Class. Both Class and interface should not know how the tool works. However, the tool needs to meet the spicification of the interface.

This principle aims to reduce the dependency of high level Class on low level Class by introducing interfaces

SOLID implements in React Project

We are supposed to figure SOLID principle out through the above explaination. So then we are gonnar research how use them in React Project one after another.

S

For instance, let's implement a fitter component of products with fetching daata

typescript 复制代码
import { useState, useMemo, useEffect, ChangeEvent } from 'react';
import data from '../mock';

type Products = typeof data;

export default function Bad() {
    const [products, setProducts] = useState<Products>([]);
    const [filterFeatured, setFilterFeatured] = useState(true);

    const fetchProducts = async () => {
        const getMockData = (): Promise<Products> => new Promise(resolve => setTimeout(() => resolve(data), 0));
        const response = await getMockData();
        setProducts(response);
    };

    useEffect(() => {
        fetchProducts();
    }, []);

    const toggleFeatured = (e: ChangeEvent<HTMLSelectElement>) => {
        e.preventDefault();
        setFilterFeatured(e.target.value === '1');
    };

    const filteredProducts = useMemo(
        () => products.filter((product: Products[0]) => product.isFeatured === filterFeatured),
        [products, filterFeatured]
    );

    return (
        <>
            <div>
                <select
                    value={filterFeatured ? '1' : '0'}
                    onChange={toggleFeatured}
                >
                    <option value="0">unfeatured</option>
                    <option value="1">featured</option>
                </select>
            </div>
            <ul>
                {filteredProducts.map(({ id, title, description, date, isFeatured }) => (
                    <li key={id}>
                        <h3>{title}</h3>
                        <p>{description}</p>
                        <p>{date} - {isFeatured ? 'featured' : 'unfeatured'}</p>
                    </li>
                ))}
            </ul>
        </>
    );
}

Abouve bad codes, all funcitons written in a component that does not confirm the single responsibility priciple. Let's split the functions into single. codes like this:

typescript 复制代码
// entrance
import Product from './product';
import Filter, { filterProducts } from './filter';
import { useProducts } from './hooks/useProducts';
import { useFeaturedFitler } from './hooks/useFeaturedFitler';

export default function Good() {
    const { products } = useProducts();
    const { filterFeatured, toggleFeatured } = useFeaturedFitler();

    return (
        <>
            <Filter
                filterFeatured={filterFeatured}
                toggleFeatured={toggleFeatured}
            />
            <ul>
                {filterProducts(products, filterFeatured).map(product => (
                    <Product product={product} />
                ))}
            </ul>
       </>
    );
}
  • hooks

  • product
  • Fitter

O

For instance, we are gonnar build a Button component.

Abouve bad codes, we have to modify the codes of the Button component that it comes with new requirements, that's we are not expecting. Therefore, the component should be scale instead of modification. Let's code like this:

L

For instance, Let's we build a SearchInput component.

I

That's so bad. The Image component only needs imageUrl from props, but we transport the whole product data. It's not necessary. So we can do it like this:

D

For instance. Let's build a sign-in Form component.

It's not appropriate to change the form's codes once we have to change the logic of submit function, that's a problem. What the submit do should be abstract devised and picked out from here, by props to execute from external implementation from out of the component. So we shoud code like this:

Summary

So far, we have knew these five priciples and underline their details. They are to help us make code easy to adjust, extend and test without unexpected problems.

If you want to get codes of this articles. you can visit my github.

相关推荐
Highcharts.js6 小时前
常见报错排雷指南2:导出失败的官方解法
javascript·react.js·ecmascript·highcharts·可视化图表·导出模块失败·导出服务
YHL10 小时前
🎯 JavaScript 单例模式(Singleton Pattern)—— 从理论到实战
javascript·设计模式
天涯浪客11 小时前
我的漏洞扫描器,把被测项目的源码写坏了
代码规范
2401_8685347811 小时前
网络环境规划核心考点全梳理
网络·设计模式
事圆则缓13 小时前
遗留项目改造实战指南:从可读性、代码质量到性能和 AI 约束
android·ai·代码规范
feiyu_gao15 小时前
Cocreation Framework:一套给所有人的 AI 协作思考系统
设计模式·aigc·ai编程
今日无bug15 小时前
从 0 到 1 搭建端侧 AI 项目:DeepSeek-R1 + WebGPU + React + TS + Tailwind 全栈笔记
前端·react.js·typescript
Highcharts.js17 小时前
常见报错排雷指南3:兼容性问题的官方解法
前端·javascript·react.js·可视化·highcharts·报错解法
光影少年18 小时前
react navite浏览器 Event Loop 和 Node Event Loop 的区别
前端·javascript·react native·react.js·前端框架
乱码三千18 小时前
开发了一套AI智能体协作知识体系
人工智能·架构·代码规范