我在React应用程序中有一个页面/收藏夹,我的Axios.post请求setFavArray在记录它时给了我一个无限循环,它不在useEffect中,当它在时,数组只在随机刷新时填充。React新手,你知道为什么post或useState会导致这种情况吗?
function Favorites() {
// console.log(login_State)
const [loginState, setLoginState] = useState("");
// const [favoriteID, setFavoriteID] = useState([]);
// const [favResult, setFavResults] = useState();
const [favArray, setFavArray] = useState();
const [resultsData, setResultsData] = useState([]);
Axios.post("http://localhost:3001/favorites", {
username: loginState
})
.then((response) => {
setFavArray(response)
// console.log("FAV ARRAY: ", favArray)
})
useEffect(() => {
Axios.get("http://localhost:3001/login").then((response) => {
if (response.data.loggedIn === true) {
setLoginState(response.data.user[0].username)
// console.log(loginState)
}
})
// fetch('https://api.spoonacular.com/recipes/644366/information?apiKey=blank')
// .then(response => response.json())
// .then((data) => {
// setResultsData(data)
// // console.log("REAL: ", resultsData)
// });
}, []);
console.log("FAV ARRAY: ", favArray)
console.log("REAL SHIT: ", resultsData)
return (
resultsData.map(item => {
return (
<div className="favorites-wrapper">
<h1> All of your favorites in one place! </h1>
<div className="favorite-card">
<Col className='mt-5' xs={6} md={4}>
<Card className='card-hover'>
<Card.Img fluid className='img' variant="top" src={item.image} />
<Card.Body className='card-body'>
<Card.Title className='title' >{item.title}</Card.Title>
<Card.Text>
Some quick example text to build on the card title and make up the
bulk of the card's content.
</Card.Text>
</Card.Body>
</Card>
</Col>
</div>
</div>
)
})
)
}
export default Favorites;
我试着移动每个调用进出useEffect,没有运气。在我的后端,我只是检查一个DB,看看当前用户名有什么“收藏夹”。
1条答案
按热度按时间oknwwptz1#
问题
你会得到一个无限循环,因为每次你的组件被渲染时你都会触发post请求,这反过来又会改变组件的状态,这反过来又会触发另一个渲染。
目前,以下情况正在逐步发生:
1.第一次调用组件
1.将触发发布请求
1.您正在记录
FAV ARRAY
和REAL SHIT
(这两个请求仍然是空的,因为这两个请求都还没有完成)1.由于
resultsData
是空的,所以您构建并返回JSX(实际上什么都没有)。1.一段时间后(两个请求中的第一个请求完成所需的时间),调用
setFavArray
或setLoginState
,这将触发组件重新呈现,因此这些步骤重新开始。为了避免无限循环,您必须确保只触发一次请求。此外,您对favourits的POST调用取决于登录调用的结果,这也是目前没有正确处理的。这可能导致您的数据有时只被正确获取(这是一个竞争条件)。
解决方案
让我们来看看如何实现这一点。首先,让我们来处理调用。因为我们需要第一次调用的结果来执行第二次调用,所以我们需要等待第一次调用完成。(这在async/await中更容易,详见文章末尾)。我还建议将这部分移到一个单独的函数中。请参阅这里:
回到组件中的主要问题。要在组件第一次渲染时触发一次请求,我们可以使用
useEffect
和一个空的依赖数组。请参见这里:工作原理
让我们再一步一步地看一下:
1.组件第一次被调用
fetchFavourites()
。(JS实际上并没有等待它完成。fetchData
函数本质上是暂停的,有时会在组件的其余部分执行完后继续执行)1.* 一段时间过去,fetchFavourites完成 *
setData
和setLoaded
被调用。(这些会改变组件的状态,这将使react重新呈现它)1.组件被调用/呈现
1.我们跳过useEffect,因为它的依赖项没有改变
1.您使用实际数据呈现组件
更好的解决方案
另一种解决问题的方法(我强烈推荐)是使用类似TanStack Query的库,这样的库可以解决获取和处理服务器状态的很多痛点。
继续阅读
有关async/await的详细信息,请参阅https://stackoverflow.blog/2019/09/12/practical-ways-to-write-better-javascript/或How and when to use ‘async’ and ‘await’。它本质上与promise.then相同,但更具可读性。
有关useEffect中的async函数的更多详细信息,请参阅以下内容:React Hook Warnings for async function in useEffect: useEffect function must return a cleanup function or nothing