使用 React 分离关注点挂钩 PlatoBlockchain 数据智能。 垂直搜索。 哎。

使用 React 钩子分离关注点

如果你已经使用 React 一段时间了,你可能遇到过 容器表示组件 ,或智能和愚蠢的组件。 这些术语描述了一个 模式 将 React 组件的 UI 层与逻辑分开。

将 UI 与业务逻辑分离并不是 React 独有的:关注点分离是一种设计原则,它具有 已经在 70 年代左右. 例如,通常的做法是将访问数据库的代码与后端的业务逻辑分开。

所以在 React 中,我们通过创建包含所有逻辑的容器组件来解决这个问题,然后容器组件会通过 props 将数据传递给展示组件。

随着 React 钩子的引入,有一种新的方法:使用 定制挂钩.

为什么要把逻辑和组件分开?

在我们开始将逻辑与 React 组件解耦之前,我们应该知道原因。

以一种每个功能或组件只负责一件事的方式组织我们的代码,其优势在于它是多 更易于更改和维护 (戴夫和安德鲁称之为“正交性” 在他们的书中 务实的程序员).

将其应用于 React 意味着我们的组件将看起来更干净、更有条理。 例如,在编辑 UI 之前,我们不需要滚动逻辑墙。

像这样组织你的代码不仅使它看起来更好,更容易导航,它也使它更容易改变,因为改变钩子不会影响 UI,反之亦然。

测试也更容易访问:如果我们愿意,我们可以将逻辑与 UI 分开测试。 然而,对我来说最重要的优势是这种方法如何组织我的代码。

如何用 React 钩子解耦逻辑

为了将逻辑与我们的组件解耦,我们将首先创建一个自定义钩子。

我们以这个组件为例。 它计算基数和指数的指数值:

你可以找到完整的源代码 此处.

代码如下所示:

export const ExponentCalculator = () => {
  const [base, setBase] = useState(4);
  const [exponent, setExponent] = useState(4);
  const result = (base ** exponent).toFixed(2);

  const handleBaseChange = (e) => {
    e.preventDefault();
    setBase(e.target.value);
  };

  const handleExponentChange = (e) => {
    e.preventDefault();
    setExponent(e.target.value);
  };

  return (
    <div className="blue-wrapper">
      <input
        type="number"
        className="base"
        onChange={handleBaseChange}
        placeholder="Base"
        value={base}
      />
      <input
        type="number"
        className="exponent"
        onChange={handleExponentChange}
        placeholder="Exp."
        value={exponent}
      />
      <h1 className="result">{result}</h1>
    </div>
  );
};

这可能看起来已经很好了,但是为了本教程,只需 想像 这里有更多的逻辑。

作为第一步,我们将 将逻辑移动到自定义挂钩 并在我们的组件中调用它。

const useExponentCalculator = () => {
  const [base, setBase] = useState(4);
  const [exponent, setExponent] = useState(4);
  const result = (base ** exponent).toFixed(2);

  const handleBaseChange = (e) => {
    e.preventDefault();
    setBase(e.target.value);
  };

  const handleExponentChange = (e) => {
    e.preventDefault();
    setExponent(e.target.value);
  };

  return {
    base,
    exponent,
    result,
    handleBaseChange,
    handleExponentChange,
  };
};

export const ExponentCalculator = () => {
  const {
    base,
    exponent,
    result,
    handleExponentChange,
    handleBaseChange,
  } = useExponentCalculator();

  // ...
};

我们可以把这个钩子移到一个 单独的文件 用于更突出的关注点分离。

此外,我们可以进一步将我们的钩子分成更小的、可重用的函数。 在这种情况下,我们只能提取 calculateExponent.

使用指数计算器.js

const calculateExponent = (base, exponent) => base ** exponent;

const useExponentCalculator = () => {
  const [base, setBase] = useState(4);
  const [exponent, setExponent] = useState(4);
  const result = calculateExponent(base, exponent).toFixed(2);

  // ...
};

测试这些函数比测试第一个示例中的整个组件的代码要容易得多。 我们可以使用任何 Node.js 测试库来测试它们,甚至不需要支持 React 组件。

现在,我们在组件和钩子的代码中拥有了特定于框架的代码(React),而我们的业务逻辑存在于我们稍后定义的不同函数中(与框架无关)。

最佳实践

命名

我喜欢将我的自定义钩子命名为组件后的串联 use 和组件的名称(例如 useExponentCalculator)。 然后我打电话给 归档相同 作为钩子。

您可能想要遵循不同的命名约定,但我建议 保持一致 在你的项目中。

如果我可以重用自定义钩子的一部分,我通常将它移动到另一个文件 src/hooks.

不要过度

尽量务实。 如果一个组件只有几行 JS,则不需要分离逻辑。

JS 中的 CSS

如果您使用的是 CSS-in-JS 库(useStyles),您可能还想将此代码移动到另一个文件中。

您可以将其移动到与钩子相同的文件中。 但是,我更喜欢将其保留在同一文件中的组件上方,或者如果它变得太大,则将其移动到自己的文件中。

结论

无论您是否认为使用自定义钩子会改进您的代码,最终,这都取决于个人喜好。 如果您的代码库不包含大量逻辑,则此模式的优势与您无关。

自定义钩子只是增加模块化的一种方式; 我也强烈推荐 将组件和功能拆分成更小的、可重用的块 若有可能。

该主题也在更一般的层面上进行了讨论 务实的程序员. 我写了一篇文章,涵盖了本书中我最喜欢的主题,因此,如果您对此感兴趣,请确保 检查出.

时间戳记:

更多来自 Codementor 反应事实