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.

相关推荐
nakyoooooo3 分钟前
【设计模式】工厂模式、单例模式、观察者模式、发布订阅模式
观察者模式·单例模式·设计模式
严文文-Chris2 小时前
【设计模式-享元】
android·java·设计模式
小白小白从不日白2 小时前
react hooks--useReducer
前端·javascript·react.js
丶白泽3 小时前
重修设计模式-设计原则
设计模式·接口隔离原则·依赖倒置原则·开闭原则
【D'accumulation】3 小时前
典型的MVC设计模式:使用JSP和JavaBean相结合的方式来动态生成网页内容典型的MVC设计模式
java·设计模式·mvc
volodyan3 小时前
electron react离线使用monaco-editor
javascript·react.js·electron
仙魁XAN4 小时前
Unity 设计模式 之 创造型模式-【工厂方法模式】【抽象工厂模式】
unity·设计模式·工厂方法模式·抽象工厂模式
龙哥·三年风水14 小时前
活动系统开发之采用设计模式与非设计模式的区别-后台功能总结
设计模式·php·tinkphp6
一头老羊15 小时前
前端常用的设计模式
设计模式
等下吃什么?15 小时前
NEXT.js 创建postgres数据库-关联github项目-连接数据库-在项目初始化数据库的数据
react.js