教你应用 SOLID 原则整理 React 代码之单一原则

 更新时间:2022年07月15日 10:10:44   作者:桃翁  
这篇文章主要介绍了如何应用 SOLID 原则整理 React 代码之单一原则,今天,我们将从一个糟糕的代码示例开始,应用 SOLID 的第一个原则,看看它如何帮助我们编写小巧、漂亮、干净的并明确责任的 React 组件,需要的朋友可以参考下

SOLID 原则的主要是作为关心自己工作的软件专业人员的指导方针,那些以经得起时间考验的设计精美的代码库为荣的人。

今天,我们将从一个糟糕的代码示例开始,应用 SOLID 的第一个原则,看看它如何帮助我们编写小巧、漂亮、干净的并明确责任的 React 组件,。

什么是单一责任原则?

单一责任原则告诉我们的是,每个类或组件应该有一个单一的存在目的。

组件应该只做一件事,并且做得很好。

让我们重构一段糟糕但正常工作的代码,并使用这个原则使其更加清晰和完善。

让我们从一个糟糕的例子开始

首先让我们看看一些违反这一原则的代码,添加注释是为了更好地理解:

import React, {useEffect, useReducer, useState} from "react";
const initialState = {
    isLoading: true
};
// 复杂的状态管理
function reducer(state, action) {
    switch (action.type) {
        case 'LOADING':
            return {isLoading: true};
        case 'FINISHED':
            return {isLoading: false};
        default:
            return state;
    }
}
export const SingleResponsibilityPrinciple = () => {
    const [users , setUsers] = useState([])
    const [filteredUsers , setFilteredUsers] = useState([])
    const [state, dispatch] = useReducer(reducer, initialState);
    const showDetails = (userId) => {
        const user = filteredUsers.find(user => user.id===userId);
        alert(user.contact)
    }
    // 远程数据获取
    useEffect(() => {
        dispatch({type:'LOADING'})
        fetch('https://jsonplaceholder.typicode.com/users')
            .then(response => response.json())
            .then(json => {
                dispatch({type:'FINISHED'})
                setUsers(json)
            })
    },[])
    // 数据处理
    useEffect(() => {
        const filteredUsers = users.map(user => {
            return {
                id: user.id,
                name: user.name,
                contact: `${user.phone} , ${user.email}`
            };
        });
        setFilteredUsers(filteredUsers)
    },[users])
    // 复杂UI渲染
    return <>
        <div> Users List</div>
        <div> Loading state: {state.isLoading? 'Loading': 'Success'}</div>
        {users.map(user => {
            return <div key={user.id} onClick={() => showDetails(user.id)}>
                <div>{user.name}</div>
                <div>{user.email}</div>
            </div>
        })}
    </>
}

这段代码的作用

这是一个函数式组件,我们从远程数据源获取数据,再过滤数据,然后在 UI 中显示数据。我们还检测 API 调用的加载状态。

为了更好地理解这个例子,我把它简化了。但是你几乎可以在任何地方的同一个组件中找到它们!这里发生了很多事情:

  • 远程数据的获取

  • 数据过滤

  • 复杂的状态管理

  • 复杂的 UI 功能

因此,让我们探索如何改进代码的设计并使其紧凑。

1. 移动数据处理逻辑

不要将 HTTP 调用保留在组件中。这是经验之谈。您可以采用几种策略从组件中删除这些代码。

您至少应该创建一个自定义 Hook 并将数据获取逻辑移动到那里。例如,我们可以创建一个名为 useGetRemoteData 的 Hook,如下所示:

