热门标签 | HotTags
当前位置:  开发笔记 > 开发工具 > 正文

编写简洁React组件的小技巧

这篇文章主要介绍了编写简洁React组件的小技巧,帮助大家更好的理解和学习使用React,感兴趣的朋友可以了解下

本文源于翻译文章 Simple tips for writing clean React components, 原文作者 Iskander Samatov

在这篇文章中,我们会回顾一些简单的技巧,它们将帮助我们编写更简洁的 React 组件,并且更好地扩展我们的项目。

避免使用扩展操作符传递 props

首先,让我们从一个应该避免的反模式开始。除非有明确的理由这样做,否则应该避免在组件树中使用扩展操作符传递props,比如:{ ...props }。

通过这种方式传递 props 确实可以更快的编写组件。但这也使得我们很难去定位代码中的 bug。会使我们对编写的组件失去信心,会使得我们重构组件变得更加困难,而且可能会导致出现很难排查的 bug。

将函数参数封装成一个对象

如果函数接收多个参数,最好将它们封装成一个对象。举个例子:

export const sampleFunction = ({ param1, param2, param3 }) => {
  console.log({ param1, param2, param3 });
}

以这种方式编写函数签名有几个显著的优点:

  1. 你不用再担心参数传递的顺序。我曾犯过几次因函数传参顺序问题而产生了 bug 的错误。
  2. 对于配置了智能提示的编辑器(现在的大多数都有),可以很好地完成函数参数的自动填充。

对于事件处理函数,将该处理函数作为函数的返回值

如果你熟悉函数式编程,这种编程技术类似于函数柯里化,因为已经提前设置了一些参数。

我们来看看这个例子:

import React from 'react'

export default function SampleComponent({ onValueChange }) {

  const handleChange = (key) => {
    return (e) => onValueChange(key, e.target.value)
  }

  return (
    
      
      
      
    
  )
}

如您所见,以这种方式编写处理程序函数,可以使组件树保持简洁。

组件渲染使用 map 而非 if/else

当你需要基于自定义逻辑呈现不同的元素时,我建议使用使用 map 而非 if/else 语句。

下面是一个使用if/else的示例:

import React from 'react'

const Student = ({ name }) => 

Student name: {name}

const Teacher = ({ name }) =>

Teacher name: {name}

const Guardian = ({ name }) =>

Guardian name: {name}

export default function SampleComponent({ user }) { let CompOnent= Student; if (user.type === 'teacher') { CompOnent= Teacher } else if (user.type === 'guardian') { CompOnent= Guardian } return (
) }

下面是一个使用map的示例:

import React from 'react'

const Student = ({ name }) => 

Student name: {name}

const Teacher = ({ name }) =>

Teacher name: {name}

const Guardian = ({ name }) =>

Guardian name: {name}

const COMPONENT_MAP = { student: Student, teacher: Teacher, guardian: Guardian } export default function SampleComponent({ user }) { const CompOnent= COMPONENT_MAP[user.type] return (
) }

使用这个简单的小策略,可以使你的组件变得更具有可读性,更容易理解。而且它还使逻辑扩展变得更简单。

Hook组件

只要不滥用,这个模式是很有用的。

你可能会发现自己在应用中使用了很多组件。如果它们需要一个状态来发挥作用,你可以将他们封装为一个 hook 提供该状态。这些组件的一些好例子是弹出框、toast 通知或简单的 modal 对话框。例如,下面是一个用于简单确认对话框的 hook 组件:

import React, { useCallback, useState } from 'react';
import ConfirmationDialog from 'components/global/ConfirmationDialog';

export default function useConfirmationDialog({
  headerText,
  bodyText,
  confirmationButtonText,
  onConfirmClick,
}) {
  const [isOpen, setIsOpen] = useState(false);

  const OnOpen= () => {
    setIsOpen(true);
  };

  const Dialog = useCallback(
    () => (
       setIsOpen(false)}
        cOnfirmationButtonText={confirmationButtonText}
      />
    ),
    [isOpen]
  );

  return {
    Dialog,
    onOpen,
  };
}

你可以像这样使用 hook 组件:

import React from "react";
import { useConfirmationDialog } from './useConfirmationDialog'

