我有一个数组,它作为 prop 提供给我的名为Child
的组件。现在,每次将新项目添加到数组中时,都应该针对 API 进行获取。
此数组使用useState
挂钩保存在名为Parent
的组件中。每当我想添加新项目时,我都必须重新创建数组,因为我不允许直接改变它。
我试图在以下代码片段中简化我的用例:
const Parent = () => {
const [array, setArray] = useState([]);
///...anywhere
setArray(a => [...a, newItem]);
return <Child array={array} />;
}
const Child = ({ array }) => {
useEffect(() => {
array.forEach(element => {
fetch(...);
});
}, [array]);
return ...;
}
现在,我的问题是:我如何才能从我的 API 中仅为新元素获取新数据,而不是再次为整个数组获取新数据?
我希望我能很好地描述我的问题。如果有任何不清楚或遗漏的地方,请告诉我。
不如在Parent
中获取 API 数据并将最终结果传递给Child
?这种重构将提供一些好处:
Parent
拥有 items 数组状态,并且知道何时何地添加新项。这使得增量fetch
变得非常容易。您还可以免费划分容器和表示组件。- 获取的 API 数据与项目数组相关。您可能希望以某种方式将它们一起使用(将 api 数据另存为状态、组合它们等)。这个星座将促进派生状态,这是一种更容易出错的模式。
类似于以下示例的内容已经可以做您想要的事情 - 通过onClick
(或其他方式)添加一个项目,获取其数据并将整个数组传递给 Child:
const Parent = () => {
const [array, setArray] = useState([]);
return (
<div onClick={addItem}>
<Child array={array} />;
</div>
);
function addItem(e) {
const item = createItemSomehow(...)
fetch(...).then(data => setArray([...array, { item, data }]));
}
};
更新:
如果你想保持你的结构和API不变,另一种方法是用usePrevious
钩子记住你的孩子中以前的数组属性,并寻找项目的变化。
const Child = ({ array }) => {
const prevArray = usePrevious(array);
useEffect(() => {
if (array !== prevArray && array.length) {
//fetch(...)
console.log(`fetch data for index ${array.length - 1}`);
}
});
return (...);
};
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}
代码沙盒
>例如,您可以保留以前获取的项目列表。
const Child = ({ values }) => {
const [fetched, setFetched] = useState([]);
useEffect(() => {
values.forEach(v => {
if (!fetched.includes(v)) {
setFetched(fetched => [...fetched, v]);
fetch(v);
}
});
}, [values, logged]);
https://codesandbox.io/s/affectionate-colden-sfpff