背景
当我们想在两个函数之间共享逻辑时,我们会把它提取到第三个函数中。而组件和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,它们是完全独立的。