英文:
How to stop infinite loop in setState
问题
我遇到的问题是,调用setState()
在我的React组件中引发了无限循环。具体来说,我正在调用API以获取一张猫的图片,并将图像URL推送到一个名为arr
的数组中。然后,我尝试通过调用setImages(arr)
来更新组件的状态,并将图像变量记录到控制台。
然而,调用setImages()
会触发组件的重新渲染,这会导致for循环再次执行,导致另一个API调用,另一个推送到arr
,并再次调用setImages()
,从而导致无限循环。
我期望状态变量images
具有3个图像URL,因为for循环被迭代三次。
英文:
const cats = [
1, 2, 3
];
let arr = [];
const [images, setImages] = useState([]);
const generateCat = () => {
fetch(
"https://api.thecatapi.com/v1/images/search?size=small&limit=1&mime_types=jpg,png&width=200&height=200"
)
.then(response=>{return response.json()})
.then(data=>{
let finalResult = data[0]['url']
arr.push(finalResult)
console.log(arr)
return finalResult
})
};
for(let i=0;i<cats.length;i++){
generateCat()
setImages(arr)
console.log('Images: '+images)
}
My problem is that I'm encountering an issue with setState() causing an infinite loop in my React component. Specifically, I'm making an API call to retrieve an image of a cat and pushing the image URL to an array called arr. Then, I'm attempting to update the state of the component by calling setImages(arr) and logging the images variable to the console.
However, calling setImages() triggers a re-render of the component, which causes the for loop to execute again, leading to another API call, another push to arr, and another call to setImages(), resulting in an infinite loop.
I am expecting the state variable images
to have 3 img urls since the for loop is being iterated thrice.
答案1
得分: 4
你需要将你的fetch操作包裹在useEffect
中:
import { useState, useEffect } from "react";
const API_URL =
"https://api.thecatapi.com/v1/images/search?size=small&limit=1&mime_types=jpg,png&width=200&height=200";
async function getCat() {
const response = await fetch(API_URL);
const data = await response.json();
return data[0].url;
}
export default function App() {
const [pics, setPics] = useState([]);
useEffect(() => {
Promise.all(Array.from({ length: 3 }, getCat)).then(setPics);
}, []);
if (!pics.length) {
return "Loading...";
}
return (
<div className="app">
{pics.map((url) => (
<img key={url} src={url} alt="A kitten" />
))}
</div>
);
}
.app {
display: flex;
flex-direction: column;
}
英文:
You need to wrap your fetch operations in a useEffect
:
import { useState, useEffect } from "react";
const API_URL =
"https://api.thecatapi.com/v1/images/search?size=small&limit=1&mime_types=jpg,png&width=200&height=200";
async function getCat() {
const response = await fetch(API_URL);
const data = await response.json();
return data[0].url;
}
export default function App() {
const [pics, setPics] = useState([]);
useEffect(() => {
Promise.all(Array.from({ length: 3 }, getCat)).then(setPics);
}, []);
if (!pics.length) {
return "Loading...";
}
return (
<div className="app">
{pics.map((url) => (
<img key={url} src={url} alt="A kitten" />
))}
</div>
);
}
<!-- begin snippet: js hide: true console: true babel: false -->
<!-- language: lang-css -->
.app {
display: flex;
flex-direction: column;
}
<!-- language: lang-html -->
<script type="text/babel">
const { useState, useEffect } = React;
const API_URL =
"https://api.thecatapi.com/v1/images/search?size=small&limit=1&mime_types=jpg,png&width=200&height=200";
async function getCat() {
const response = await fetch(API_URL);
const data = await response.json();
return data[0].url;
}
function App() {
const [pics, setPics] = useState([]);
useEffect(() => {
Promise.all(Array.from({ length: 3 }, getCat)).then(setPics);
}, []);
if (!pics.length) {
return "Loading...";
}
return (
<div className="app">
{pics.map((url) => (
<img key={url} src={url} alt="A kitten" />
))}
</div>
);
}
ReactDOM.createRoot(document.querySelector("#root")).render(<App />);
</script>
<div id="root"></div>
<script src="https://unpkg.com/@babel/standalone@7/babel.min.js"></script>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<!-- end snippet -->
答案2
得分: 1
以下是代码的翻译部分:
const cats = [
1, 2, 3
];
const ExampleComponent = () => {
const [images, setImages] = useState([]);
// this code will only be called on initial load of the component
useEffect(() => {
const generateCat = () => {
fetch(
"https://api.thecatapi.com/v1/images/search?size=small&limit=1&mime_types=jpg,png&width=200&height=200"
)
.then(response => {return response.json()})
.then(data => {
let finalResult = data[0]['url']
setImages(prev => [...prev, finalResult])
})
};
for(let i = 0; i < cats.length; i++){
generateCat()
}
},[])
console.log('Images: ' + images)
return <div>The Rest of your component here</div>
}
英文:
I am assuming this code is inside of a react component so here is modified example that should prevent the pre-rendering:
const cats = [
1, 2, 3
];
const ExampleComponent = () => {
const [images, setImages] = useState([]);
// this code will only be called on initial load of the component
useEffect(() => {
const generateCat = () => {
fetch(
"https://api.thecatapi.com/v1/images/search?size=small&limit=1&mime_types=jpg,png&width=200&height=200"
)
.then(response=>{return response.json()})
.then(data=>{
let finalResult = data[0]['url']
setImages(prev => [...prev, finalResult])
})
};
for(let i=0;i<cats.length;i++){
generateCat()
}
},[])
console.log('Images: '+images)
return <div>The Rest of your component here</div>
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论