在 useEffect 中使用 setState 进行 API 调用后如何执行函数?

How to execute a function AFTER an API-Call was made with setState within useEffect?

我是 React 新手(学习 30 小时),有一些基础 Javascript 背景。现在我正在学习一门课程,并试图“离开”这条路。但是我很好奇我的预期目标是如何实现的。

有一个 Memegenerator 在渲染开始时从 API 获取所有模因图像。这是通过 useEffect-Hook 解决的。现在我希望函数 getMemeImage() 在 API 开始时是 运行 一次,在调用 API-Call 并更新状态之后(这不是课程的一部分,但我想尝试一下)无论如何)。

但它给我一个错误:“无法对未安装的组件执行 React 状态更新”

虽然我的研究发现 didMount(我不明白)之类的东西并不是主要使用挂钩的“现代”反应方式,您可以简单地使用第二个 useEffect。但不幸的是,这对我不起作用。

我该如何解决这个问题?是否有适合初学者的“简单”方法或高级方法?我想也许可以使用超时功能,但似乎编码很糟糕。

import React from "react"

export default function Meme() {
    const [meme, setMeme] = React.useState({
        topText: "",
        bottomText: "",
        randomImage: "" 
    })
    const [allMemes, setAllMemes] = React.useState([])

React.useEffect(() => {   /* first useEffect */
    fetch("https://api.imgflip.com/get_memes")
        .then(res => res.json())
        .then(data => setAllMemes(data.data.memes))
}, [])




React.useEffect(() => {   /* This should run after the setAllMemes in the first useEffect was complete */

    getMemeImage()
}, [allMemes])



function getMemeImage() {
    const randomNumber = Math.floor(Math.random() * allMemes.length)
    const url = allMemes[randomNumber].url
    setMeme(prevMeme => ({
        ...prevMeme,
        randomImage: url
    }))
    
}

function handleChange(event) {
    const {name, value} = event.target
    setMeme(prevMeme => ({
        ...prevMeme,
        [name]: value
    }))
}

return (
    <main>
        <div className="form">
            <input 
                type="text"
                placeholder="Top text"
                className="form--input"
                name="topText"
                value={meme.topText}
                onChange={handleChange}
            />
            <input 
                type="text"
                placeholder="Bottom text"
                className="form--input"
                name="bottomText"
                value={meme.bottomText}
                onChange={handleChange}
            />
            <button 
                className="form--button"
                onClick={getMemeImage}
            >
                Get a new meme image 
            </button>
        </div>
        <div className="meme">
            <img src={meme.randomImage} className="meme--image" />
            <h2 className="meme--text top">{meme.topText}</h2>
            <h2 className="meme--text bottom">{meme.bottomText}</h2>
        </div>
    </main>
)
}

首先,“无法对未安装的组件执行 React 状态更新”是警告,不是错误。

为了仅在第一个 useEffect 挂钩执行后调用 'getMemeImage',您可以检查在第一个 useEffect 执行后更改的二进制标志的值以及响应已收到异步函数。

import React from "react";

export default function Meme() {
  const [meme, setMeme] = React.useState({
    topText: "",
    bottomText: "",
    randomImage: ""
  });
  const [allMemes, setAllMemes] = React.useState([]);
  const isInitialRender = React.useRef(true);

  React.useEffect(() => {
    fetch("https://api.imgflip.com/get_memes")
      .then((res) => res.json())
      .then((data) => {

        isInitialRender.current = false;
        setAllMemes(data.data.memes);
      });
  }, []);

  React.useEffect(() => {
 /* Check if it is called before the first useEffect data fetching was completed */
    if (!isInitialRender.current) getMemeImage();
  }, [allMemes]);

  function getMemeImage() {
    const randomNumber = Math.floor(Math.random() * allMemes.length);
    const url = allMemes[randomNumber].url;
    setMeme((prevMeme) => ({
      ...prevMeme,
      randomImage: url
    }));
  }
}

使用 useRef 挂钩在渲染之间保留它引用的值。

您可以将控件添加到您的第二个useEffect,它会解决您的问题。这是工作示例 https://codesandbox.io/s/heuristic-matan-3kdbmv

React.useEffect(() => {
    if (allMemes.length > 0) {
      getMemeImage();
    }
  }, [allMemes]);