React组件二次包装的具体实现

目录
  • 1. 类型声明
  • 2. 默认属性
  • 3. 自定义属性与属性透传

原生组件是对公共场景的抽象,若要契合实际业务往往需要对其进行二次包装。
对组件进行二次包装一般需要进行包括不限于以下的步骤:

  • 组件类型类型声明
  • 自定义组件渲染逻辑
  • 向原生组件透传属性

1. 类型声明

类型声明是组件二次包装过程中的第一步,项目中常见的方案是直接进行类型声明,例如通过Button组件包装个自定义的Button:

import React, { CSSProperties } from "react";
import { Button } from "@arco-design/web-react";

type IProps = {
  style?: CSSProperties;
  className?: string | string[];
  type?: "default" | "primary" | "secondary" | "dashed" | "text" | "outline";
  // ...其他Button属性
};

const MyButton: React.FC<IProps> = ({ style, className, type, children }) => {
  // 此处为自定义逻辑

  return (
    <Button style={style} className={className} type={type}>
      {children}
    </Button>
  );
};

export default MyButton;

直接类型声明简单粗暴,用到什么属性就添加什么,但存在一个致命的,其限定了原生组件提供的能力,降低了二次包装的自定义组件的可用性。
因此更为好的方案是类型继承,不仅继承类型,也继承属性:

import React from "react";
import { Button, ButtonProps } from "@arco-design/web-react";

// 继承类型
type IProps = ButtonProps & {};

const MyButton: React.FC<IProps> = (props) => {
  // 此处为自定义逻辑

  // 继承属性
  return <Button {...props} />;
};

export default MyButton;

2. 默认属性

开源组件库提供的组件满足了日常项目的开发需求,但开源项目毕竟是面对公共场景,其组件默认值并不能匹配实际的业务场景,因此我们通常需要在二次包装自定义组件的时候重置默认值。
常见的重置方案也是直接重置:

import React from "react";
import { Button, ButtonProps } from "@arco-design/web-react";

type IProps = ButtonProps & {};

const MyButton: React.FC<IProps> = (props) => {
  const { size = "large", type = "primary" } = props;
  return <Button size={size} type={type} {...props} />;
};

export default MyButton;

这种方式很直观,也没有任何问题。但追求极致的各位大佬们,肯定在重置多个自定义组件的过程中厌烦了这种重复的写法。
因此更好的方式是使用高阶组件,首先先定义一个通用的Hoc:

import React from "react";

/**
 * 组件默认属性Hoc
 * @param defaultProps 默认属性
 * @returns
 */
export function withDefaultProps<P = {}>(defaultProps?: Partial<P>) {
  return function (Component: any) {
    const WrappedComponent: React.FC<P> = (props) => {
      return React.createElement(Component, {
        ...defaultProps,
        ...props,
      });
    };

    WrappedComponent.displayName = `withDefaultProps(${getDisplayName(
      Component
    )})`;

    return WrappedComponent;
  };
}

这时候属性重置就会变得有亿点点优雅了:

import React from "react";
import { Button, ButtonProps } from "@arco-design/web-react";

type IProps = ButtonProps & {};

export default withDefaultProps<IProps>({
  size: "large",
  type: "primary",
})(Button);

通过组件默认属性Hoc可以有效抽离包装业务组件,优化代码结构。

3. 自定义属性与属性透传

二次包装组件的当然不仅仅只包含原生组件的属性,还有新增的自定义属性,例如下面定义的组件:

import React, { useEffect } from "react";
import { Button, ButtonProps } from "@arco-design/web-react";

type IProps = ButtonProps & {
  hello?: string;
};

const MyButton: React.FC<IProps> = (props) => {
  useEffect(() => console.log(props.hello), [props.hello]);

  return <Button {...props} />;
};

export default withDefaultProps<IProps>({
  hello: "world",
})(MyButton);

