如何自定义Hook?

自定义Hook大概是React Hooks最迷人的特性了。它让你能把组件里那些纠缠在一起的逻辑抽出来,变成一个独立、可复用的函数。这可不是什么高阶组件或者渲染属性那种绕弯子的复用,而是最直接的函数复用。

自定义Hook是什么?

简单说,它就是一个普通的JavaScript函数,但名字必须以use开头,而且内部可以调用其他Hook(比如useStateuseEffect)。React靠这个命名约定来检查你的Hook调用是否符合规则。

// 这不是一个组件,它不返回JSX。这是一个自定义Hook。
function useWindowWidth() {
  const [width, setWidth] = useState(window.innerWidth);
  useEffect(() => {
    const handleResize = () => setWidth(window.innerWidth);
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);
  return width;
}

这个useWindowWidth Hook封装了监听窗口大小和清理订阅的逻辑。任何组件需要用到当前窗口宽度时,直接调用它就行,不用再把一样的代码写一遍。

怎么从组件里抽逻辑?

想象你有个组件,里面有一堆处理表单状态的useState,还有验证逻辑。你发现另一个组件也需要差不多的东西。这时候就可以动手了:

  1. 新建一个useForm.js文件。
  2. 把组件里所有和表单相关的状态、useEffect、处理函数都剪贴过来。
  3. 把它们组织成一个函数,接收必要的初始参数(比如初始值),然后返回其他组件需要的东西(比如表单值、错误信息、提交函数)。
function useForm(initialValues) {
  const [values, setValues] = useState(initialValues);
  const handleChange = (e) => {
    setValues({ ...values, [e.target.name]: e.target.value });
  };
  const resetForm = () => setValues(initialValues);
  return { values, handleChange, resetForm };
}

在组件里用起来非常清爽:

function MyForm() {
  const { values, handleChange, resetForm } = useForm({ name: '', email: '' });
  return (
    <form>
      <input name="name" value={values.name} onChange={handleChange} />
      <input name="email" value={values.email} onChange={handleChange} />
    </form>
  );
}

注意,每个组件调用同一个自定义Hook,得到的都是完全独立的状态和副作用。它们不会共享数据。你只是在复用逻辑,而不是状态本身。

什么时候该用?

别为了抽象而抽象。当你在两个以上的组件里发现了一模一样的Hook调用模式,或者某个组件内部的Hook逻辑已经复杂到影响阅读了,那就是抽成自定义Hook的好时机。常见的例子有:数据获取、订阅监听、动画逻辑、复杂的本地存储操作。

这就像是你给自己写了一套实用的工具函数库,只不过这些工具专门用来封装React的副作用和状态逻辑。用好了,代码会干净很多。

© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容