复用 hook 是通过传递 state 变量:
import { useState, useEffect } from 'react';
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;
}
function FriendStatus(props) {
const isOnline = useFriendStatus(props.friend.id);
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
重点在于:
- 即使
isOnline
是在useFriendStatus
中被调用的,它实际上是存储在FriendStatus
函数的实例中的。这意味着它在FriendStatus
的实例中的值,跟另外一个使用useFriendStatus
的函数式组件(如FriendListItem
)之间是不共享 - 本质上,
FriendStatus
调用useFriendStatus
的过程,可以当作把后者的实现拷贝过来 useFriendStatus
的参数可以任意定,它需要什么就传什么;对于返回值,如果返回的内容有多个,可以用 object 包裹一下
同时,一个 hook 它的参数可以是另外一个 hook 的返回值,比如下面 useFriendStatus
使用的是 useState
的返回值。这意味着你可以把 state 中的变量作为参数传给 hook:
function ChatRecipientPicker() {
const [recipientID, setRecipientID] = useState(1);
const isRecipientOnline = useFriendStatus(recipientID);
return (
<>
<Circle color={isRecipientOnline ? 'green' : 'red'} />
<select
value={recipientID}
onChange={e => setRecipientID(Number(e.target.value))}
>
{friendList.map(friend => (
<option key={friend.id} value={friend.id}>
{friend.name}
</option>
))}
</select>
</>
);
}
我做了个视频讲解: