React:如何创建一个自定义hook

551 阅读4分钟

React:如何创建一个自定义hook

原文链接:www.robinwieruch.de/react-custo…

React引入Hooks已经有一段时间了。随着它们的发布,Hooks通过内置的hook为函数组件提供了状态管理和副作用的能力,例如useState和useEffect。

然而React提供的内置hook很少(例如:useReducer,useCallBack,useMemo,useContext)。不过,以这些内置hook作为基础,React开发者可以创建自己的自定义hook。在这个教程作为学习实践,我将带你创建一个自定义hook。

在我们创建一个自定义hook,你应该知道创建一个hook的两个规则:

  • 自定义hooks命名需要以"use"作为前缀。例如,一个自定义hook可以被命名useLocalStorage或useAuthentication。在我们的例子中,这个自定义的hook会被命名为useBoolean。
  • 自定义hooks由React内置的hook或其他的自定义hook组成。因此一个自定义hook本质是一个或多个hook构成的新组合。如果一个自定义hook没有使用任何的内部hook,那它就不是一个自定义hook,也不应该以"use"为前缀。

我们会创建一个自定义hook命名为useBoolean,当我作为一个React自由职业者参与一个新项目时,我几乎都会使用它。不过在我们实现这个hook之前,看下它为我们解决了什么问题。让我们以一个小例子开始:

import * as React from 'react';

function App() {
  const [isToggle, setToggle] = React.useState(false);

  const handleToggle = () => setToggle(!isToggle);

  return (
    <div>
      <button type="button" onClick={handleToggle}>
        Toggle
      </button>

      {isToggle.toString()}
    </div>
  );
}

export default App;

这个组件渲染了一个可以切换一个布尔值的按钮。在真实世界的React应用中,一个状态布尔值对你来说可做的并不多。要么你可以切换它(就像前面的例子),要么直接将它设置为 true 或 false (就像下面的例子) :

import * as React from 'react';

function App() {
  const [isToggle, setToggle] = React.useState(false);

  const handleToggle = () => setToggle(!isToggle);
  const handleTrue = () => setToggle(true);
  const handleFalse = () => setToggle(false);

  return (
    <div>
      <button type="button" onClick={handleToggle}>
        Toggle
      </button>
      <button type="button" onClick={handleTrue}>
        To True
      </button>
      <button type="button" onClick={handleFalse}>
        To False
      </button>

      {isToggle.toString()}
    </div>
  );
}

export default App;

一些开发者可能会争辩,我们可以使用内联处理来代替,这样就不会有重复声明的事件处理。但是,就我个人而言会尽可能避免内联处理,因为它们会在jsx中注入太多逻辑,而应该在组件的函数签名和返回语句之间定义函数来替代。不过这只是个人偏好。

总之,你每次使用状态布尔值,你都会遇到相同的实现细节:切换布尔值或者将其设置为两个可能值中的一个。在多个React组件中使用状态布尔值时,为了规避这段重复代码,我开始创建一个自定义hook。

const useBoolean = () => {
  const [state, setState] = React.useState();

  const handleTrue = () => setState(true);
  const handleFalse = () => setState(false);
  const handleToggle = () => setState(!state);

  return [
    state,
    {
      setTrue: handleTrue,
      setFalse: handleFalse,
      setToggle: handleToggle,
    },
  ];
};

本质上是把包含状态和事件处理的所有实现细节,移动到这个名为useBoolean的hook中。另外,这个自定义hook返回一个数组,包含状态和一些更新状态函数。

从一个自定义hook中需要返回多个值时最佳的做法是返回一个数组,因为React内置的hooks在返回多个值时,都会利用数组和数组解构。使用数组解构带来的好处就是可以指定任何变量名(相比于在对象解构中的重命名代码量更少)。

const useBoolean = (initialState = false) => {
  const [state, setState] = React.useState(initialState);

  const handleTrue = () => setState(true);
  const handleFalse = () => setState(false);
  const handleToggle = () => setState(!state);

  return [
    state,
    {
      setTrue: handleTrue,
      setFalse: handleFalse,
      setToggle: handleToggle,
    },
  ];
};

一个很好的补充是增加了一个初始状态(如上一个代码片段所示)。回到我们的应用组件中,我们可以通过传递一个初始状态使用这个新的自定义hook,利用它的返回值来显示和更新状态。

function App() {
  const [isToggle, { setToggle }] = useBoolean(false);

  return (
    <div>
      <button type="button" onClick={setToggle}>
        Toggle
      </button>

      {isToggle.toString()}
    </div>
  );
}

由于这个自定义hook不仅提供切换状态布尔值的更新函数,还可以显式设置true或者false,所以我们都可以使用这些函数:

function App() {
  const [isToggle, {
    setToggle,
    setTrue,
    setFalse,
  }] = useBoolean(false);

  return (
    <div>
      <button type="button" onClick={setToggle}>
        Toggle
      </button>
      <button type="button" onClick={setTrue}>
        To True
      </button>
      <button type="button" onClick={setFalse}>
        To False
      </button>

      {isToggle.toString()}
    </div>
  );
}

本质上我们在一个自定义hook中封装了一个状态布尔值和所有相关的事件处理。当我们需要一个状态布尔值时使用这个自定义hook,可以不用再定义实现控制这个状态布尔值相关的事件处理而是使用hook返回值中的函数。

作为总结,我们学习了如何使用React内置hook--useState创建一个自定义hook,这个自定义hook虽然并不复杂,但它向你展示了如何在自己的React项目中降低复杂度或冗余度。

这有很多自定义的React hook用于解决各种各样的问题。他们大多数可以在通过npm安装。但是,当我发现对于对我来说很好的hook时,我都会尝试简单的实现它。以下可能是你可能想要查看的内容: