<SKYLER/>
组件封装tip
Back to Blog
August 25, 2022(updated June 29, 2024)React.js, 组件设计

🪢组件封装tip

组件分类

    作为一个前端开发,我们可用的组件库相当丰富,有antd、mui、elementui等等,但是不是有了这些UI库后,我们在业务开发中就不用封装组件了,我把组件分为这么几类:
  1. Page组件,这种是页面级组件,一个页面就是一个组件,用于组织业务组件、通用组件和业务逻辑。
  2. 业务组件,这个级别的组件是包含了系统的特定业务逻辑且可复用的,比如我们系统中有一个流程图渲染组件,这就属于一个业务组件,业务组件中可以包含通用组件。
  3. 通用组件,这个是最细粒度级别的组件,比如一个按钮、标签、tabs等,在任何系统都会有这样的组件需求。

组件封装tip

这里介绍一些我在开发中的一些封装思路。

我们要封装组件要考虑两件事情。

  1. 复用级别。复用级别就是我上述所说的是属于哪种组件,业务组件和通用组件很好区分,包含了系统业务逻辑的就属于业务组件。
  2. 易用性,易用性涉及到props如何设计、文档是否完善、组件demo,如何让使用者使用简便,愿意去使用你封装的组件,这是一个很重要的指标。

下面我想主要围绕易用性讲一个例子,浏览器有一个API ResizeObserver,用于监听dom大小变化,我们在React使用通常是这样的

const ref = useRef();
const [sizeObj, setSizeObj] = useState({ width: 0, height: 0 });
useEffect(() => {
  const resizeObserver = new ResizeObserver((entries) => {
    const el = entries[0].target;
    setSizeObj({
      width: el.clientWidth,
      height: el.clientHeight,
    });
    onResize(el, el.clientWidth, el.clientHeight);
  });
  resizeObserver.observe(ref.current);

  return () => {
    resizeObserver.disconnect();
  };
}, []);

这段代码是固定范式,所以我们可以把它抽取成一个通用组件,在容器变化后把宽高状态向下传递渲染子组件,可以是这样的:

export default ({ className, style, onResize = () => {}, children }) => {
  const ref = useRef();
  const [sizeObj, setSizeObj] = useState({ width: 0, height: 0 });
  useEffect(() => {
    const resizeObserver = new ResizeObserver((entries) => {
      const el = entries[0].target;
      setSizeObj({
        width: el.clientWidth,
        height: el.clientHeight,
      });
      onResize(el, el.clientWidth, el.clientHeight);
    });
    resizeObserver.observe(ref.current);

    return () => {
      resizeObserver.disconnect();
    };
  }, []);

  return (
    <div ref={ref} style={style} className={className}>
      {children(sizeObj)}
    </div>
  );
};

这个组件props很简单,className和style是为了控制容器的样式,onResize是宽高变化的回调,有时候外部需要这样的回调,children是要渲染的子组件,它是一个函数,通过把sizeObj传入来渲染。

这里的易用性体现在复用了代码,用户不用每次都写模版代码。