<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                &emsp;&emsp;Hook(鉤子)是React v16.8新引入的特性,能以鉤子的形式為函數組件附加類組件的狀態、生命周期等特性。React的類組件有難以拆分、測試,狀態邏輯分散,難以復用等問題,雖然可以通過渲染屬性(Render Props)和高階組件來提取狀態邏輯,但會形成層層嵌套,而使用Hook后的函數組件就能避免這些問題。 &emsp;&emsp;Hook本質上是一種特殊的JavaScript函數,名稱以use為前綴,在使用它時需要遵循兩條規則,如下所列: &emsp;&emsp;(1)在循環、條件語句或嵌套函數中調用Hook是不允許的,必須在函數的最頂層調用,確保Hook的調用順序。 &emsp;&emsp;(2)只能在React的函數組件或自定義的Hook中調用Hook。 &emsp;&emsp;這兩條規則可以結合后文的分析慢慢體會,接下來會詳細講解幾個內置的Hook,并且會介紹如何自定義Hook,文中的示例來源于[官網](https://react.docschina.org/docs/hooks-intro.html)。 ## 一、State Hook(狀態鉤子) &emsp;&emsp;先來看一個簡單的類組件,Btn組件會渲染出一個按鈕,每次點擊按鈕,其文本會加一。 ~~~ import React from "react"; class Btn extends React.Component { constructor() { super(); this.state = { count: 0 }; this.dot = this.dot.bind(this); } dot() { this.setState({ count: this.state.count + 1 }) } render() { return <button onClick={this.dot}>{this.state.count}</button>; } } ~~~ &emsp;&emsp;然后將Btn組件改成相同功能的函數形式,如下代碼所示,沒有了構造函數和render()方法,通過useState()為函數組件附加狀態。 ~~~ import { useState } from "react"; function Btn() { const [count, setCount] = useState(0); return (<button onClick={() => setCount(count + 1)}>{count}</button>); } ~~~ &emsp;&emsp;useState()是一個鉤子函數,它的參數是狀態的初始值,返回一個數組,包含兩個元素:當前狀態和更新狀態的函數。通過數組解構的方式聲明了一個名為count的狀態變量和一個名為setCount的函數,相當于類組件中的this.state.count和this.setState()。在點擊事件中讀取狀態或調用更新狀態的函數都不需要this。 &emsp;&emsp;注意,useState()可以被多次調用,React會根據useState()的出現順序保證狀態的獨立性,并且與this.setState()不同的是,更新狀態是替換而不是合并。 ## 二、Effect Hook(副作用鉤子) &emsp;&emsp;在React組件中有兩種常見的副作用:無需清除和需要清除,接下來會逐個講解。 **1)無需清除** &emsp;&emsp;在React更新DOM之后會運行一些無需清除的副作用,例如向服務器請求數據、變更DOM結構、記錄日志等。在類組件中,這些副作用常在componentDidMount()和componentDidUpdate()生命周期方法中執行。以上一節的Btn組件為例,在更新計數后,修改頁面標題,如下所示(只列出了核心代碼)。 ~~~ class Btn extends React.Component { componentDidMount() { document.title = `You clicked ${this.state.count} times`; } componentDidUpdate() { document.title = `You clicked ${this.state.count} times`; } } ~~~ &emsp;&emsp;注意,兩個函數中的代碼是重復的,因為很多情況下,在組件掛載和更新時會執行相同的操作,而React并未提供每次渲染之后可回調的函數。 &emsp;&emsp;接下來用useEffect()鉤子函數實現相同功能,同樣只列出了核心代碼,如下代碼所示。useEffect()使得相同功能的副作用不用再分散到不同的生命周期中,即按照用途分離副作用。 ~~~ import { useEffect } from "react"; function Btn() { useEffect(() => { document.title = `You clicked ${count} times`; }); } ~~~ &emsp;&emsp;useEffect()可接收兩個參數,第一個參數是回調函數,叫做Effect,在每次渲染(包括第一次掛載和后續的DOM更新)之后Effect都會被執行,其中每次接收的Effect都是新的,不用擔心狀態過期的問題;第二個參數是可選的數組(由Effect的依賴項組成),用于控制Effect的執行,而是否執行Effect將取決于數組中的元素是否發生了變化,例如將count變量作為數組的元素(如下代碼所示),當count的值與重新渲染后的count的值一樣時,React會忽略這個Effect,優化性能。 ~~~ useEffect(() => { document.title = `You clicked ${count} times`; }, [count]); ~~~ &emsp;&emsp;當把一個空數組(\[\])傳給useEffect()時,Effect只會運行一次,即僅在組件掛載和卸載時運行。由于Effect不依賴state或props中的任意值,因此永遠都不需要重復執行。 &emsp;&emsp;useEffect()相當于componentDidMount()、componentDidUpdate()和componentWillUnmount()三個生命周期方法的組合,但與componentDidMount()或componentDidUpdate()不同,使用useEffect()會異步執行副作用,可避免阻塞瀏覽器更新視圖。 **2)需要清除** &emsp;&emsp;有些副作用是必須清除的,例如訂閱的外部數據源,將其清除后,可防止內存泄露。在類組件中,通常會在componentDidMount()中設置訂閱,并在componentWillUnmount()中執行清除。 &emsp;&emsp;假設有一個ChatAPI模塊,用于訂閱好友的在線狀態,如下所示(只有關鍵部分),其中componentDidMount()和componentWillUnmount()處理的是關聯的副作用。 ~~~ class FriendStatus extends React.Component { componentDidMount() { ChatAPI.subscribeToFriendStatus( this.props.friend.id, this.handleStatusChange ); } componentWillUnmount() { ChatAPI.unsubscribeFromFriendStatus( this.props.friend.id, this.handleStatusChange ); } handleStatusChange(status) { this.setState({ isOnline: status.isOnline }); } } ~~~ &emsp;&emsp;接下來用函數組件實現相同的功能,同樣只有關鍵部分的代碼。由于添加和移除訂閱的邏輯有很強的緊密性,因此useEffect()將它們組織在一起。當Effect返回一個函數時,React將在執行清除操作時調用它,如下所示。 ~~~ function FriendStatus(props) { useEffect(() => { function handleStatusChange(status) { setIsOnline(status.isOnline); } ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; }); } ~~~ &emsp;&emsp;注意,React會在執行當前Effect之前對上一個Effect進行清除,也就是說,副作用并不僅在組件卸載時被執行。 ## 三、自定義Hook &emsp;&emsp;自定義的Hook用于保存組件中可復用的邏輯,它的參數和返回值都沒有特殊要求,類似于一個普通的函數,但為了遵循Hook的規則,其名稱必須以use開頭。接下來將之前的FriendStatus組件中訂閱好友在線狀態的邏輯抽離到自定義的useFriendStatus()中,其參數為friendID,返回值為好友當前的狀態,如下所示。 ~~~ function useFriendStatus(friendID) { const [isOnline, setIsOnline] = useState(null); useEffect(() => { function handleStatusChange(status) { setIsOnline(status.isOnline); } ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange); }; }); return isOnline; } ~~~ &emsp;&emsp;在FriendStatus組件中調用自定義的Hook,其內部邏輯將變得非常簡潔,如下所示。 ~~~ function FriendStatus(props) { const isOnline = useFriendStatus(props.friend.id); if (isOnline === null) { return 'Loading...'; } return isOnline ? 'Online' : 'Offline'; } ~~~ ## 四、其它Hook &emsp;&emsp;除了上面所講解的兩個內置Hook,React還提供了其它功能的Hook,例如useContext()、useCallback()、useMemo()、useLayoutEffect()等,具體可參考[官方的API索引](https://react.docschina.org/docs/hooks-reference.html)。 **1)useContext()** &emsp;&emsp;接收一個由React.createContext()創建的Context對象,返回該Context的當前值(即要傳送的數據)。調用了useContext()的組件會在Context值發生變化時重新渲染。 **2)useCallback()** &emsp;&emsp;包含兩個參數,第一個是回調函數,第二個是依賴項數組,返回回調函數的記憶版本。當某個依賴項發生改變時,會更新回調函數。注意,依賴項數組不會作為參數傳給回調函數。 **3)useMemo()** &emsp;&emsp;包含回調函數和依賴項數組兩個參數,回調函數的返回值就是useMemo()的返回值,它會被緩存,并且僅在某個依賴項發生改變時才重新計算它。之前的useCallback(fn, deps)相當于useMemo(() => fn, deps)。 **4)useLayoutEffect()** &emsp;&emsp;函數簽名與useEffect()相同,但調用時機不同,它會在所有的DOM更新之后同步調用Effect,也就是在瀏覽器更新視圖之前調用Effect。 ***** > 原文出處: [博客園-React躬行記](https://www.cnblogs.com/strick/category/1455720.html) [知乎專欄-React躬行記](https://zhuanlan.zhihu.com/pwreact) 已建立一個微信前端交流群,如要進群,請先加微信號freedom20180706或掃描下面的二維碼,請求中需注明“看云加群”,在通過請求后就會把你拉進來。還搜集整理了一套[面試資料](https://github.com/pwstrick/daily),歡迎瀏覽。 ![](https://box.kancloud.cn/2e1f8ecf9512ecdd2fcaae8250e7d48a_430x430.jpg =200x200) 推薦一款前端監控腳本:[shin-monitor](https://github.com/pwstrick/shin-monitor),不僅能監控前端的錯誤、通信、打印等行為,還能計算各類性能參數,包括 FMP、LCP、FP 等。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看