function Client() {
  const { Dialog, onOpen } = useConfirmationDialog({
    headerText: "Delete this record?",
    bodyText:
      "Are you sure you want delete this record? This cannot be undone.",
    confirmationButtonText: "Delete",
    onConfirmClick: handleDeleteConfirm,
  });

  function handleDeleteConfirm() {
    //TODO: delete
  }

  const handleDeleteClick = () => {
    onOpen();
  };

  return (
    
); } export default Client;

以这种方式提取组件可以避免编写大量状态管理的样板代码。如果你想了解更多 React hooks,请查看 我的帖子。

组件拆分

下面三个技巧是关于如何巧妙地拆分组件。根据我的经验,保持组件的简洁是保持项目可管理的最佳方法。

使用包装器

如果你正在努力寻找一种方法来拆分复杂组件,看看你的组件中每个元素所提供的功能。有些元素提供了独特的功能,比如拖拽功能。

下面是一个使用react-beautiful-dnd实现拖拽的组件示例:

import React from 'react'
import { DragDropContext, Droppable } from 'react-beautiful-dnd';
export default function DraggableSample() {
  function handleDragStart(result) { 
    console.log({ result });
  }
  function handleDragUpdate({ destination }) { 
    console.log({ destination });
  }
  const handleDragEnd = ({ source, destination }) => { 
    console.log({ source, destination });
  };
  return (
    
{(provided) => (
{columns.map((column, index) => { return ( ); })}
)}
) }

现在,看一下在我们将所有拖拽逻辑移到包装器之后的组件:

import React from 'react'
export default function DraggableSample() {
  return (
    
{columns.map((column, index) => { return ( ); })}
) }

下面是包装器的代码:

import React from 'react'
import { DragDropContext, Droppable } from 'react-beautiful-dnd';
export default function DragWrapper({children}) {
  function handleDragStart(result) { 
    console.log({ result });
  }
  function handleDragUpdate({ destination }) { 
    console.log({ destination });
  }
  const handleDragEnd = ({ source, destination }) => { 
    console.log({ source, destination });
  };
  return (
    
       
        {(provided) => (
          
{children}
)}
) }

因此,可以更直观地看到组件在更高层次上的功能。所有用于拖拽的功能都在包装器中,使得代码更容易理解。

关注点分离

这是我最喜欢的拆分较大组件的方法。

从 React 角度出发,关注点的分离意味着分离组件中负责获取和改变数据的部分和纯粹负责显示元素的部分。

这种分离关注点的方法是引入 hooks 的主要原因。你可以用自定义 hook 封装所有方法或全局状态连接的逻辑。

例如,让我们看看如下组件:

import React from 'react'
import { someAPICall } from './API' 
import ItemDisplay from './ItemDisplay'
export default function SampleComponent() { 
  const [data, setData] = useState([])
  useEffect(() => { 
    someAPICall().then((result) => { setData(result)})
  }, [])
  function handleDelete() { console.log('Delete!'); }
  function handleAdd() { console.log('Add!'); }
  const handleEdit = () => { console.log('Edit!'); };
  return (
    
{data.map(item => )}
) }

下面是它的重构版本,使用自定义hook拆分后的代码:

import React from 'react'
import ItemDisplay from './ItemDisplay'
export default function SampleComponent() {
  const { data, handleDelete, handleEdit, handleAdd } = useCustomHook()
  return (
    
{data.map(item => )}
) }

这是该 hook 本身的代码:

import { someAPICall } from './API'
export const useCustomHook = () => { 
  const [data, setData] = useState([])
  useEffect(() => { 
    someAPICall().then((result) => { setData(result)})
  }, [])
  function handleDelete() { console.log('Delete!'); }
  function handleAdd() { console.log('Add!'); }
  const handleEdit = () => { console.log('Edit!'); };
  return { handleEdit, handleAdd, handleDelete, data }
}

每个组件封装为一个单独的文件

通常大家会这样写代码:

import React from 'react'
export default function SampleComponent({ data }) {
  const ItemDisplay = ({ name, date }) => ( 
    

{name}

{date}

) return (
{data.map(item => )}
) }

