自定义hook

130 阅读2分钟

背景

当我们想在两个函数之间共享逻辑时,我们会把它提取到第三个函数中。而组件和Hook都是函数,所以也同样适用这种方式。

自定义Hook解决了以前在react组件中无法灵活共享逻辑的问题。

规则

自定义Hook是一个函数,其名称以use开头,函数内部可以调用其他的Hook

可以自由的决定它的参数是什么,以及它应该返回什么(如果需要的话)。换句话说,它就像一个正常的函数,但是它的名字应该始终以use开头,这样可以一眼看出其符合Hook的规则

Hook的规则:1.只在最顶层使用Hook(不要在循环、条件或嵌套函数中调用Hook)2.只在react函数中调用Hook(不要在普通的js函数中调用Hook);

示例

import { useState, useEffect } from 'react';

// `useFriendStatus` 的 Hook 目的是订阅某个好友的在线状态。friendID作为参数并返回这位好友的在线状态
function useFriendStatus(friendID) {  
  const [isOnline, setIsOnline] = useState(null);

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}

// FriendStatus 使用useFriendStatus
function FriendStatus(props) {
  const isOnline = useFriendStatus(props.friend.id);
  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

// FriendListItem 使用useFriendStatus
function FriendListItem(props) {
  const isOnline = useFriendStatus(props.friend.id);
  return (
    <li style={{ color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );
}

上面的示例只是将FriendStatus和FriendListItem两个函数之间一些共同的代码提取到单独的函数中。

自定义Hook的本质是一种函数代码逻辑的抽取

FAQ

自定义Hook必须以use开头吗?

必须如此。

这个约定非常重要。不遵循的话,由于无法判断某个函数是否包含对其内部Hook的调用,React将无法自动检查你的Hook是否违反了Hook的规则。

在两个组件中使用相同的Hook会共享state吗?

不会。

自定义Hook是一种重用状态逻辑的机制,所以每次使用自定义Hook时,其中的所有state和副作用都是完全隔离的。

自定义Hook如何获取独立的state?

每次调用Hook,它都会获取独立的state。

如上例中,直接调用了useFriendStatus,从react角度来看,我们的组件只是调用了useState和useEffect。我们在一个组件中多次调用useState和useEffect,它们是完全独立的。