Javascript React自定义钩子问题-无限依赖循环
我一直喜欢陷入困境,处理现实世界中出现的所有新的有趣问题:)这里有一个我遇到过几次的问题,我想看看你“应该”如何解决它 概述:我创建了一个自定义钩子来封装我的应用程序的一些业务逻辑,并存储我的一些状态。我在组件中使用自定义挂钩,并在加载时触发事件 问题是:my hook的Javascript React自定义钩子问题-无限依赖循环,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,我一直喜欢陷入困境,处理现实世界中出现的所有新的有趣问题:)这里有一个我遇到过几次的问题,我想看看你“应该”如何解决它 概述:我创建了一个自定义钩子来封装我的应用程序的一些业务逻辑,并存储我的一些状态。我在组件中使用自定义挂钩,并在加载时触发事件 问题是:my hook的loadItems功能需要访问myitems以获取最后一个项目的ID。将项添加到我的依赖项数组中会导致无限循环。下面是一个(简化的)示例: 简单项目列表组件 // //简单功能部件 // 从“React”导入React,{use
loadItems
功能需要访问myitems
以获取最后一个项目的ID。将项添加到我的依赖项数组中会导致无限循环。下面是一个(简化的)示例:
简单项目列表
组件
//
//简单功能部件
//
从“React”导入React,{useffect}
将useItems从“/path/to/custom/hooks/useItems”导入
常量项列表=()=>{
常量{items,loadItems}=useItems()
//在加载时,使用我们的自定义钩子触发API调用
//注意:这就是问题所在。因为在我们的钩子中(下面)
//当项目发生变化时,我们依靠'items'为API设置一些参数
//'loadItems'也将更改,再次触发此'useEffect'调用..并再次:)
useffect(()=>{
loadItems()
},[loadItems])
返回(
{items.map(item=>- {item.text}
)}
)
}
导出默认项目列表
自定义useItems
Hook
//
//简单定制挂钩
//
从“react”导入{useState,useCallback}
常量useItems=()=>{
const[items,setItems]=useState([])
//注意:问题的第二部分。因为我使用的是'items'`
//要获取最后一个项的id,我需要将其作为` loadItems'的依赖项提供`
//按linting(和React docs)指令调用。当然,我正在设置项目
//这…所以每次运行它时,它也会更新。
const loadItems=useCallback(()=>{
//抓住我们的最后一件物品
const lastItem=items[items.length-1]
//将该项的id提供给我们的API,以便我们可以分页
常量参数={
itemsAfter:lastItem?lastItem.id:nil
}
//现在点击我们的API并更新我们的项目
返回Api.fetchItems(params).then(response=>setItems(response.data))
},[项目])
返回{items,loadItems}
}
导出默认useItems
代码中的注释应该指出问题所在,但我现在能想到的唯一让linters满意的解决方案是为loadItems
调用提供参数(例如loadItems({itemsAfter:…})
),因为数据已经在这个自定义挂钩中,我真的希望不用在我使用loadItems
功能的任何地方都做
非常感谢您的帮助
Mike如果计划只运行一次效果,请忽略所有依赖项:
useEffect(() => {
loadItems();
}, []);
您可以尝试使用useReducer,将分派作为loadItems传递,因为它从不更改引用。reducer只关心操作是否为NONE,因为useffect的cleanup函数就是这样清理的
如果action不是NONE,那么state将被设置为项的最后一项,这将触发useffect使用您的api进行获取,当解决此问题时,它将使用setItems来设置项
const NONE = {};
const useItems = () => {
const [items, setItems] = useState([]);
const [lastItem, dispatch] = useReducer(
(state, action) => {
return action === NONE
? NONE
: items[items.length - 1];
},
NONE
);
useEffect(() => {
//initial useEffect or after cleanup, do nothing
if (lastItem === NONE) {
return;
}
const params = {
itemsAfter: lastItem ? lastItem.id : Nil,
};
// Now hit our API and update our items
Api.fetchItems(params).then(response =>
setItems(response)
);
return () => dispatch(NONE); //clean up
}, [lastItem]);
//return dispatch as load items, it'll set lastItem and trigger
// the useEffect
return { items, loadItems: dispatch };
};
在useEffect中,只需将“[loadItems]”替换为“[]”,您只需要在加载时获取,对吗?所以就一次,不再依赖useEffect。你想继续加载项目直到没有更多的项目吗?我不明白项目是如何被传递到钩子中的?钩子从哪里获得项目
?@mattOestreich加载项目
从服务器加载项目?@jonaswillms我误读了问题和操作代码。我以为OP想向钩子传递一些东西,让钩子获取数据,然后返回数据。相反,钩子所做的只是公开一个“fetch”函数。。。具体来说,Dan说:“但是,删除您使用的依赖项(或盲目指定[])通常是错误的修复方法。”。。有一件事我一直不明白,为什么这么多人建议这样做,而React的一位作者建议不要提供空数组列表。(这也会导致林特错误)。。你能详细解释一下为什么会这样吗?@mattOestreich我不是瞎子。请提出一个更好的解决方案:)这些方案是在钩子击中现实之前写的。@马特:好吧,在这种情况下,它不会咬到你,而且提供的所有解决方案在这里都不起作用。谢谢你抽出时间!我理解OPs的问题并不是和丹的例子一一对应——我完全明白你的意思。我很感激!