首先,我声明这两个变量以获取并设置从axios请求中获取的值
let tmpFolder = [];
const [folder_JSX,setFolder_JSX] = useState([])
然后我发送请求
const sendRequest = () => {
return axios.get(`sample_url`).then(response => {return response.data})
}
sendRequest().then(folder=> {
//loop through each item and append a JSX element into the array
for (let i=0;i <folder.length;i++) {
tmpFolder.push(<Folder tags={folder[i].tags} name={folder[i].name} description={folder[i].description} date={folder[i].date_created[0]} tagOne={folder[i].tags[0]} tagTwo={folder[i].tags[1]} tagThree={folder[i].tags[2]} tagRest={folder[i].tags.length - 3} />)
}
setFolder_JSX(prev => tmpFolder) // <----- This line is causing an infinite loop
}).catch(err => console.log(err))
编译器抛出Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
这是正确的(当我从文件夹 JSX元素中删除一个道具时,它不会引发此错误,但会不断发出无限请求)
-将文件夹状态设置为该数组。
folder_JSX(在dom中呈现)不会更改,但请求会不断发送。
我不知道是什么导致了无限循环答案 0 :(得分:2)
每次状态更新时,都会再次运行组件功能。因为每次调用该函数时都在调用sendRequest
,然后根据该状态更新状态,所以您将获得无休止的重新提交周期。
无论如何,您都不应在函数的主体内部执行副作用(例如API调用)。 (如果您以前在React中使用过类组件,则应将功能组件视为render
的等效组件,该组件仅从组件的当前属性和状态计算JSX输出,并且不会产生副作用。 )使用钩子时,您可以使用useEffect钩子来进行此类操作。特别是,它的第二个参数是一个变量数组,仅当这些值之一自上次渲染以来发生更改时,效果才会运行。这样可以防止效果在每个渲染器上运行-必须在此处阻止这种效果以停止无限更新。
据我所知,此请求不依赖于任何内部状态,因此它可能仅应在组件首次呈现时运行。在这种情况下,请将空数组作为第二个参数传递。
简而言之,您应该像这样重写代码:
useEffect(() => sendRequest().then(folder => {
//loop through each item and append a JSX element into the array
for (let i=0;i <folder.length;i++) {
tmpFolder.push(<Folder tags={folder[i].tags} name={folder[i].name} description={folder[i].description} date={folder[i].date_created[0]} tagOne={folder[i].tags[0]} tagTwo={folder[i].tags[1]} tagThree={folder[i].tags[2]} tagRest={folder[i].tags.length - 3} />)
}
setFolder_JSX(prev => tmpFolder)
}).catch(err => console.log(err)), []);
答案 1 :(得分:1)
似乎您在功能组件主体中公开了获取逻辑,就像这样:
Auth.configure({
oauth: {
domain: aws.idpDomain,
scope: ['email', 'openid'],
// we need the /autologin step in between to set the cookies properly,
// we don't need that when signing out though
redirectSignIn: aws.redirectSignIn,
redirectSignOut: aws.redirectSignOut,
responseType: 'token',
},
})
如果是这种情况,则/* Return first day of specified week of month of year
**
** @param {number|string} year - year for required week
** @param {number|string} month - month for required week
** Month is calendar month number, 1 = Jan, 2 = Feb, etc.
** @param {number|string} week - week of month
** First week of month is the one with the first Thursday
** @returns {Date} date for Monday at start of required week
*/
function getMonthWeek(year, month, week) {
// Set date to 4th of month
let d = new Date(year, month - 1, 4);
// Get day number, set Sunday to 7
let day = d.getDay() || 7;
// Set to prior Monday
d.setDate(d.getDate() - day + 1);
// Set to required week
d.setDate(d.getDate() + 7 * (week - 1));
return d;
}
// Return array of dates for specified week of month of year
function getWeekDates(year, month, week) {
let d = getMonthWeek(year, month, week);
for (var i=0, arr=[]; i<7; i++) {
// Array of date strings
arr.push(d.toDateString());
// For array of Date objects, replace above with
// arr.push(new Date(d));
// Increment date
d.setDate(d.getDate() + 1);
}
return arr;
}
// Week dates for week 1 of Jan 2020 - week starts in prior year
console.log(getWeekDates(2020, 1, 1));
// Week dates for week 5 of Jan 2020 - 5 week month
console.log(getWeekDates(2020, 1, 5));
// Week dates for week 1 of Oct 2020 - 1st is a Thursday
console.log(getWeekDates(2020, 10, 1));
// Week dates for week 1 of Nov 2020 - 1st is a Sunday
console.log(getWeekDates(2020, 11, 1));
在每个渲染周期被调用,并最终更新组件状态,从而触发另一个渲染,即无限周期。
也许您只想在安装组件时获取数据,就可以使用效果来产生任何副作用:
const MyComponent = () => {
let tmpFolder = [];
const [folder_JSX, setFolder_JSX] = useState([]);
const sendRequest = () => {
return axios.get(`sample_url`).then(response => {
return response.data;
});
};
sendRequest() // <-- invoked each render cycle
.then(folder => {
//loop through each item and append a JSX element into the array
for (let i = 0; i < folder.length; i++) {
tmpFolder.push(
<Folder
tags={folder[i].tags}
name={folder[i].name}
description={folder[i].description}
date={folder[i].date_created[0]}
tagOne={folder[i].tags[0]}
tagTwo={folder[i].tags[1]}
tagThree={folder[i].tags[2]}
tagRest={folder[i].tags.length - 3}
/>
);
}
setFolder_JSX(prev => tmpFolder); // <-- state update triggers rerender
})
.catch(err => console.log(err));
...
};