我在useEffect
内遇到无限循环问题。我想仅在id依赖项更改时发出新请求。当我不传递数据时,setData
就会出现问题。我的数据状态未更新。当我将数据传递给依赖项时,我遇到了无限循环。如何修复它,为什么?
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;
答案 0 :(得分:0)
这是一个示例,您可以使用useDispatch进行操作,它是更多代码,但是您可以将reducer从组件中取出到单独的文件中,并且还应将操作类型和操作创建者放在单独的文件中。
const Slide = () => {
const [id, setId] = React.useState(0);
const [data, dispatch] = React.useReducer(
//you can move this function to a separate file and import it
(state, action) => {
const { type } = action;
if (type === 'LOAD') {//action types should be defined as constants
return {
...state,
loading: true,
};
}
if (type === 'RECEIVED') {
const currencies = action.payload;
return {
currencies,
loading: false,
};
}
if (type === 'ERROR') {
return {
...state,
loading: false,
};
}
return state;
}
);
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 {
//should create action creator functions so you can do
//dispatch(load()) put the action creators in separate file
//usually called actions.js
dispatch({ type: 'LOAD' });
console.log('loading');
//not sure how this depends on id since you are not using id
// in the request or anywhere in the effect
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: dollar,
} = responseData.rates;
const currencies = [euro, franc, dollar];
console.log(currencies);
dispatch({
type: 'RECEIVED',
payload: currencies,
});
console.log('currencies', currencies);
} catch (e) {
console.log(e);
dispatch({
type: 'ERROR',
});
}
};
getCurrentCurrency();
}, [id]);
//other stuff and return jsx
};
在分派之前,您可能应该检查组件是否为still mounted,如果该组件不会卸载,那么这不是问题。
答案 1 :(得分:0)
这里,即使您使用自己的值来设置状态,当useEffect完成时它也会认为您已使用新值更新了数据状态。在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队列,因此setState不是立即的,所以最好不要依赖于此)
完整(略作修改的return语句)工作代码:
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>
);
}