javascript - 为什么我的自定义钩子被调用了这么多次?
问题描述
我正在尝试实现一个自定义钩子来为应用程序提供访客购物车。我的钩子环绕着useMutation
来自 Apollo 的钩子,它将购物车 ID 保存在 cookie 中,同时还提供了“重置”购物车的功能(基本上,在下订单时删除 cookie)。
代码时间!(为简洁起见省略了一些代码):
export const useGuestCart = () => {
let cartId;
const [createCart, { data, error, loading }] = useMutation(MUTATION_CREATE_CART);
console.log(`Hook!`);
if (!cartId || cartId.length === 0) {
createCart();
}
if (loading) {
console.log(`Still loading`);
}
if (data) {
console.log(`Got cart id ${data.createEmptyCart}`);
cartId = data.createEmptyCart;
}
const resetGuestCart = useCallback(() => {
// function body here
});
return [cartId, resetGuestCart];
};
在我的组件中,我只是使用let [cartId, resetCart] = useGuestCart();
.
当我运行单元测试(使用 Apollo 提供模拟突变)时,我看到钩子被调用了几次,输出看起来像这样:
console.log src/utils/hooks.js:53
Hook!
console.log src/utils/hooks.js:53
Hook!
console.log src/utils/hooks.js:59
Still loading
console.log src/utils/hooks.js:53
Hook!
console.log src/utils/hooks.js:62
Got cart id guest123
console.log src/utils/hooks.js:53
Hook!
console.log src/utils/hooks.js:53
Hook!
我只是开始使用钩子,所以我仍然无法掌握它们的工作方式。为什么这么多的钩子调用?
谢谢您的回复!
解决方案
将钩子视为直接在组件中具有相同的代码。这意味着每次组件渲染钩子都会运行。
例如,您定义:
let cartId;
// ...
if (!cartId || cartId.length === 0) {
createCart();
}
语句中的内容将在每次cartId
创建时在每次渲染时运行,并且此时没有分配任何值。而不是使用if
语句使用useEffect
:
export const useGuestCart = () => {
const [cartId, setCartId] = useState(0);
const [createCart, { data, error, loading }] = useMutation(
MUTATION_CREATE_CART
);
const resetGuestCart = () => {
// function body here
};
useEffect(() => {
if(!cartId || cartId.length === 0){
createCart();
}
}, [cartId]);
useEffect(() => {
// Here we need to consider the first render.
if (loading) {
console.log(`Started loading`);
} else {
console.log(`Finished loading`);
}
}, [loading]);
useEffect(() => {
// Here we need to consider the first render.
console.log(`Got cart id ${data.createEmptyCart}`);
setCartId(data.createEmptyCart);
}, [data]);
return [cartId, resetGuestCart];
};
还要注意,useCallback
如果接收函数的组件没有被记忆,使用并没有实际的好处。
推荐阅读
- visual-studio-code - 如何关闭 VSCode 中折叠代码的高亮显示?
- hibernate - Spring boot 3 问题:为什么不能用 Postman 和前端调用 API 调用 API 然后得到空数组?
- telegram-bot - Telegram Bot API:是否可以强制折叠移动设备上的默认键盘?
- java - 如何不允许用户在 ArrayList 的对象中输入重复条目
- angular - ionic4 中不显示幻灯片
- c# - System.Net.WebException:'无法连接到 /192.168.8.100:5001'
- matlab - 在对象的构造函数中传递对象
- electron - Chrome Dev-Tools Electron Uncaught TypeError:无法读取未定义的属性“长度”
- delphi - 首先创建 Delphi 表单,但不是主表单
- javascript - Javascript 未在使用 Selenium 的页面中执行