更新的数组需要使用反应钩子设置但会创建无限循环

Updated array needs to be set with react hooks but creates infinite loop

在我下面的代码中,我正在从 Firebase Firestore 中获取图像。 url 正确返回并被推送到 images state

现在的问题是添加了相同的 url(因为 useEffect 运行得快了还是早了?)

所以在第二个 useEffect 中,我使用 ...new Set 更新图像数组并轻松删除重复项,但问题是 setImages() 也被调用,这是不允许的因为这会造成无限循环。

所以我的问题是,有人可以告诉我在哪里设置 updated array uniqimages state 的正确方法吗?

提前致谢!

const [evtsFiltered, setEvtsFiltered] = useState([])
const [images, setImages] = useState([])

 useEffect(() => {
    evtsFiltered?.map((item) => {
      storageRef
        .child(item)
        .getDownloadURL()
        .then((url) => {
          setImages((images) => [...images, url]) // url returns a plain string such as 'http://image-1.png'
        })
    })
  }, [evtsFiltered])

  useEffect(() => {
    let uniq = [...new Set(images)] // Duplicates are removed
    setImages(uniq) // Infinite loop problem
  }, [images])

这是因为您尝试更新收听更新的状态。一种解决方案是创建另一个包含独特图像的状态。

const [evtsFiltered, setEvtsFiltered] = useState([])
const [images, setImages] = useState([])
const [uniqueImages, setUniqueImages] = useState([])

 useEffect(() => {
    evtsFiltered?.map((item) => {
      storageRef
        .child(item)
        .getDownloadURL()
        .then((url) => {
          setImages((images) => [...images, url]) // url returns a plain string such as 'http://image-1.png'
        })
    })
  }, [evtsFiltered])

  useEffect(() => {
    let uniq = [...new Set(images)] // Duplicates are removed
    setUniqueImages(uniq) // Infinite loop problem
  }, [images])

另一种设置独特图像的方法。

.then((url) => {
          setImages((images) => [ ...new Set([ ...images, url])]) // url returns a plain string such as 'http://image-1.png'
})

您的代码需要改进:

  • 您不需要将 optional-chainingevtsFiltered 一起使用,因为它的初始值是一个空数组。

  • 如果您只是要遍历数组,
  • map() 不是正确的方法。您可以使用 map() 方法和 Promise.all() 来获取图像 URL。

  • 由于 useEffect 钩子,无法使用相同的 URL。您在 firebase 存储中有重复的 URL,或者您没有正确更新状态。

  • 如果您在第一个 useEffect 挂钩中正确更新 images 状态,则不需要第二个 useEffect 挂钩。

尝试使用 Promise.all()map() 方法更新状态,如下所示:

useEffect(() => {
    const arr = evtsFiltered.map((item) => {
       return storageRef.child(item).getDownloadURL();          
    });

   Promise.all(arr)
     .then(urls => {
        setImages(urls);
     })
     .catch(err => /* handle error */ );
    
}, [evtsFiltered]);

使用 map() 方法创建一个承诺数组,然后您可以使用 Promise.all() 方法解析这些承诺。另外,删除第二个 useEffect 挂钩。