useEffect无限循环
请看下面的例子:
App组件显示了一个项目列表,状态和状态更新函数来自与useState这个hooks,
通过调用useState,来创建App组件的内部状态。
初始状态是一个object,其中的hits为一个空数组,目前还没有请求后端的接口。
import React, { useState } from 'react';
function App() {
const [data, setData] = useState({ hits: [] });
return (
<ul>
{data.hits.map(item => (
<li key={item.objectID}>
<a href={item.url}>{item.title}</a>
</li>
))}
</ul>
);
}
export default App;
为了获取后端提供的数据,接下来将使用axios来发起请求,
同样也可以使用fetch,这里会使用useEffect来隔离副作用。
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function App() {
const [data, setData] = useState({ hits: [] });
useEffect(async () => {
const result = await axios(
'urlurlurl',
);
setData(result.data);
});
return (
<ul>
{data.hits.map(item => (
<li key={item.objectID}>
<a href={item.url}>{item.title}</a>
</li>
))}
</ul>
);
}
export default App;
在useEffect中,不仅会请求后端的数据,
还会通过调用setData来更新本地的状态,这样会触发view的更新。
但是,运行这个程序的时候,会出现无限循环的情况。
useEffect在组件mount时执行,但也会在组件更新时执行。
因为我们在每次请求数据之后都会设置本地的状态,所以组件会更新,
因此useEffect会再次执行,因此出现了无限循环的情况。我们只想在组件mount时请求数据。
我们可以传递一个空数组作为useEffect的第二个参数,这样就能避免在组件更新执行useEffect,
只会在组件mount时执行。
import React, { useState, useEffect } from 'react';
import axios from 'axios';
function App() {
const [data, setData] = useState({ hits: [] });
useEffect(async () => {
const result = await axios(
'urlurlurl',
);
setData(result.data);
}, []);
return (
<ul>
{data.hits.map(item => (
<li key={item.objectID}>
<a href={item.url}>{item.title}</a>
</li>
))}
</ul>
);
}
export default App;
useEffect的第二个参数可用于定义其依赖的所有变量。
如果其中一个变量发生变化,则useEffect会再次运行。
如果包含变量的数组为空,则在更新组件时useEffect不会再执行,因为它不会监听任何变量的变更。
再看这个例子:
业务场景:需要在页面一开始时得到一个接口的返回值,取调用另一个接口。
我的思路是,先设置这个接口的返回值为data=[], 等到数据是再去请求另一个接口,
即data作为useEffect的第二个参数传入。
但是不知道为什么会造成死循环,拿不到我们想要的结果。
直到在官网看到这个例子:
知道useEffect会比较前一次渲染和后一次渲染的值,然后我就在想,
如果我所设置的data=[],那么即使我后一次渲染的data也为[],那么[]===[]为false,
所以才会造成useEffect会一直不停的渲染,
所以我把data的初始值改为undefined,试了一下果然可以。
结论:useEffect的不作为componentDidUnmount的话,
传入第二个参数时一定注意:第二个参数不能为引用类型,
引用类型比较不出来数据的变化,会造成死循环