import {useEffect, useReducer, useState} from "react";
const initialState = {
    isLoading: true
};
function reducer(state, action) {
    switch (action.type) {
        case 'LOADING':
            return {isLoading: true};
        case 'FINISHED':
            return {isLoading: false};
        default:
            return state;
    }
}
export const useGetRemoteData = (url) => {
    const [users , setUsers] = useState([])
    const [state, dispatch] = useReducer(reducer, initialState);
    const [filteredUsers , setFilteredUsers] = useState([])
    useEffect(() => {
        dispatch({type:'LOADING'})
        fetch('https://jsonplaceholder.typicode.com/users')
            .then(response => response.json())
            .then(json => {
                dispatch({type:'FINISHED'})
                setUsers(json)
            })
    },[])
    useEffect(() => {
        const filteredUsers = users.map(user => {
            return {
                id: user.id,
                name: user.name,
                contact: `${user.phone} , ${user.email}`
            };
        });
        setFilteredUsers(filteredUsers)
    },[users])
    return {filteredUsers , isLoading: state.isLoading}
}

现在我们的主要组件看起来像这样:

import React from "react";
import {useGetRemoteData} from "./useGetRemoteData";

export const SingleResponsibilityPrinciple = () => {

    const {filteredUsers , isLoading} = useGetRemoteData()

    const showDetails = (userId) => {
        const user = filteredUsers.find(user => user.id===userId);
        alert(user.contact)
    }

    return <>
        <div> Users List</div>
        <div> Loading state: {isLoading? 'Loading': 'Success'}</div>
        {filteredUsers.map(user => {
            return <div key={user.id} onClick={() => showDetails(user.id)}>
                <div>{user.name}</div>
                <div>{user.email}</div>
            </div>
        })}
    </>
}

看看我们的组件现在是多么的小,多么的容易理解!这是在错综复杂的代码库中所能做的最简单、最重要的事情。

但我们可以做得更好。

2. 可重用的数据获取钩子

现在,当我们看到我们 useGetRemoteData Hook 时,我们看到这个 Hook 正在做两件事:

  • 从远程数据源获取数据

  • 过滤数据

让我们把获取远程数据的逻辑提取到一个单独的钩子,这个钩子的名字是 useHttpGetRequest,它把 URL 作为一个参数:

import {useEffect, useReducer, useState} from "react";
import {loadingReducer} from "./LoadingReducer";

const initialState = {
    isLoading: true
};

export const useHttpGetRequest = (URL) => {

    const [users , setUsers] = useState([])
    const [state, dispatch] = useReducer(loadingReducer, initialState);

    useEffect(() => {
        dispatch({type:'LOADING'})
        fetch(URL)
            .then(response => response.json())
            .then(json => {
                dispatch({type:'FINISHED'})
                setUsers(json)
            })
    },[])

    return {users , isLoading: state.isLoading}
}

我们还将 reducer 逻辑移除到一个单独的文件中:

export function loadingReducer(state, action) {
    switch (action.type) {
        case 'LOADING':
            return {isLoading: true};
        case 'FINISHED':
            return {isLoading: false};
        default:
            return state;
    }
}

所以现在我们的 useGetRemoteData 变成了:

import {useEffect, useState} from "react";
import {useHttpGetRequest} from "./useHttpGet";
const REMOTE_URL = 'https://jsonplaceholder.typicode.com/users'

export const useGetRemoteData = () => {
    const {users , isLoading} = useHttpGetRequest(REMOTE_URL)
    const [filteredUsers , setFilteredUsers] = useState([])

    useEffect(() => {
        const filteredUsers = users.map(user => {
            return {
                id: user.id,
                name: user.name,
                contact: `${user.phone} , ${user.email}`
            };
        });
        setFilteredUsers(filteredUsers)
    },[users])

    return {filteredUsers , isLoading}
}

干净多了,对吧? 我们能做得更好吗? 当然,为什么不呢?

3. 分解 UI 组件

看看我们的组件,其中显示了用户的详细信息。我们可以为此创建一个可重用的 UserDetails 组件:

const UserDetails = (user) => {

    const showDetails = (user) => {
        alert(user.contact)
    }

    return <div key={user.id} onClick={() => showDetails(user)}>
        <div>{user.name}</div>
        <div>{user.email}</div>
    </div>
}

