返回

以显式简化封装复杂公共组件的三要素

前端

当我们进行组件封装时,我们一般需要实现两个主要的功能:

  • 可复用:封装成可以被其他程序使用
  • 可配置:提供多种方式让用户进行配置。

在本文中,我们将以开发表单组件库为案例,对输入框组件实现一个最简单的属性配置封装,通过这一个组件的封装,去理解公共组件封装中最核心的三要素。

在进行以下步骤之前,请确保你已经了解了诸如函数式组件钩子函数声明状态 等基本概念。

封装组件

import React, { useState } from "react";

export function Input(props: any) {
  // 将placeholder进行类型校验
  const _placeholder = typeof props.placeholder === "string" ? props.placeholder : '';

  // 使用useState声明一个状态,来保存输入的内容
  const [value, setValue] = useState(props.value ? props.value : '');

  // 输入框的onChange事件
  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    // 将输入的值赋给value这个状态
    setValue(event.target.value);
  };

  return (
    <input
      {...props}
      value={value}
      placeholder={_placeholder}
      onChange={handleChange}
    />
  );
}

在进行组件封装时,我们需要仔细思考一个问题,组件的状态应该在哪里声明

我们知道,状态唯一可以改变的 。那么在开发组件时,状态是一个很容易导致父组件与子组件之间的逻辑混乱的点。我们通常需要认真考虑状态的声明位置。

比如,对于这个输入框组件而言,如果我们希望支持受控组件,也就是从父组件传递value来控制输入框的状态,那么我们就不能在组件内部声明状态。

同时,考虑到后续我们会封装一个表单组件,我们需要在表单组件内部支持表单受控,也就是从表单组件外部传递值来修改表单内部所有输入框的值。这样一来,我们也不应该在输入框内部声明状态。

所以,在最终实现这个组件的组件库时,我们通过组合继承,在父组件内部声明组件状态,这样就实现了一个通用的可配置输入框组件。

声明属性与状态

接下来,我们要思考的是组件的属性与状态,我们应该如何进行声明。

首先,我们先明确 属性状态 的区别。

属性 是从外部组件传递过来的值,在组件内部使用这些属性值进行组件渲染,组件并不能修改自己的属性

状态唯一可以改变的 ,它由组件内部维护,可以被组件自身通过一些操作进行修改。

我们从这个输入框组件的角度来说,它的属性一般包括:

  • id
  • placeholder
  • type
  • value

而它的状态一般包括:

  • 输入框的值
  • 是否有焦点
  • 是否被禁用
  • 是否正在提交

显而易见,这个组件的属性与状态是非常多的。

在声明属性与状态时,我们需要秉持着最少原则

我们应该只在组件内部声明和使用那些必须 的属性与状态,而不是把所有可能的情况都考虑进来。我们更希望的做法是根据实际情况进行属性与状态的声明。

例如,在实现这个输入框组件时,我们仅支持受控组件,也就是状态全部由外部组件声明,在这个场景下,组件内部完全没有必要声明状态。

export function Input(props: any) {
  const _placeholder = typeof props.placeholder === "string" ? props.placeholder : '';
  
  return (
    <input
      {...props}
      placeholder={_placeholder}
    />
  );
}

暴露组件

完成属性和状态的声明之后,我们就可以导出组件了。

如果我们写一个npm包,那么在index.js文件里我们需要导出这个组件,在最终的发布包里,用户可以通过 import Input from 'xxx' 来使用这个组件。

export { Input };

总结

在本文中,我们通过开发表单组件库的案例,理解了组件封装中最核心的三要素:

  • 组件的状态应该在哪里声明
  • 组件的属性与状态应该如何进行声明
  • 暴露组件

我们希望通过这三个要素的实现,可以帮你去开发出一个可复用,且可配置性较强的公共组件库。