如何在 useEffect 中包含缺失的依赖项但防止函数的无限循环执行?
How to include missing dependency in useEffect but prevent infinite loop execution of function?
我正在开发一个相当简单的 React 功能组件,它从 URL 获取值 (tag
) 并从 firestore correspondig 请求文档到 tag
(inlc. firestore 查询光标与 加载更多 按钮一起使用)。整个组件由一个函数声明和一个调用该函数的useEffect
钩子组成。
基本上该组件工作正常。但是有一个问题:ESLint 告诉我我需要将该函数作为 useEffect
挂钩的依赖项包括在内:
React Hook useEffect has a missing dependency: 'getNextImages'. Either include it or remove the dependency array react-hooks/exhaustive-deps
如果我将函数包含到依赖项数组中或完全删除依赖项数组,当然,组件最终会进入无限渲染循环。
我可以使用 // eslint-disable-next-line
跳过 ESLint 的依赖数组,但感觉不对。
我试图通过将 getNextImages
包装到 useCallback
钩子中来解决这个问题,但没有成功。但也许我做错了。我以前从来没有用过 useCallback
…
有没有人可以告诉我一些提示?
您会在 https://codesandbox.io/s/great-liskov-d12l3?file=/src/App.js 找到我的组件。或者在这里:
import { useEffect, useState } from "react";
import firebase from "firebase";
import { useParams } from "react-router-dom";
const GalleryTag = () => {
//const [isPending, setIsPending] = useState(true);
//const [galleryData, setGalleryData] = useState([]);
//const [lastDocument, setLastDocument] = useState(null);
//const [isLastPage, setIsLastPage] = useState(false);
const numImagesPerPage = 20;
const { tag } = useParams();
const getNextImages = (lastDocument) => {
let query;
!lastDocument
? (query = firebase
.firestore()
.collectionGroup("images")
.where("showinapp", "==", true)
.where("tags", "array-contains", tag)
.orderBy("createdate", "desc")
.limit(numImagesPerPage)
.get())
: (query = firebase
.firestore()
.collectionGroup("images")
.where("showinapp", "==", true)
.where("tags", "array-contains", tag)
.orderBy("createdate", "desc")
.startAfter(lastDocument)
.limit(numImagesPerPage)
.get());
query
.then((data) => {
setIsLastPage(data.empty);
setIsPending(false);
setLastDocument(data.docs[data.docs.length - 1]);
setGalleryData((galleryData) => galleryData.concat(data.docs));
})
.catch((error) => console.error(error));
};
useEffect(() => {
getNextImages();
}, [tag]);
return <>JSX goes here then</>;
};
export default GalleryTag;
尝试将您的 function
移至 useEffect
回调:
useEffect(() => {
const getNextImages = (lastDocument) => {
let query;
!lastDocument
? (query = firebase
.firestore()
.collectionGroup("images")
.where("showinapp", "==", true)
.where("tags", "array-contains", tag)
.orderBy("createdate", "desc")
.limit(numImagesPerPage)
.get())
: (query = firebase
.firestore()
.collectionGroup("images")
.where("showinapp", "==", true)
.where("tags", "array-contains", tag)
.orderBy("createdate", "desc")
.startAfter(lastDocument)
.limit(numImagesPerPage)
.get());
query
.then((data) => {
setIsLastPage(data.empty);
setIsPending(false);
setLastDocument(data.docs[data.docs.length - 1]);
setGalleryData((galleryData) => galleryData.concat(data.docs));
})
.catch((error) => console.error(error));
};
getNextImages();
}, [tag]);
现在我得到了解决方案。它被称为 useCallback
钩子。
在玩完 useCallback
及其依赖数组后,我只需要将函数 getNextImages()
包装在这个钩子中并设置它的依赖项(在本例中为 tag
)。
然后我可以将函数 getNextImages
设置为下面 useEffect
挂钩的依赖项……瞧:ESLint 现在很开心(当然还有构建过程)。重新渲染和无限执行循环也被阻止。
这是工作代码:
const getNextImages = useCallback(
(lastDocument) => {
let query;
!lastDocument
? (query = firebase
.firestore()
.collectionGroup("images")
.where("showinapp", "==", true)
.where("tags", "array-contains", tag)
.orderBy("createdate", "desc")
.limit(numImagesPerPage)
.get())
: (query = firebase
.firestore()
.collectionGroup("images")
.where("showinapp", "==", true)
.where("tags", "array-contains", tag)
.orderBy("createdate", "desc")
.startAfter(lastDocument)
.limit(numImagesPerPage)
.get());
query
.then((data) => {
setIsLastPage(data.empty);
setIsPending(false);
setLastDocument(data.docs[data.docs.length - 1]);
setGalleryData((galleryData) => galleryData.concat(data.docs));
})
.catch((error) => console.error(error));
},
[tag]
);
useEffect(() => {
getNextImages();
setPageTitle(`Bilder zum Tag »${tag}«`);
sendAnalytics("page_view", {
page_title: `Bilder zum Tag »${tag}«`,
});
}, [getNextImages, tag]);
我正在开发一个相当简单的 React 功能组件,它从 URL 获取值 (tag
) 并从 firestore correspondig 请求文档到 tag
(inlc. firestore 查询光标与 加载更多 按钮一起使用)。整个组件由一个函数声明和一个调用该函数的useEffect
钩子组成。
基本上该组件工作正常。但是有一个问题:ESLint 告诉我我需要将该函数作为 useEffect
挂钩的依赖项包括在内:
React Hook useEffect has a missing dependency: 'getNextImages'. Either include it or remove the dependency array react-hooks/exhaustive-deps
如果我将函数包含到依赖项数组中或完全删除依赖项数组,当然,组件最终会进入无限渲染循环。
我可以使用 // eslint-disable-next-line
跳过 ESLint 的依赖数组,但感觉不对。
我试图通过将 getNextImages
包装到 useCallback
钩子中来解决这个问题,但没有成功。但也许我做错了。我以前从来没有用过 useCallback
…
有没有人可以告诉我一些提示?
您会在 https://codesandbox.io/s/great-liskov-d12l3?file=/src/App.js 找到我的组件。或者在这里:
import { useEffect, useState } from "react";
import firebase from "firebase";
import { useParams } from "react-router-dom";
const GalleryTag = () => {
//const [isPending, setIsPending] = useState(true);
//const [galleryData, setGalleryData] = useState([]);
//const [lastDocument, setLastDocument] = useState(null);
//const [isLastPage, setIsLastPage] = useState(false);
const numImagesPerPage = 20;
const { tag } = useParams();
const getNextImages = (lastDocument) => {
let query;
!lastDocument
? (query = firebase
.firestore()
.collectionGroup("images")
.where("showinapp", "==", true)
.where("tags", "array-contains", tag)
.orderBy("createdate", "desc")
.limit(numImagesPerPage)
.get())
: (query = firebase
.firestore()
.collectionGroup("images")
.where("showinapp", "==", true)
.where("tags", "array-contains", tag)
.orderBy("createdate", "desc")
.startAfter(lastDocument)
.limit(numImagesPerPage)
.get());
query
.then((data) => {
setIsLastPage(data.empty);
setIsPending(false);
setLastDocument(data.docs[data.docs.length - 1]);
setGalleryData((galleryData) => galleryData.concat(data.docs));
})
.catch((error) => console.error(error));
};
useEffect(() => {
getNextImages();
}, [tag]);
return <>JSX goes here then</>;
};
export default GalleryTag;
尝试将您的 function
移至 useEffect
回调:
useEffect(() => {
const getNextImages = (lastDocument) => {
let query;
!lastDocument
? (query = firebase
.firestore()
.collectionGroup("images")
.where("showinapp", "==", true)
.where("tags", "array-contains", tag)
.orderBy("createdate", "desc")
.limit(numImagesPerPage)
.get())
: (query = firebase
.firestore()
.collectionGroup("images")
.where("showinapp", "==", true)
.where("tags", "array-contains", tag)
.orderBy("createdate", "desc")
.startAfter(lastDocument)
.limit(numImagesPerPage)
.get());
query
.then((data) => {
setIsLastPage(data.empty);
setIsPending(false);
setLastDocument(data.docs[data.docs.length - 1]);
setGalleryData((galleryData) => galleryData.concat(data.docs));
})
.catch((error) => console.error(error));
};
getNextImages();
}, [tag]);
现在我得到了解决方案。它被称为 useCallback
钩子。
在玩完 useCallback
及其依赖数组后,我只需要将函数 getNextImages()
包装在这个钩子中并设置它的依赖项(在本例中为 tag
)。
然后我可以将函数 getNextImages
设置为下面 useEffect
挂钩的依赖项……瞧:ESLint 现在很开心(当然还有构建过程)。重新渲染和无限执行循环也被阻止。
这是工作代码:
const getNextImages = useCallback(
(lastDocument) => {
let query;
!lastDocument
? (query = firebase
.firestore()
.collectionGroup("images")
.where("showinapp", "==", true)
.where("tags", "array-contains", tag)
.orderBy("createdate", "desc")
.limit(numImagesPerPage)
.get())
: (query = firebase
.firestore()
.collectionGroup("images")
.where("showinapp", "==", true)
.where("tags", "array-contains", tag)
.orderBy("createdate", "desc")
.startAfter(lastDocument)
.limit(numImagesPerPage)
.get());
query
.then((data) => {
setIsLastPage(data.empty);
setIsPending(false);
setLastDocument(data.docs[data.docs.length - 1]);
setGalleryData((galleryData) => galleryData.concat(data.docs));
})
.catch((error) => console.error(error));
},
[tag]
);
useEffect(() => {
getNextImages();
setPageTitle(`Bilder zum Tag »${tag}«`);
sendAnalytics("page_view", {
page_title: `Bilder zum Tag »${tag}«`,
});
}, [getNextImages, tag]);