最后,我们的原始组件变成:

import React from "react";
import {useGetRemoteData} from "./useGetRemoteData";

export const Users = () => {
    const {filteredUsers , isLoading} = useGetRemoteData()

    return <>
        <div> Users List</div>
        <div> Loading state: {isLoading? 'Loading': 'Success'}</div>
        {filteredUsers.map(user => <UserDetails user={user}/>)}
    </>
}

我们把代码从 60 行精简到了 12 行!我们创建了五个独立的组成部分,每个部分都有明确而单一的职责。

让我们回顾一下我们刚刚做了什么

让我们回顾一下我们的组件,看看我们是否实现了 SRP:

  • Users.js - 负责显示用户列表

  • UserDetails.js ー 负责显示用户的详细资料

  • useGetRemoteData.js - 负责过滤远程数据

  • useHttpGetrequest.js - 负责 HTTP 调用

  • LoadingReducer.js - 复杂的状态管理

当然,我们可以改进很多其他的东西,但是这应该是一个很好的起点。

总结

这是一个简单的演示,演示如何减少每个文件中的代码量,并使用 SOLID 的强大功能创建漂亮的可重用组件。

到此这篇关于如何应用 SOLID 原则整理 React 代码之单一原则的文章就介绍到这了,更多相关React  SOLID单一原则内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • React中useEffect原理的代码简单实现详解

    React中useEffect原理的代码简单实现详解

    React的useEffect钩子是React函数组件中处理副作用,本文将通过一个简单的例子解释如何用代码实现useEffect的基本原理,感兴趣的小伙伴可以了解下
    2023-12-12
  • react实现同页面三级跳转路由布局

    react实现同页面三级跳转路由布局

    这篇文章主要为大家详细介绍了react实现同页面三级跳转路由布局,一个路由小案例,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-09-09
  • React父组件如何调用子组件的方法推荐

    React父组件如何调用子组件的方法推荐

    在React中,我们经常在子组件中调用父组件的方法,一般用props回调即可,这篇文章主要介绍了React父组件如何调用子组件的方法推荐,需要的朋友可以参考下
    2023-11-11
  • React中闭包陷阱的几种情及解决方案

    React中闭包陷阱的几种情及解决方案

    在react中我们使用其提供的Hooks中的useState,useEffect,useCallback 时,可能会造成闭包陷阱,下面我们来看一下出现的情况以及如何解决,感兴趣的小伙伴跟着小编一起来看看吧
    2024-07-07
  • React事件监听和State状态修改方式

    React事件监听和State状态修改方式

    这篇文章主要介绍了React事件监听和State状态修改方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-08-08
  • 基于React封装一个验证码输入控件

    基于React封装一个验证码输入控件

    邮箱、手机验证码输入是许多在线服务和网站常见的安全验证方式之一,本文主要来和大家讨论一下如何使用React封装一个验证码输入控件,感兴趣的可以了解下
    2024-03-03
  • React中常用的Hook有哪些

    React中常用的Hook有哪些

    这篇文章主要介绍了react hooks实现原理,文中给大家介绍了useState dispatch 函数如何与其使用的 Function Component 进行绑定,节后实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2023-01-01
  • React使用react-sortable-hoc如何实现拖拽效果

    React使用react-sortable-hoc如何实现拖拽效果

    这篇文章主要介绍了React使用react-sortable-hoc如何实现拖拽效果问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07
  • React Native与iOS OC之间的交互示例详解

    React Native与iOS OC之间的交互示例详解

    这篇文章主要为大家介绍了React Native与iOS OC之间的交互示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07
  • react 下拉框内容回显的实现思路

    react 下拉框内容回显的实现思路

    这篇文章主要介绍了react 下拉框内容回显,实现思路是通过将下拉框选项的value和label一起存储到state中, 初始化表单数据时将faqType对应的label查找出来并设置到Form.Item中,最后修改useEffect,需要的朋友可以参考下
    2024-05-05

最新评论