React 5种高级组件模式

五种高级React模式的概述,本篇文章包括了示例代码,优缺点以及公共库中的具体用法。

不清楚你在日常设计组件的时候有没有问过自己以下问题之一:

  • 如何构建可重用组件以适应不同的用例?
  • 如何使用简单的 API构建组件,使其易于使用?
  • 如何在 UI 和功能方面构建可扩展的组件?

这些反复出现的问题导致了整个 React 社区的出现了一些高级模式。

在本文中,我们将概述 5 种不同的模式。为了便于比较,我们将对所有这些模式使用相同的结构:

我们将从一个简短的介绍开始,然后是一个真实的代码示例(基于简单的Counter组件)。

image.png

我们将列出各个模式的优点和缺点,然后以下面的两个标准进行评判:

  • 控制翻转: 给予组件用户的灵活性和控制级别。
  • 实现复杂性: 你和用户都难以使用该模式。

注意: 强烈建议阅读本片文章一定要边看源码边阅读,不然你看不懂!!!!!

源码: 快快点击这里!!

复合组件模式

这种模式更适用于设计灵活性较强的组件。而不需要不必要的Props传递。如果你想使你的组件更加具有灵活性,更加可定制,具有更好的关注点分离和更易理解的API,那么你就可以使用这种模式设计你的组件。

例子: 复合组件模式代码示例

import React from "react";
import Counter from "./Counter";

const Usage = () => {
  const handleChangeCount = (count) => {
    console.log("复合组件模式 -> count", count);
  };
  return (
    <div>
      <h1>复合组件模式 用例一</h1>
      <Counter onChange={handleChangeCount}>
        {/* 传递Props <Counter.Increment iconProps={{ spin: true }} /> */}
        <Counter.Increment />
        <Counter.Count max={10} />
        <Counter.Decrement />
      </Counter>
    </div>
  );
};

export default Usage;

复制代码

优点

  • 降低 API 复杂性:这里不是将所有 props 塞进一个巨大的父组件中并将它们深入到子 UI 组件中,而是将每个 props 附加到最有意义的子组件。

image.png

  • 灵活的标记结构:你的组件具有很大的 UI 灵活性,允许从单个组件创建各种案例。例如,用户可以更改子组件的顺序或定义应该显示哪一个。

image.png

  • 关注点分离:大部分逻辑包含在主Counter组件中,然后使用React.Context来共享states和handlers所有子组件。我们得到了明确的责任分工。

未命名文件.png

缺点

  • 过多的 UI 灵活性:灵活性伴随着引发意外行为的可能性(放置不需要的组件的子组件,使组件的子组件无序,忘记包含强制子组件)。

根据您希望用户如何使用您的组件,您可能不希望允许如此大的灵活性。

image.png

  • 更重的 JSX:应用此模式将增加 JSX 行的数量,特别是如果你使用 linterEsLint 或 代码格式化程序如Prettier。

在单个组件规模上这似乎没什么大不了的,但当你看大局时,肯定会产生巨大的差异。

image.png

标准:

  • 控制翻转: 1/4
  • 实现复杂性: 1/4

使用该模式的公共库:

Props控制模式

此模式将您的组件转换为受控组件。外部状态被用作“单一事实来源”,允许用户插入自定义逻辑来修改默认组件行为。

例子: Props控制模式代码示例

import React, { useState } from "react";
import Counter from "./Counter";

const Usage = () => {
  const [count, setCount] = useState(0);
  const handleChangeCount = (count) => {
    console.log("Props 控制模式 -> count", count);
    setCount(count);
  };
  return (
    <div>
      <h1>Props 控制模式 用例二</h1>
      <Counter onChange={handleChangeCount} value={count}>
        {/* 传递Props <Counter.Increment iconProps={{ spin: true }} /> */}
        <Counter.Increment />
        <Counter.Count max={10} />
        <Counter.Decrement />
      </Counter>
    </div>
  );
};

export default Usage;

复制代码

优点

  • 给予更多控制:由于状态暴露在你的组件之外,用户可以控制它,因此可以直接影响你的组件。

image.png

缺点

  • 实现复杂性:以前,在一个地方进行一次集成 ( JSX) 就足以使您的组件正常工作。现在,这将是分布在3米不同的地方(JSX/ useState/ handleChange)。

未命名文件 (2).png

标准:

  • 控制翻转: 2/4
  • 实现复杂性: 1/4

使用该模式的公共库:

自定义Hooks模式

让我们在“控制反转”中更进一步:现在将主要逻辑转移到自定义hook中。用户可以访问此hook并公开几个内部逻辑 ( States, Handlers),使他可以更好地控制你的组件。

例子:自定义Hooks模式代码示例

import React, { useEffect } from "react";
import Counter from "./Counter";
import useCounter from "./useCounter";