上述代码中未过滤自定义属性,可能会导致原生组件接收非声明的属性导致渲染异常(例如Antd组件会将未声明属性渲染为文档标签属性,输出控制台错误)。
因此往往需要做自定义属性过滤后再进行透传,过滤方式包括不限于以下这些:

  • 通过拓展运算符
  • 通过omit函数

改造后代码如下:

import React, { useEffect } from "react";
import { Button, ButtonProps } from "@arco-design/web-react";

type IProps = ButtonProps & {
  hello?: string;
};

/// 这里通过拓展运算符过滤原生组件未声明属性
const MyButton: React.FC<IProps> = ({ hello, ...restProps }) => {
  useEffect(() => console.log(hello), [hello]);

  return <Button {...restProps} />;
};

export default withDefaultProps<IProps>({
  hello: "world",
})(MyButton);

到此这篇关于React组件二次包装的具体实现的文章就介绍到这了,更多相关React组件二次包装装内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 基于React封装组件的实现步骤

    目录 前言 antd 是如何封装组件的 divider 组件源代码 如何暴露组件属性 如何设置统一类名前缀 如何处理样式与类名 divider 组件样式源代码 前言 很多小伙伴在第一次尝试封装组件时会和我一样碰到许多问题,比如人家的组件会有 color 属性,我们在使用组件时传入组件文档中说明的属性值如 primary ,那么这个组件的字体颜色会变为 primary 对应的颜色,这是如何做到的?还有别人封装的组件类名都有自己独特的前缀,这是如何处理的呢,难道是 css 类名全部加上前缀吗,这也太

  • 你知道怎么基于 React 封装一个组件吗

    目录 antd 是如何封装组件的 仓库地址 divider 组件源代码 如何暴露组件属性 如何设置统一类名前缀 如何处理样式与类名 divider 组件样式源代码 总结 前言 很多小伙伴在第一次尝试封装组件时会和我一样碰到许多问题,比如人家的组件会有 color 属性,我们在使用组件时传入组件文档中说明的属性值如 primary ,那么这个组件的字体颜色会变为 primary 对应的颜色,这是如何做到的?还有别人封装的组件类名都有自己独特的前缀,这是如何处理的呢,难道是 css 类名全部加上前缀

  • React Form组件的实现封装杂谈

    前言 对于网页系统来说,表单提交是一种很常见的与用户交互的方式,比如提交订单的时候,需要输入收件人.手机号.地址等信息,又或者对系统进行设置的时候,需要填写一些个人偏好的信息. 表单提交是一种结构化的操作,可以通过封装一些通用的功能达到简化开发的目的.本文将讨论Form表单组件设计的思路,并结合有赞的ZentForm组件介绍具体的实现方式.本文所涉及的代码都是基于React v15的版本. Form组件功能 一般来说,Form组件的功能包括以下几点: 表单布局 表单字段 封装表单验证&错误提示

  • React组件二次包装的具体实现

    目录 1. 类型声明 2. 默认属性 3. 自定义属性与属性透传 原生组件是对公共场景的抽象,若要契合实际业务往往需要对其进行二次包装.对组件进行二次包装一般需要进行包括不限于以下的步骤: 组件类型类型声明 自定义组件渲染逻辑 向原生组件透传属性 1. 类型声明 类型声明是组件二次包装过程中的第一步,项目中常见的方案是直接进行类型声明,例如通过Button组件包装个自定义的Button: import React, { CSSProperties } from "react"; imp

  • ES6下React组件的写法示例代码

    本文主要跟大家分享了ES6下React组件的写法示例,下面来一起看看详细的介绍: 一:定义React组件 class Hello extends React.Component { render() { return <h1>Hello, {this.props.value}</h1>; } } 二:声明prop类型与默认prop class Hello extends React.Component { // ... } Hello.propTypes = { value: Re

  • 用react-redux实现react组件之间数据共享的方法

    上篇文章写到了redux实现组件数据共享的方法,但是在react中,redux作者提供了一个更优雅简便的模块实现react组件之间数据共享.那就是利用react-redux 利用react-redux实现react组件数据之间数据共享 1.安装react-redux $ npm i --save react-redux 2.从react-redux导入Prodiver组件将store赋予Provider的store属性, 将根组件用Provider包裹起来. import {Provider,c

  • React 组件间的通信示例

    前言 从官网上也有介绍组件间如何通信,但不够详细,这里做个小结,方便对比和回顾 本文内容 处理组件之间的通信, 主要取决于组件之间的关系,因此我们划分为以下三种: [父组件]向[子组件]传值: [子组件]向[父组件]传值: [组件A]向无关系[组件B]传值,一般为兄弟组件: 一.「父组件」向「子组件」传值 这是最普遍的用法,实现上也非常简单,主要是利用props来实现 // 父组件 import React from 'react'; import Son from './components/

  • 编写简洁React组件的小技巧

    本文源于翻译文章 Simple tips for writing clean React components, 原文作者 Iskander Samatov 在这篇文章中,我们会回顾一些简单的技巧,它们将帮助我们编写更简洁的 React 组件,并且更好地扩展我们的项目. 避免使用扩展操作符传递 props 首先,让我们从一个应该避免的反模式开始.除非有明确的理由这样做,否则应该避免在组件树中使用扩展操作符传递props,比如:{ ...props }. 通过这种方式传递 props 确实可以更快

  • React组件的生命周期详细描述

    目录 一.什么是生命周期 二.装载过程 1.constructor 2.render 3.componentWillMount和componentDidMount 三.更新过程 1.componentWillReceiveProps(nextProps) 2.shouldComponentUpdate(nextProps, nextState) 3.componentWillUpdate和componentDidUpdate 4.触发render 四.卸载过程 五.生命周期流程 1.第一次初始化

  • React组件间通信的三种方法(简单易用)

    目录 一.父子组件通信 二.跨级组件通信 1.逐层传值 2.跨级传值 三.兄弟(无嵌套)组件通信 四.路由传值 五.Redux React知识中一个主要内容便是组件之间的通信,以下列举几种常用的组件通信方式,结合实例,通俗易懂,建议收藏. 一.父子组件通信 原理:父组件通过props(与vue中的props区分开)向子组件通信,子组件通过回调事件与父组件通信. 首先,先创建一个父组件Parent.js跟子组件Children.js,二者的关系为直接父子关系. Parent.js父组件如下,给父组

  • Vue组件二次封装的一些实用技巧总结

    目录 前言 透传 Attribute 透传 slot 普通slot 动态插槽名 作用域插槽 封装组件存在的问题 组件实例属性和方法的调用 总结 前言 在开发Vue项目我们一般使用第三方UI组件库进行开发,如element-plus, @arco-design/web-Vue, naive-ui等, 但是这些组件提供的接口并不一定满足我们的需求,这时我们可以通过对组件库组件的二次封装,来满足我们特殊的需求. 对于封装组件有一个大原则就是我们应该尽量保持原有组件的接口,除了我们需要封装的功能外,我们

  • 解决react组件渲染两次的问题

    目录 react组件渲染两次 react总结之避免不必要的重复渲染 类组件PureComponent 使用插件seamless-immutable 使用插件pure-render-decorator react组件渲染两次 可能会有人问,问什么我的组件明明是就让渲染一次,但是实际上却渲染两次呢?其实我也遇到了这个问题,那么下面我提出一种解决这个问题的一种方法. 如果你使用了react-router低于4.x版本中的hashHistory,那么问题就来了,出现这种情况的原因是因为router中进行

  • React组件实例三大属性state props refs使用详解

    目录 一. State 1.概念 2.State的简单用法 3. JS绑定事件 4.react 绑定事件 5.react this指向问题 6.修改state值 7.代码简写 二.props 1.概念 2.传参的基础方法.运算符传参 三.refs 定义 字符串形式的ref.回调函数下ref.createRef 创建ref容器 一. State 1.概念 概念:state是组件对象最重要的属性,值是对象(可以包含多个key:value的组合),组件被称为状态机,通过更新组件的state来更新对应的

随机推荐