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"), [] );