const Usage = () => {
  const { count, handleDecrement, handleIncrement } = useCounter(0);
  useEffect(() => {
    console.log("自定义 Hooks 模式 -> count", count);
  }, [count]);
  return (
    <div>
      <h1>自定义 Hooks 模式 用例三</h1>
      <Counter value={count}>
        {/* 传递Props <Counter.Increment iconProps={{ spin: true }} /> */}
        <Counter.Increment onClick={handleIncrement} />
        <Counter.Count max={10} />
        <Counter.Decrement onClick={handleDecrement} />
      </Counter>
    </div>
  );
};

export default Usage;

复制代码

优点

  • 给予更多控制:用户可以在 hook 和 JSX 元素之间插入他自己的逻辑,允许他修改默认的组件行为。

image.png

未命名文件 (4).png

缺点

  • 实现复杂度:由于逻辑部分与渲染部分分离,必须由用户将两者联系起来。正确实现组件需要很好地理解组件的工作方式。

WX20210612-140824@2x.png

标准:

  • 控制翻转: 2/4
  • 实现复杂性: 2/4

使用该模式的公共库:

Props Getters 模式

Props Getters 模式提供了很好的控制,但也使你的组件更难集成,因为用户必须处理大量本地钩子的props并重新创建他的逻辑。该Props Getters 模式试图掩盖这种复杂性。我们提供了一个Props getters,而不是原生Props 。getter是一个返回许多 props 的函数,它有一个有意义的名称,允许用户自然地将它链接到正确的 JSX 元素。

例子:Props Getters 模式代码示例

import React, { useEffect } from "react";
import Counter from "./Counter";
import useCounter from "./useCounter";

const Usage = () => {
  const { getCountProps, getDecrementProps, getIncrementProps } = useCounter({
    initValue: 0,
    max: 20,
  });

  const handleClickIncrement = () => {
    console.log("handleIncrement -> Props Getters 模式");
  };
  const handleClickDecrement = () => {
    console.log("handleIncrement -> Props Getters 模式");
  };

  return (
    <div>
      <h1>Props Getters 模式 用例四</h1>
      <Counter {...getCountProps()}>
        {/* <Counter.Increment
          {...getIncrementProps({
            onClick: handleClickIncrement,
            iconProps: { spin: true },
          })}
        /> */}
        <Counter.Increment
          {...getIncrementProps({
            onClick: handleClickIncrement,
          })}
        />
        <Counter.Count max={10} />
        <Counter.Decrement
          {...getDecrementProps({ onClick: handleClickDecrement })}
        />
      </Counter>
    </div>
  );
};

export default Usage;

复制代码

优点

  • 易用性:提供一种简单的方法来集成你的组件,隐藏复杂性,用户只需将正确的连接到正确getter的 JSX 元素。

未命名文件 (5).png

缺点

  • 缺乏可见性: 带来的抽象getters使你的组件更容易集成,但也更不透明。要正确覆盖您的组件,用户必须知道 getter 公开的 props 列表以及其中一个更改时的内部逻辑影响。

标准:

  • 控制翻转: 3/4
  • 实现复杂性: 3/4

使用该模式的公共库:

State Reducer 模式

控制反转方面最先进的模式。它为用户提供了一种高级方法来更改组件在内部的运行方式。
代码类似于自定义Hook模式,但除此之外,用户还定义了reducer传递给钩子的 。这reducer将使组件的任何内部操作重载。

例子:State Reducer 模式代码示例

import React, { useEffect } from "react";
import Counter from "./Counter";
import useCounter from "./useCounter";

const Usage = () => {
  const reducer = (state, action) => {
    switch (action.type) {
      case "Decrement":
        return {
          count: Math.max(0, state.count - 2),
        };
      default:
        return useCounter.reducer(state, action);
    }
  };

  const { count, handleDecrement, handleIncrement } = useCounter(
    {
      initValue: 0,
      max: 20,
    },
    reducer
  );

  useEffect(() => {
    console.log("State Reducer 模式 -> count", count);
  }, [count]);

  return (
    <div>
      <h1>State Reducer 模式 用例五</h1>
      <Counter value={count}>
        <Counter.Increment onClick={handleIncrement} />
        <Counter.Count max={10} />
        <Counter.Decrement onClick={handleDecrement} />
      </Counter>
    </div>
  );
};

export default Usage;

复制代码

优点

  • 给予更多控制权:在最复杂的情况下,使用state reducers是将控制权留给用户的最佳方式。所有内部组件的操作现在都可以从外部访问并且可以被覆盖。

未命名文件 (6).png

缺点

  • 实现复杂性:对于您和用户来说,这种模式无疑是最复杂的。
  • 缺乏可见性:由于任何reducer的动作都可以改变,因此需要很好地理解组件的内部逻辑。

标准:

  • 控制翻转: 4/4
  • 实现复杂性: 4/4

使用该模式的公共库:

总结

通过这 5 个高级 React 模式,我们已经看到了利用“控制反转”概念的不同方式。它们为你提供了一种创建灵活且适应性强的组件的强大方法。
但是,我们都知道“能力越大,责任越大”这句著名的谚语,你将控制权转移给用户的次数越多,你的组件就越远离“即插即用”的思维方式。作为开发人员,你的职责是根据正确的需求选择正确的模式。

往期精彩文章

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享