前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >React | 如何制作一个按钮组件

React | 如何制作一个按钮组件

原创
作者头像
花花Binki
发布2024-06-16 23:45:36
1250
发布2024-06-16 23:45:36
举报
文章被收录于专栏:岚的工作随笔岚的工作随笔

概要

本文从零开始,使用React + TypeScript的方式制作一个按钮组件。

面临的挑战

起个好名

在计算机中,有一个经常遇到但又十分难缠的问题,起名。好的名字可能是灵感闪现,也可能来自借鉴。所以笔者回忆了下大厂的组件库,决定命名为fafa-design

于是在终端中输出如下指令

代码语言:shell
复制
npx create-react-app fafa-design --template typescript

代码结构

关于代码结构,各个公司,乃至各个部门都有各自的规范。本次就是用刚刚初始化的项目结构。见如下

代码语言:txt
复制
node_modules
public  // 本机临时演示用,后期删除
src // 本机临时演示用,后期删除
.gitignore
package-lock.json
package.json
README.md
tsconfig.json

在根目录src下新建一个component文件夹,用来存放组件,本期是做一个按钮,那么结构大概就长这样:

代码语言:txt
复制
component
    - button                            // button 组件
        - Index.tsx                     // 组件实现
        - PropsType.tsx                 // 组件接口
    - index.ts                          // 对外接口
    - styles                            // 统一样式

样式方案

对于Style,React 强调 All in JS。所以直接在标签上去写部分CSS是可以的。

代码语言:jsx
复制
<div style={{background: 'skyblue'}} >。。。</div>

当然,也可以抽离出来,单独作为一个对象。

这样做的优点就是:简单,可以加一些内部处理逻辑。缺点就是你的css属性需要做一些调整,比如下划线转为驼峰:

  • background-color -> backgroundColor 这样需要转换一下的。除此之外,还有统一管理,性能问题等。

那CSS-in-JS方案怎么样?

截取自旧版官方文档
截取自旧版官方文档

官方对此保持中立。


  • sass和less

这是比较大众的使用方式,大厂的组件库也大都采用此种。

需求分析

单纯的开发人员对需求都比较敏感,能不做就不做。就笔者来说,一时想不出要做什么功能。索性直接按照大厂的文档来做。

TDesign Button
TDesign Button

基础功能就是

  • 主题
  • 带Icon
  • 多尺寸

开始编码

原形按钮

写一个基础组件,一般依赖于原html,按钮也不例外。值得一提的是,如果你想在TypeScript中“继承”属性,并且添加自定义,你可以这样写:

代码语言:jsx
复制
export interface ButtonProps extends React.HTMLAttributes<HTMLButtonElement> {
  /** 类型 */
  type?: "primary" | "secondary" | "link";
  /** 尺寸 */
  size?: "small" | "medium" | "large";
...省略
}
// 画面描绘
<button {...restProps}>{children}</button>;

现在就得到了一个基础按钮,但是不太够好看。

给点颜色

在按钮的使用场景中,使用主要,次要,危险等颜色。不同的组件库,所选的这几种主题略有差别。见下面:

Ant Design的色彩选择
Ant Design的色彩选择

设计颜色不在行,来到代码层面,该怎样实现呢?

首先做一个基础style,然后根据type值修改background属性

代码语言:jsx
复制
  const buttonStyle = {
    backgroundColor: type === 'primary' ? '#007bff' :
                      type === 'secondary' ? '#6c757d' :
                      type === 'success' ? '#28a745' :
                      type === 'danger' ? '#dc3545' :
                      type === 'warning' ? '#ffc107' :
                      type === 'info' ? '#17a2b8' :
                      '#ffffff',
    color: '#ffffff',  // 这里也建议动态调整,比如深色背景配浅色字。
  ...省略
  };

按钮结合图标

图标有两种,一个是静态的,一个是loading。

无需重绘按钮,因为本身就是可以在button内部加入图标与文字,只需要注意对其方式即可。

比如,我这里加了一个TDesign的上传的图标

代码语言:jsx
复制
    <button {...restProps}>
      <svg fill="none" viewBox="0 0 24 24" width="1em" height="1em">
        <path
          fill="currentColor"
          d="M4.6 6.28a7.5 7.5 0 0114.8 0 6.5 6.5 0 011.06 12.01l-.9.46-.9-1.78.88-.46a4.5 4.5 0 00-1.23-8.44l-.77-.14-.05-.78a5.5 5.5 0 00-10.98 0l-.05.78-.77.14a4.5 4.5 0 00-1.23 8.44l.89.46-.91 1.78-.9-.46a6.5 6.5 0 011.06-12zm7.4 3.3L17.41 15 16 16.41l-3-3V23h-2v-9.59l-3 3L6.59 15 12 9.59z"
        ></path>
      </svg>
      {children}
    </button>

然后我们就得到一个

带Icon的按钮
带Icon的按钮

优化的点?

如果没有其它的处理,当页面上的元素很多时,会明显变卡。尤其是当一个state hook影响很多组件渲染时。这时会想:如果能告诉他哪些不需要渲染就好了。

React官方早就想到了这一点,所以有了useCallbackuseMemo等hook。

这些钩子的第二个参数就是让我们来告诉React,哪些需要真渲染,哪些需要使用缓存。

代码语言:jsx
复制
useCallback(() => {
  // doSomeThing
}, []) 

空数组表示只在创建时生成并缓存。useMemo同理,后者常用于组件的缓存

useMemo 和 useCallback 都可以用于缓存函数,二者有何不同? useMemo 用于缓存计算结果,只有当依赖项发生变化时,才会重新计算。它适用于不经常改变且计算成本较高的值。例如,当你需要根据组件的 props 计算一个复杂的对象或数组时,可以使用 useMemo 来避免不必要的重新计算。 useCallback 用于缓存函数,只有当依赖项发生变化时,才会返回一个新的函数。它适用于作为回调函数的函数,特别是当这个函数作为 prop 传递给子组件时。这样可以避免不必要的重新创建函数,减少组件重新渲染的次数。

不过,你需要注意缓存带来的后果。常常有一些莫名其妙的Bug发生于此。


延迟加载:参考Suspense组件

总结

厘清上述基本逻辑后,再去看组件库的源码可能还是一头雾水。因为需求是迭代来的,代码也是。但是,无论如何改变,你还是能找到基础设计的影子,以及design这一词的含义。希望本文对你有帮助。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概要
  • 面临的挑战
    • 起个好名
      • 代码结构
        • 样式方案
          • 需求分析
          • 开始编码
            • 原形按钮
              • 给点颜色
                • 按钮结合图标
                  • 优化的点?
                  • 总结
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档