虽然用这种方式编写 React 组件没有什么大问题,但这并不是一个好的做法。将 ItemDisplay 组件移动到一个单独的文件可以使你的组件松散耦合,易于扩展。

在大多数情况下,要编写干净整洁的代码,需要注意并花时间遵循好的模式和避免反模式。因此,如果你花时间遵循这些模式,它有助于你编写整洁的 React 组件。我发现这些模式在我的项目中非常有用,希望你也这么做!

以上就是编写简洁React组件的小技巧的详细内容,更多关于编写React组件的技巧的资料请关注其它相关文章!


推荐阅读
  • linux 使用sudo开放普通用户权限
    整理一下以前写的东东,刚才又忘了~----------------------------------------------------------- ... [详细]
  • Java体系化进阶学习图谱:java进阶路线图
    第一篇Linux基础学习篇目录第零章﹑计算机概论关于电脑的硬件组成部分﹐其实你可以观察你的台式机来分析一下﹐依外观来说这家伙主要可分为三部分﹐分别是∶输入单元∶包括键盘﹑鼠标﹑读 ... [详细]
  • ubuntu下安装source ... [详细]
  • 编写程序可以用vi编辑器vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和 ... [详细]
  • 如何使网页自适应电脑屏幕分辨率?
    在1024*768或者800*600的分辨率下可以自动调整成适用于该客户端分辨率的大小。  第一种方法:做一个网页解决问题(长了点)  如果只是因为浏览者改变了浏览器的设置,或者因为浏览器不兼容,使自 ... [详细]
  • Unity中的事件监听
    Unity3D的uGUI系统的将UI可能触发的事件分为12个类型,即EventTriggerType枚举的12个值。如下图所示:先以PointerClick为例。这个是用于某点点击 ... [详细]
  • 微软正在逐步放弃在Windows
    在文件资源管理器中,3D对象文件夹与桌面、图片、文档等重要文件夹的快捷方式一起被放置,一直占用着视觉空间。同样,上下文菜单中也带有用Paint3D进行编辑的选项,而大多数人可能 ... [详细]
  • vscode调试c程序失败怎么办
    小编给大家分享一下vscode调试c程序失败怎么办,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!问题:执行调试时,出现问题:无法在 ... [详细]
  • 一、向Unity和Android问好欢迎来到手机游戏开发的精彩世界。无论你是还在寻找合适 ... [详细]
  • 写给前端同学的C++入门教程(一):概述和环境搭建
    说明:本人是前端er,因为最近对UE4(一个游戏开发引擎)产生了兴趣,而这个引擎源开发游戏时需要用到C++,所以就开始入坑C++了。现将自己学习C++的笔记整理并分享出来,以便一些 ... [详细]
  • 用uniapp和springboot做出的高效记忆小程序,技术点总结
    临时起意老早前就听说过一些高效记忆的方法,其中听的最多的就是艾宾浩斯记忆法和费曼学习法。恰好赶上过年放假,就在想除了吃吃吃之外,还能干点什么。本来想学习理财的知识,一看概念还真不少 ... [详细]
  • 卸载mysql残留【MySQL】
    数据库|mysql教程卸载mysql残留数据库-mysql教程A、在控制面板中查看是否有mysql,有则进行卸载。或运行相同版本的mysql安装文件,选择“remove”进行卸载。 ... [详细]
  • 编程技巧_安全编程的10个主要技巧
    编程技巧全世界的技术安全威胁正在逐渐增加。在以前,仅仅是个人信用卡号被盗之前,如今似乎几乎每天都有另一个严重违规的故事,其中披露了数百万条 ... [详细]
  • 10 软件源_WinQTLCartographer软件之QTL分析
    集思慧远又一QTL软件分析来啦!今天小编要跟大家分享的是WinQTLCart。WinQTLCart是北卡罗来纳州立大学发布的一款在windows下运行的QTL软件&# ... [详细]
  • 之前在命令行下面打印JSON的时候统统都是Cat,然后将结果复制到支持JSON解析的编辑器里面,非常曲折。简单的搜索了一下之后,在StackOverflow上找到了一篇文章。支持率 ... [详细]
author-avatar
dreamingsue
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有