React hooks分离关注点

React hooks分离关注点

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

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

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

随着 React hook 的引入,这方面又有了新的方法:使用定制的 hook

为什么我们要将逻辑与组件分开?

在我们开始将逻辑与我们的反应组件分离之前,我们应该知道原因。

组织我们的代码时,每个函数或组件只负责一件事情,它的优点是更容易更改和维护(Dave和Andrew在他们的书“务实的程序员”中称之为“正交性”)。

将此应用于反应意味着我们的组件看起来更干净和更有组织。例如,在编辑UI之前,我们不需要翻过逻辑墙。

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

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

如何用 React hooks 解耦逻辑

为了将逻辑从组件中解耦,我们将首先创建一个自定义hook。

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

256.00

你可以在这里找到完整的源代码。

代码如下所示:

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>
  );
};
复制代码

这可能看起来已经很好了,但是为了本教程的缘故,请想象这里有更多的逻辑。

作为第一步,我们将把逻辑移到一个自定义hook上,并在组件内部调用它。

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();

  // ...
};
复制代码

我们可以将这个hook移动到一个单独的文件中,以便更显著地分离关注点。

此外,我们还可以将hook进一步分离成更小的、可重用的函数。在这种情况下,我们只能提取计算指数

useExponentCalculator.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 ),而我们的业务逻辑存在于我们后面定义的不同函数中(这些函数与框架无关)。

最佳做法

命名

我喜欢以组件的名称命名我的定制hook,作为使用和组件名称的串联 (e.g. useExponentCalculator). 然后我调用文件相同的hook。

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

如果我可以重用定制hook的部分内容,我通常会将其移动到src/hook下的另一个文件中。

不要做的太多余

尽量讲求实效。如果组件只有几行JS,则没有必要分离逻辑。

CSS-in-JS

如果您正在使用CSS-in-JS库(UsStyle),您可能也希望将此代码移动到另一个文件中。

你可以把它和钩子放在同一个文件里。但是,我更喜欢将其保留在同一个文件中的组件之上,或者在它增长过大时将其移动到自己的文件中。

结论

不管你是否认为使用自定义 hooks 提高了你的代码,最终还是取决于个人喜好。如果你的代码库没有包含很多逻辑,那么这种模式的优势对你来说就没有太大的相关性。

定制hooks只是增加模块化的一种方法; 我还强烈建议尽可能将组件和函数拆分为更小的、可重用的块

这个话题在**《实用程序员》**一书中也有更一般的讨论。我写了一篇文章,涵盖了我最喜欢的主题的书,所以如果你有兴趣,一定要检查出来

链接

我发现这里有一些文章对研究这篇文章有帮助:

我写的其他一些文章你可能会喜欢读:

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