react hooks的缺点(针对状态不同步和没有生命周期)
react在16.8中加入了hooks,可以在函数组件中添加一些有自己独立上下文管理的状态(useState),不再依赖于类组件,同时一些逻辑也可以放到hooks中来复用(useEffects)。
不巧,最近react项目里用到了hooks,就拿来练练手,在开发中遇到了点问题,我就说说我的问题和解决方案吧
1.没有生命周期。
2.没有回调函数。
缺点
一、状态不同步
函数的运行是独立的,每个函数都有一份独立的作用域。函数的变量是保存在运行时的作用域里面,当我们有异步操作的时候,经常会碰到异步回调的变量引用是之前的,也就是旧的(这里也可以理解成闭包)如下:
import React, { useState } from "react";
const Counter = () => {
const [counter, setCounter] = useState(0);
const onAlertButtonClick = () => {
setTimeout(() => {
alert("Value: " + counter);
}, 3000);
};
return (
<div>
<p>You clicked {counter} times.</p>
<button onClick={() => setCounter(counter + 1)}>Click me</button>
<button onClick={onAlertButtonClick}>
Show me the value in 3 seconds
</button>
</div>
);
};
export default Counter;
当你点击Show me the value in 3 seconds的后,紧接着点击Click me使得counter的值从0变成1。三秒后,定时器触发,但alert出来的是0(旧值),但我希望的结果是当前的状态1。
这时我们可以用useEffect来实现我们的需求
import React, { useState, useRef, useEffect } from "react";
const Counter = () => {
const [counter, setCounter] = useState(0);
const counterRef = useRef(counter);
const onAlertButtonClick = () => {
setTimeout(() => {
alert("Value: " + counterRef.current);
}, 3000);
};
useEffect(() => {
counterRef.current = counter;
});
return (
<div>
<p>You clicked {counter} times.</p>
<button onClick={() => setCounter(counter + 1)}>Click me</button>
<button onClick={onAlertButtonClick}>
Show me the value in 3 seconds
</button>
</div>
);
};
export default Counter;
这时alert的是当前的值1。其实解决这个hooks的问题也可以参照类的instance。用useRef返回的immutable RefObject(current属性是可变的)来保存state,然后取值方式从counter变成了: counterRef.current 。
二、没有生命周期
比如我在开发中设置了个定时器,那我想页面销毁的时候肯定要清除定时器。那没有生命周期的hooks怎么实现我们的需求呢。
//创建一个标识,通用容器
const timer = useRef(null);
const onEvent = async (eventName, params) => {
switch (eventName) {
case 'updateFileList':
try {
timer.current = setInterval(async () => {
await getReferenceBooKData(true, true, setAllocatedMainfestData);//某些循环请求数据的
}, 1500);
} catch (e) {
// todo
}
return;
}
}
useEffect(() => () => { return componentWillUnmount() }, []);
//销毁组件清除定时器
const componentWillUnmount = ()=>{
if (timer.current) {
clearTimeout(timer.current);
}
};
代码不是很全,主要可以参考方法的使用。就这样完美解决了我的问题,相当于监听了页面销毁的componentWillUnmount,如果你有其他需要周期需要操作的,也可以参考下面的用useEffect实现其他的周期变化操作
useEffect( () => console.log("mount"), [] );
useEffect( () => console.log("will update data1"), [ data1 ] );
useEffect( () => console.log("will update any") );
useEffect( () => () => console.log("will update data1 or unmount"), [ data1 ] );
useEffect( () => () => console.log("unmount"), [] );