javascript - Incorrect dependency behavior in hook useEffect?
问题描述
I've got a problem with infinite loop inside useEffect
. I want to make new request only when id dependency changes. When I not pass data I've got a problem with setData
. My data state is not updated. When I pass data to the dependency I've got an infinite loop. How to fix it and why?
import React, {useEffect, useState} from 'react';
import LeftArrow from './LeftArrow';
import RightArrow from './RightArrow';
import SlideItem from './SlideItem';
const Slide = () => {
const [id, setId] = useState(0);
const [data, setData] = useState({currencies:[], isFetching:false});
const images = [
"https://images.pexels.com/photos/672532/pexels-photo-672532.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
"https://images.pexels.com/photos/773471/pexels-photo-773471.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
"https://images.pexels.com/photos/64271/queen-of-liberty-statue-of-liberty-new-york-liberty-statue-64271.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940"
];
useEffect(()=> {
const getCurrentCurrency = async () => {
try{
setData({currencies: data.currencies, isFetching: true});
console.log("data", data.isFetching);
const currencyArr = [];
const response = await fetch(`https://api.exchangeratesapi.io/latest?base=GBP`);
const responseData = await response.json();
console.log(responseData);
const {EUR:euro ,CHF:franc, USD: dolar} = responseData.rates;
currencyArr.push(euro,franc,dolar);
console.log(currencyArr);
setData({currencies: currencyArr, isFetching: false});
console.log("currencies", data);
}
catch (e) {
console.log(e);
setData({currencies: data.currencies, isFetching: false});
}
};
getCurrentCurrency();
}, [id]);
const goToPrevSlide = () => {
// id === 0 ? setId(2) : setId(id-1);
}
const goToNextSlide = () =>{
// id === 2 ? setId(0) : setId(id+1);
}
return(
<div className="slide">
<div className="slide-wrapper"
style={{
transform: `translateX(500px)`,
transition: 'transform ease-out 0.45s'
}}
>
{
currencies.map((currency, i, images) => (
<SlideItem currency={currency} key={i} imageUrl={images[i]} />
))
}
</div>
<LeftArrow
goToPrevSlide={goToPrevSlide}
/>
<RightArrow
goToNextSlide={goToNextSlide}
/>
</div>
);
}
export default Slide;
解决方案
在这里,即使您使用自己的值设置状态,当 useEffect 完成时它认为您已经使用新值更新了状态,因为 data.currencies 将在 useEffect 期间设置,这会在将其添加为依赖项时导致循环。
如果您想保留代码,您可以添加// eslint-disable-next-line
到之前的行。
原因:在这种情况下,您知道当 data.currencies 更改时您不想运行此 useEffect(因为这是此 useEffect 的重点)
另一种选择,因为您实际上是在尝试将货币更改为加载状态,您可以简单地更改:
setData({currencies: data.currencies, isFetching: true});
-and-
setData({currencies: data.currencies, isFetching: false});
成为:
setData({isFetching: true});
-and-
setData({isFetching: false});
(请记住,setState 不是即时的,因为设置状态会进入 javascript 队列,所以最好不要依赖它)
完整(略微修改的返回语句)工作代码:
import React, {useEffect, useState} from 'react';
import ReactDOM from 'react-dom'
const Slide = () => {
const [id, setId] = useState(0);
const [data, setData] = useState({currencies:[], isFetching:false});
const images = [
"https://images.pexels.com/photos/672532/pexels-photo-672532.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
"https://images.pexels.com/photos/773471/pexels-photo-773471.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
"https://images.pexels.com/photos/64271/queen-of-liberty-statue-of-liberty-new-york-liberty-statue-64271.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940"
];
useEffect(()=> {
const getCurrentCurrency = async () => {
try{
setData({isFetching: true});
const currencyArr = [];
const response = await fetch(`https://api.exchangeratesapi.io/latest?base=GBP`);
const responseData = await response.json();
const {EUR:euro ,CHF:franc, USD: dolar} = responseData.rates;
currencyArr.push(euro,franc,dolar);
setData({currencies: currencyArr, isFetching: false});
}
catch (e) {
setData({isFetching: false});
}
};
getCurrentCurrency();
}, [id]);
const goToPrevSlide = () => {
id === 0 ? setId(2) : setId(id-1);
}
const goToNextSlide = () =>{
id === 2 ? setId(0) : setId(id+1);
}
return(
<div>
<div className="slide">
<div>
{id}
</div>
{JSON.stringify(data)}
<div>
<button onClick={goToPrevSlide}>Prev</button>
<button onClick={goToNextSlide}>Next</button>
</div>
</div>
</div>
);
}
推荐阅读
- discord - discord.py和discord.py的区别[voice]
- python - 如何修复不起作用的python请求分页
- vue.js - 如何使用 vuejs 嵌套组件?
- sql-server - 合并语句与视图
- git - 什么是默认的 git diff 工具(和合并工具)?
- python - 如何在 df 拆分期间维护我的列模式?
- react-native - React Native useState 不自动更新?
- python - 将多页网页表格提取到 Excel 中
- swift - Swift 4:PHAsset to Image 降低质量
- nginx - 如何将 nginx 配置为仅允许来自云端客户端的请求?