新手刚用hooks的时候,如果没开eslint,比较容易写出无线循环,比如下面代码
export default function App() {
const [count, setCount] = useState(0);
const value = { name: 1 };
useEffect(() => {
setCount(Math.random());
alert("render 1");
}, [value]);
return (
<div className="App">
<h1>xxxx 1</h1>
<h2>xxxx 1 xxxx</h2>
</div>
);
}
造成循环的原因是:组件初始化渲染->useEffect执行->setCount触发组件重新渲染->useEffect执行->setCount触发组件重新渲染...
解决的方法有两种:
1.useMemo() 或者 useCallback()
export default function App() {
const [count, setCount] = useState(0);
const value = useMemo( ()=>{
return { name: 1 };
},[])
useEffect(() => {
setCount(Math.random());
alert("render 1");
}, [value]);
return (
<div className="App">
<h1>xxxx 1</h1>
<h2>xxxx 1 xxxx</h2>
</div>
);
}
useMemo :返回一个缓存值,仅会在依赖项改变时才重新计算返回.
本例子中useMemo 依赖项因为回调函数太简单,所以填空
如果依赖的值需要调用一个函数来生成,用useCallback即可
export default function App() {
const [count, setCount] = useState(0);
function doSomething(){
return { name: 1 };
}
const value = useCallback( ()=>{
doSomething()
},[] )
useEffect(() => {
setCount(Math.random());
alert("render 1");
}, [value]);
return (
<div className="App">
<h1>xxxx 1</h1>
<h2>xxxx 1 xxxx</h2>
</div>
);
}
如果你定义了一个变量,满足下面的条件就最好用useMemo和useCallback给包裹住:
- 它不是状态,也就是说,不是用useState定义的(redux中的状态实际上也是用useState定义的)
- 它不是基本类型
- 它会被放在useEffect的依赖列表里 || 自定义hook的返回值
说一下第3条,中间的两个竖线是 或,也就是两者满足其一第3条就成立。自定义hook的返回值也成立是因为,你不知道自定义hook的返回值将会被用在哪里,它可能会被用在依赖也可能不会,所以干脆都加上
代码简单不复杂 就用useMemo来生成变量,复杂需要调用第三方函数就用useCallback
2.更改依赖
useEffect依赖对象改成依赖对象某个属性
export default function App() {
const [count, setCount] = useState(0);
const value = { name: 1 };
useEffect(() => {
setCount(Math.random());
alert("render 1");
}, [value.name]);
return (
<div className="App">
<h1>xxxx 1</h1>
<h2>xxxx 1 xxxx</h2>
</div>
);
}
参考文章
网友评论