博客 / 詳情

返回

類組件中如何使用hook函數

靈感來源來自一個面試官問我為什麼hook函數不能在class類組件中使用?如何在class類組件中使用呢?
第一個問題你們自己可以百度一下晚上有,今天着重講解一下第二個問題。
碰到這個問題首先要進行分析:
(1)hook函數在什麼情況下可以調用?答:函數最外層可以調用Hook。
=>可不可以衍生一個函數代替class類組件調用?答:高階組件就可以,因為高階組件本身就是從高階函數演變過來,高階函數我的理解就是在高階函數內調用傳過來的參數(參數一般為回調函數)。高階組件概念差不多,只不過,參數為組件,在react中組件的本質就是函數。。。
接下來,那麼我們現在實現一個需求——————來個數字遞增效果,然後到達某一個值時,停止。
原先錯誤的代碼是這樣的:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
    </head>
    
    <body>
        <div id="root"></div>
        <script src="https://cdn.bootcss.com/react/16.8.6/umd/react.development.js"></script>
 
        <script src="https://cdn.bootcss.com/react-dom/16.8.6/umd/react-dom.development.js"></script>
         
        <script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/require.js/2.3.6/require.js"></script>
            <script type="text/babel">
                 const useState = React.useState;
                function useDateHook(){
                    return new Date().toDateString()
                }
                let timer = null;
                function withHooksHOC(Component){
                    return function (props){
                        const nowDate = useDateHook();
                        let [date,setDate] = useState(5);
                        timer = setInterval(()=>{
                            date++;
                            setDate(date)
                            /*if(date == 10){ //錯誤1
                                clearInterval(timer)
                            }*/ 
                        },1000)
                        if(date == 10){//錯誤2
                            console.log("exe")
                            clearInterval(timer)
                         }
                        return <Component date={date} 
 {...props} />;
                    }
                }
                 class DateCom extends React.Component{
                    render() {
                        return <p>date: {this.props.date}</p>;
                    }
                 }
                 let WithHooksHOCer = withHooksHOC(DateCom);
                class App extends React.Component{
                    constructor(props){
                        super(props)
                    }
                    render() {
                        return <WithHooksHOCer />;
                    }
                };
                
                ReactDOM.render(<App />,document.querySelector('#root'))
            </script>
    </body>
</html>

錯誤1和錯誤2其實錯誤點都差不多,都是date到達10的時候清掉當前定時器,但是每次HOOK setState函數每次更新數據都會生成一個定時器,慢慢的越來越多,導致頁面崩潰!

在之前科普一下useRef作用?
1.獲取DOM對象

2.保存數據
useRef相當於在函數式組件中添加了一個實例對象。useRef不會因為組件的更新而丟失數據,雖然組件進行了更新,但是通過useRef保存的數據並不隨之發生改變。
3.ref對象的值發生改變之後,不會觸發組件重新渲染。
(https://blog.csdn.net/qq_30267753/article/details/125173931)

下面是解決方案,這裏用到了自定義hook函數,然後借鑑useEffect函數結合高階函數(傳遞函數作為參數)和useRef作用(聲明全局變量)的形式,並配置useEffect第二個參數,數組為空代表,組件掛載後和卸載後執行,[參數]表明,參數變化時,這點剛好契合定時函數定時傳參的效果!即每次調用自定義hook函數的時候初始化生成一個回調函數的鏡像,然後再另外一個副作用函數裏代替執行回調函數內容,相當於直接在自定義hook函數中執行定時器效果。

下面是正確的完整的代碼,可以在瀏覽器跑

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title></title>
</head>

<body>
    <div id="root"></div>
    <script src="https://cdn.bootcss.com/react/16.8.6/umd/react.development.js"></script>

    <script src="https://cdn.bootcss.com/react-dom/16.8.6/umd/react-dom.development.js"></script>

    <script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/require.js/2.3.6/require.js"></script>
    <script type="text/babel">
        const useState = React.useState;
        const useEffect = React.useEffect;
        const useRef = React.useRef;
        function useDateHook() {
            return new Date().toDateString()
        }
        function withHooksHOC(Component) {
            return function (props) {
            const nowDate = useDateHook();
            let [date, setDate] = useState(5);
            useInterval(() => {
                if(date < 10){
                    setDate(date + 1);
                }
            }, 1000)
            props = {
                date,
                nowDate
            }
            
            return <Component {...props} />
         }
        }
        function useInterval(callback,delay){
            const savedCallback = useRef();
            useEffect(() => {
                savedCallback.current = callback; //每次都初始化一個saveCallBack對象 用於後面副作用函數執行。
            }, [callback]); //第二個參數代表callback每次變化就就行,數組為空就代表組件掛載和卸載的時候執行
            useEffect(() => {
                let id = setInterval(() => {
                    savedCallback.current(); //執行回調
                }, delay);
                return function (){
                    clearInterval(id);
                }
            }, [delay])
        }
        class DateCom extends React.Component {
            render() {
                return <div id="box"><p>date: {this.props.date}</p><p>props:{this.props.nowDate}</p></div>       
            }
        }
        
        let WithHooksHOCer = withHooksHOC(DateCom);
        class App extends React.Component {
            constructor(props) {
                super(props)
            }
            render() {
                return <WithHooksHOCer />;
            }
        };

        ReactDOM.render(<App />, document.querySelector('#root'))
    </script>
 </body>
</html>

參考文獻:

https://www.52dianzi.com/category/article/37/689191.html

https://baijiahao.baidu.com/s?id=1744203108622010543&wfr=spid...

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.