reactjs 代码中的循环存在问题,不断重新呈现

wgmfuz8q  于 2022-12-18  发布在  React
关注(0)|答案(1)|浏览(168)

React警告我必须添加一个“图像”依赖项,但当我这样做时,它会循环并关闭所有依赖项。我可以对“图像”做些什么,使它们不会改变每个渲染吗?

const App = () => {
  const [imageName, setImageName] = useState('');
  const [images, setImages] = useState([]);
  const [page, setPage] = useState(1);
  const [error, setError] = useState(null);
  const [status, setStatus] = useState(Status.IDLE);
  const [isShowBtn, setIsShowBtn] = useState(false);

  useEffect(() => {
    if (!imageName) {
      setStatus(Status.IDLE);
      setImages([]);
      setIsShowBtn(false);
    }

    if (imageName !== '' || page > 1) {
      setStatus(Status.PENDING);

      fetchImages(imageName, page)
        .then(({ data }) => {
          const imagesValue = images.concat(data.hits);

          setImages(
            imagesValue.map(({ id, webformatURL, largeImageURL }) => ({
              id,
              webformatURL,
              largeImageURL,
            }))
          );

          setIsShowBtn(data.totalHits > imagesValue.length);
          setStatus(Status.RESOLVED);
        })
        .catch(error => {
          console.log(error);
          setError(error);
          setStatus(Status.REJECTED);
        });
    }
  }, [imageName, page]);

const handleSearchSubmit = imageName => {
    setImageName(imageName);
    setPage(1);
  };

  const handleLoadMoreClick = () => {
    setPage(page => page + 1);
    setIsShowBtn(false);
  };

  return (
    <div className="app">
      <Searchbar onSubmit={handleSearchSubmit} />
      {status === Status.REJECTED && <p>Error: {error.message}</p>}

      <ImageGallery imageName={imageName} images={images} status={status} />
      {status === Status.PENDING && <Loader />}
      {isShowBtn && <Button onClick={handleLoadMoreClick} />}
    </div>
  );
};

我尝试将“imagesValue”移出,但它受到提取的严格影响。此外,我将提取的整个函数移到useEffect并在那里调用它,但没有起作用。此外,尝试了useMemo和useCallback,但也没有修复。

xdnvmnnf

xdnvmnnf1#

嗯......这里的经验法则是,无论何时useEffect实际上改变了“图像”和“状态”,你都应该将它们作为useEffect中的依赖项。为了清楚起见,我将“状态.挂起”切换为“挂起”,将“状态.空闲”切换为“空闲”,等等。也许这样做有潜在的原因......只是看起来多余。
因此,我们需要告诉React,如果fetchImages fn已经被调用并且承诺已经实现,那么它应该跳过fetchImages。

const [status, setStatus] = useState("IDLE"); //changed here

useEffect(() => {
    if (!imageName) {
        setStatus("IDLE");
        setImages([]);
        setIsShowBtn(false);
    }

    if (imageName !== '' || page > 1) {
        setStatus("PENDING");
    }
    
    if (status === "PENDING") { //notice what we did here to avoid multiple calls
        fetchImages(imageName, page)
            .then(({ data }) => {
                 // seems like you are mapping something to itself,
                 // so I removed the mapping function here.
                 // feel free to keep it in case you have something in mind to do it
                 setImages(images => [...images, data.hits]) 
                 // those functions from useState, so called reducers,
                 // can accept a callback fn with the current state and instead of using concat, I used the spread operator, but you should be the same results afterall. 
                 setIsShowBtn(data.totalHits > imagesValue.length);
                 setStatus("RESOLVED");
            }).catch(error => {
                console.log(error);
                setError(error);
                setStatus("REJECTED");
            });
         }}}, [images, setImages, status, imageName, page]);

这里潜在的想法是如果

imageName !== '' OR page > 1

我们将状态设置为PENDING。2 useEffect将在那里结束他的回合。3然后,因为状态在你的依赖项数组中,useEffect将再次被调用,这次status ===“PENDING”将为真,我们将获取图像。
当履行承诺时,fetchImages将状态更新为“RESOLVED”或“REJECTED”,因此fetchImages不会再次触发。
如果您有时间,请阅读https://overreacted.io/a-complete-guide-to-useeffect/下面的文章
这个对我理解useEffect行为帮助很大。干杯。

相关问题