在 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]);
我是 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]);