Reactjs 即使提供了第二个参数,useEffect钩子也在运行无限循环
我可以发现类似的问题被问了几十次,但提供的解决方案对我来说并不适用。我有一个Reactjs 即使提供了第二个参数,useEffect钩子也在运行无限循环,reactjs,Reactjs,我可以发现类似的问题被问了几十次,但提供的解决方案对我来说并不适用。我有一个useffecthook,它运行一个函数从数据库返回一些数据 const VenueDetails = ({ venue_details, fetchVenueDetails, id }) => { React.useEffect(() => { fetchVenueDetails(id); }, [venue_details]); return (<div></div&
useffect
hook,它运行一个函数从数据库返回一些数据
const VenueDetails = ({ venue_details, fetchVenueDetails, id }) => {
React.useEffect(() => {
fetchVenueDetails(id);
}, [venue_details]);
return (<div></div>)
}
但这些解决方案对我不起作用。我肯定我遗漏了一些明显的东西,但如果有人能为我指出这一点,那就太好了
我也试过了
React.useEffect(() => {
fetchVenueDetails(id);
}, [id]);
及
编辑:添加更多信息
此外,我的fetchVenueDetails
函数位于contextProvider
fetchVenueDetails = (venue_id) => {
this.setState({ loading: true });
fetch(`/venues/details?venue_id=${venue_id}`)
.then((res) => res.json())
.then((data) => {
this.setState({ loading: false });
const details = data;
this.setState({
venue_details: details,
});
})
.catch((error) => {
console.log('error fetching venue details', error);
this.setState({ loading: false });
});
};
发生无限循环是因为您在contextProvider组件中设置了状态 当您
setState
时,它会重新呈现您的contextProvider,api调用会一次又一次地发生
解决方案与其直接更新您的
状态
,不如调度
一个操作,并将加载设置为true或false。
在useffect
中添加此依赖项将有助于仅当加载
被reducer
操作更改时才重新呈现
除非您的加载
状态通过reducer
操作更改,否则您的useffect
依赖关系不会更改,因此您的组件不会无限呈现
您不应该在功能组件中使用state
和setState
试试这个:
上下文提供程序组件
根据您的应用程序调整代码。
这里上下文提供程序和reducer位于它们自己的目录中,所以将reducer导入更改为reducer组件
我希望这对你有用,因为它对我有用
快乐编程:)似乎id
应该在依赖项数组中?同意@Nick-依赖项数组应该只包含那些可能在使用效果中发生变化的项<代码>id
可能就是您想要的。当您执行提取时,地点\u详细信息可能正在更改,这正是触发useEffect再次运行的原因。我刚刚更新了我的问题。@tdammon这是因为您不能在arrow函数中使用this.setState()
。我甚至没有看到您呈现任何内容或使用从fetchVenueDetails()
检索到的任何数据。当然,任何包含一个值的JS标识符都可以用作react钩子依赖项,该值不能保证是稳定的引用。我刚刚意识到你提到过,即使有一个空的依赖数组,无限循环仍然在发生。。。听起来组件正在重新安装,而不是简单地重新招标。您能否提供一个示例,说明如何呈现VenueDetails
组件?当useReducer
状态更新时,是否会出现重新呈现上下文提供程序的问题?分派更新状态的操作仍会更新状态。此外,reducer函数应该简单地合并状态更新,在reducer中的切换\u加载
操作将清除场馆\u细节
状态。不,我有两周前的相同情况,我尝试了此代码,它对我有效。infinte渲染问题已解决。我必须在减速机中添加…状态,我忘记了。谢谢:)@DrewReese不重新加载,因为加载状态仍然相同,并且仅当reducer更改它时才进行更改,无论contextProvider渲染多少次。而且useffect
只有在加载状态发生变化时才会运行。哦,我明白了,所以您的建议是将load
作为一个道具传递给VenueDetails
,并用作调用fetchVenueDetails
的依赖项和条件保护。您的解决方案/建议似乎暗示仅使用useReducer
hook就可以解决状态更新/渲染循环问题。你可能想让你的答案中的这一部分更加公开和清晰。
React.useEffect(() => {
fetchVenueDetails(id);
}, [venue_details, id]);
fetchVenueDetails = (venue_id) => {
this.setState({ loading: true });
fetch(`/venues/details?venue_id=${venue_id}`)
.then((res) => res.json())
.then((data) => {
this.setState({ loading: false });
const details = data;
this.setState({
venue_details: details,
});
})
.catch((error) => {
console.log('error fetching venue details', error);
this.setState({ loading: false });
});
};
import React, { createContext, useReducer, useEffect } from 'react';
import { venueReducer } from '../reducers/venueReducer';
export const venueContext = createContext();
const venueContextProvider = (props) => {
const [venueDetails, venueDispatch] = useReducer(venueReducer, {
venue_details: null,
loading: true
});
fetchVenueDetails = (venue_id) => {
venueDispatch({type: 'TOGGLE_LOADING'}):
fetch(`/venues/details?venue_id=${venue_id}`)
.then((res) => res.json())
.then((data) => {
venueDispatch({type: 'TOGGLE_LOADING'}):
const details = data;
venueDispatch({type: 'FETCH_DETAILS', payload: details});
})
.catch((error) => {
console.log('error fetching venue details', error);
venueDispatch({type: 'TOGGLE_LOADING'}):
});
};
useEffect(() => {
fetchVenueDetails(id);
}, [venueDetails.loading]);
return (
<venueContext.Provider value={{ venueDetails, venueDispatch }}>
{props.children}
</venueContext.Provider>
)
}
export default venueContextProvider;
export const venueReducer = (state, action) => {
switch(action.type) {
case 'FETCH_DETAILS':
return {
...state,
venue_details: action.payload
}
case 'TOGGLE_LOADING':
return {
...state,
loading: !state.loading
}
}
}