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.

相关推荐
big男孩11 小时前
autocode 使用指南
代码规范
昭昭日月明13 小时前
AI 时代的《重构》
设计模式·架构
这个DBA有点耶14 小时前
备份成功≠数据可恢复:静默损坏会让物理备份把坏页一起带走
数据库·mysql·代码规范
深圳老胡18 小时前
STM32F103 硬件 SPI 与软件 IO 模拟 SPI 最高速度差异详解
笔记·stm32·单片机·代码规范·1024程序员节
工一木子20 小时前
设计模式与生活③:你的早晨,是一套模板
设计模式
ZoeLandia21 小时前
React08:自定义 Hook
开发语言·前端·react.js·typescript
深圳老胡21 小时前
STM32C562RET6 外部中断详解:从 EXTI 原理到 GPIO 外部中断实战
笔记·stm32·单片机·代码规范·1024程序员节
是2的10次方啊1 天前
设计模式与生活④:冰箱空了,早餐换个买法
设计模式
知守观1 天前
设计模式实战:从真实老项目中看标准模板方法与工厂的落地
java·spring·设计模式
深圳老胡2 天前
压力检测空吸功能硬件方案全解析:主流压力传感器品牌与实现路径
笔记·单片机·代码规范