反应-发送axios请求时出现Infiinite循环(useState问题?)

时间:2020-07-24 23:20:59

标签: javascript reactjs axios react-hooks infinite-loop

首先,我声明这两个变量以获取并设置从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中呈现)不会更改,但请求会不断发送。

我不知道是什么导致了无限循环

2 个答案:

答案 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));

  ...
};