我使用钩子来重构可能在多个 React 组件中重复的获取逻辑。钩子本身的逻辑相对通用,映射如下。 它旨在返回响应、潜在错误,并在响应完成后将 isLoading 从 true 更新为 false。
const useFetch = (url, options = {}) => {
const [response, setResponse] = useState(null);
const [error, setError] = useState(null);
const [isLoading, setIsLoading] = useState(true);
console.log("again running useFetch")
useEffect(() => {
const fetchData = async () => {
try {
const res = await fetch(url, options);
const json = await res.json();
setResponse(json);
} catch (error) {
setError(error);
}
setIsLoading(false);
};
fetchData();
}, []);
return { response, error, isLoading };
};
现在这是我在 React 组件中使用它的方式,
function CardTable() {
const [cards, setCards] = useState([]);
const url = "https://deckofcardsapi.com/api/deck/new/draw/"
const data = useFetch(url)
console.log(data.response)
//{success: true, deck_id: 'mnpedlyiolj7', cards: Array(1), remaining: 51}
const addCard = async () => {
setCards(cards => [...cards, { ...data.response, id: uuid() }]);
};
它几乎可以工作了,我的理解是数据被分配了在每次渲染我们的 Cardtable 组件时调用我们的 useFetch 钩子函数的值。但是,每次我向 API 发出获取请求时,都会返回相同的响应数据。 我这里一定缺少一些东西,有什么想法吗? 非常感谢您的帮助。
我尝试了多种方法来重新迭代 API 调用,从 API 请求中抽取卡片,但结果仍然相同。这在response.data 的剩余属性中很明显,尽管有多个 API 请求,该属性仍保留并持续在 51。
useFetch
钩子的使用是导致您遇到问题的原因。由于钩子 useEffect
内的 (useEffect(() => {...}, []))
有一个空的依赖数组,因此钩子当前仅在安装 CardTable
组件时调用一次。因此,它在第一次渲染期间仅检索一次数据。
您应该更改
useFetch
挂钩以接受可以更改的参数,从而在必要时(例如,添加新卡时)重新获取。
const useFetch = (url, options = {}) => {
const [response, setResponse] = useState(null);
const [error, setError] = useState(null);
const [isLoading, setIsLoading] = useState(true);
const fetchData = async () => {
setIsLoading(true);
try {
const res = await fetch(url, options);
const json = await res.json();
setResponse(json);
} catch (error) {
setError(error);
}
setIsLoading(false);
};
return { response, error, isLoading, fetchData }; // Expose fetchData to trigger re-fetch
};
function CardTable() {
const [cards, setCards] = useState([]);
const url = "https://deckofcardsapi.com/api/deck/new/draw/";
const { response: responseData, fetchData } = useFetch(url); // Destructure the fetchData function
const addCard = async () => {
await fetchData(); // Trigger re-fetch when adding a new card
setCards((prevCards) => [...prevCards, { ...responseData, id: uuid() }]);
};
return (
<div>
<button onClick={addCard}>Add Card</button>
{/* Render your card components here */}
</div>
);
}
当您想要启动
re-fetch
时(在本例中,在添加卡片时),您可以从 fetchData
挂钩公开 useFetch
方法并显式使用它。这将导致一个新的 API 请求返回更新的数据,使您能够添加具有更新的响应的卡片。