您好,登錄后才能下訂單哦!
React中Hooks是如何工作的?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
React Hook 說白了就是 React V18.6 新增的一些 API,API的本質就是提供某種功能的函數接口。因此,React Hooks 就是一些函數,但是 React Hooks 不是純函數。
什么是純函數呢?就是此函數在相同的輸入值時,需產生相同的輸出,并且此函數不能影響到外面的數據。
簡單理解就是函數里面不能用到在外面定義的變量,因為如果用到了外面定義的變量,當外面的變量改變時會影響函數內部的計算,函數也會影響到外面的變量。
對于 React Hooks 提供的函數 API,恰恰就不是純函數。
來看一個 useState 的使用語句 const [count, setCount] = useState(0),使用 useState 函數得到的結果并不是全都一樣的,因為如果 useState(0) 每次得到的結果都是一樣的,那 count 值就永遠不會改變了,那 count 所在的頁面就永遠不會改變,和我們看到的結果就不一樣了。由此可知,React Hooks 都不是純函數,也就是說 Hooks 用到了函數外的變量。
那么是什么特性讓 React Hooks 一定不能是純函數呢?實際上是 React 框架和函數組件本身決定的。我們知道,React 頁面渲染的原理就是通過每次 render 得到新的虛擬 DOM ,然后進行 DOM Diff 來渲染頁面。而 React 的函數組件是通過執行整個函數得到一個虛擬 DOM。因此在每次頁面渲染 render 時,在函數組件內部的所有語句都會重新執行一次。如果在函數組件內部使用的 React Hooks 是純函數的話,就不會在每次渲染后得到不同的虛擬 DOM 了。
React 規定: 所有 React 組件都必須是純函數,并禁止修改其自身 props 。
因此在 React V16.8 之前 React Hooks 還沒出來的時候,函數組件因為是純函數,只能返回一個固定的虛擬 DOM,不能包含狀態,也不支持生命周期方法。因此,當時僅僅是支持函數組件,但函數組件相比于類組件限制太多,函數組件無法取代類組件,也沒類組件好用。
React 希望組件是簡單的而不是復雜的,React 認為組件的最佳寫法應該是函數,而不是類。因此 React 就新增了 React Hooks,Hook 就是鉤子的意思,是 React 提供給函數組件在需要外部功能和數據狀態時將其 “鉤” 進去,從而完善函數組件,使其能完全代替類組件。
React 的函數組件只能是純函數,那么每次事件發生時重新 render 函數組件時得到不同的虛擬 DOM 的事就完全交給了 React Hooks,那么 React Hooks 是如何做到的呢?下面就手動實現一個 useState,useState 的具體細節肯定不是這樣的,但原理和思路是一樣的。
React.useState 的第一次執行是將初始值賦予給一個 _state,之后的每次重新 render 時就是讀取 _state 的值。[state, setState] 中的 setState 做的事就是改變 _state 的值,然后重新渲染頁面。
根據這個原理實現 myUseState 函數如下:
import React from 'react'; import ReactDOM from 'react-dom'; let _state function myUseState(initialValue){ if(_state === undefined){ _state = initialValue } const setState = (newValue)=>{ _state = newValue render() } return [_state, setState] } function render(){ ReactDOM.render(<App/>,document.getElementById('root')); } function App(){ const [n, setN] = myUseState(0) return ( <div> n: {n} <button onClick={() => setN(n+1)}>+1</button> </div> ) } ReactDOM.render(<App/>,document.getElementById('root'));
上述實現的 myUseState 存在 bug,當在函數組件內用到兩次 myUseState 時就會出現問題了,二者共用一個 _state 會出現混亂。
因此需要將上述實現進行改進,改進的思路就是將 _state 定義為一個數據或者是對象,由于我們在函數使用時只傳了一個數值,無法確定鍵值,因此只能使用數據。改進如下:
import React from 'react'; import ReactDOM from 'react-dom'; let _state = [] let index = 0 function myUseState(initialValue){ const currentIndex = index if(_state[currentIndex] === undefined){ _state[currentIndex] = initialValue } const setState = (newValue)=>{ _state[currentIndex] = newValue render() } index++ return [_state[currentIndex], setState] } function render(){ index = 0 ReactDOM.render(<App/>,document.getElementById('root')); } function App(){ const [n, setN] = myUseState(0) const [m, setM] = myUseState(0) return ( <div> n: {n} <button onClick={() => setN(n+1)}>+1</button> <br/> m: {m} <button onClick={() => setM(m+1)}>+1</button> </div> ) } ReactDOM.render(<App/>,document.getElementById('root'));
上述實現的 myUseState 肯定不是 React.useState 的具體實現代碼,但實現原理是一致的。myUseState 函數封裝了函數組件內的數據狀態,并對該狀態進行管理,以暴露出相關的操作接口的方式提供給函數組件使用。
這樣一來,函數組件就和其數據狀態分離了,函數組件只負責返回虛擬 DOM 本身就可以了,對于數據狀態的管理完全交給其 “鉤” 住的 React.useState Hook 就可以了。
從上述的實現思路可以發現,React Hooks 的實現其實是基于 全局變量 和 閉包 原理實現的特殊函數。
但是,正是因為這樣的實現方式,限制了 React Hooks 的使用必須是 只在頂層調用Hook,意思就是說 不要在循環,條件或嵌套函數中調用 Hook,如果在 if 條件句中使用了 Hook, 導致組件每次渲染生成時 React.useState 語句的執行次數不對,就會打亂 index 的計數,從而導致數據維護的錯誤。
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。