我一直喜欢进入钩子和处理所有新的有趣的问题,提出了现实世界的问题:)这里有一个我遇到过几次,并想看看你如何“应该”解决它!
概述:我创建了一个自定义钩子来封装我的应用程序的一些业务逻辑,并存储我的一些状态。我使用组件内部的自定义钩子,并在加载时触发事件。
问题是:我的钩子的loadItems函数需要访问我的items才能获取最后一项的ID。将items添加到我的依赖项数组将导致无限循环。下面是一个(简化的)示例:
ItemList 简单组件
//
// Simple functional component
//
import React, { useEffect } from 'react'
import useItems from '/path/to/custom/hooks/useItems'
const ItemList = () => {
const { items, loadItems } = useItems()
// On load, use our custom hook to fire off an API call
// NOTE: This is where the problem lies. Since in our hook (below)
// we rely on `items` to set some params for our API, when items changes
// `loadItems` will also change, firing off this `useEffect` call again.. and again :)
useEffect(() => {
loadItems()
}, [loadItems])
return (
<ul>
{items.map(item => <li>{item.text}</li>)}
</ul>
)
}
export default ItemListuseItems 定制 Hook
//
// Simple custom hook
//
import { useState, useCallback } from 'react'
const useItems = () => {
const [items, setItems] = useState([])
// NOTE: Part two of where the problem comes into play. Since I'm using `items`
// to grab the last item's id, I need to supply that as a dependency to the `loadItems`
// call per linting (and React docs) instructions. But of course, I'm setting items in
// this... so every time this is run it will also update.
const loadItems = useCallback(() => {
// Grab our last item
const lastItem = items[items.length - 1]
// Supply that item's id to our API so we can paginate
const params = {
itemsAfter: lastItem ? lastItem.id : nil
}
// Now hit our API and update our items
return Api.fetchItems(params).then(response => setItems(response.data))
}, [items])
return { items, loadItems }
}
export default useItems代码中的注释应该指出问题所在,但我现在想出的唯一解决方案是为loadItems调用(ex )提供params,以使指针感到高兴。loadItems({ itemsAfter: ... })),因为数据已经在这个自定义钩子中,所以我真的希望不必在任何地方使用loadItems函数。
任何帮助都是非常感谢的!
麦克
发布于 2019-08-31 15:12:49
如果计划只运行一次效果,则忽略所有依赖项:
useEffect(() => {
loadItems();
}, []);发布于 2019-08-31 17:12:07
您可以尝试使用useReducer,将分派作为loadItems传递,因为它从不更改引用。还原器只关心操作是否为NONE,因为这是useEffect的清理功能用来清理的。
如果操作不是“无”,则状态将被设置为“项的最后一项”,这将触发useEffect使用您的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 };
};https://stackoverflow.com/questions/57739169
复制相似问题