props
對象並返回一個
React 元素
,它本質上就是基礎的
JavaScript函數。
Class組件的寫法建立方法有兩種,下圖是兼容es5寫法的React.createClass定義的組件,這也是react一開始的建立組件的方法。 前端
propTypes
用來處理校驗定義屬性的類型校驗,PropTypes是從React中獲取的,在React16.0.0版本之後廢棄了這種寫法,PropTypes被單獨提取到prop-types
包中,因此先比較新的版本中,咱們要進行類型校驗,須要手動引入 prop-types 這個模塊getInitialState
用來初始化state,getDefaultProps
用來定義props的默認屬性值,這兩個函數的用法有點相似於如今vue中的data和props方法render函數
,它會返回 react node用來渲染視圖這是一個如今常見的ES6的class react組件寫法 vue
Component API
, 配合一些代碼轉換工具咱們可使用最新的es語法render函數
用來渲染視圖,因爲es6支持了方法簡寫,render以及其餘定義的函數已經不須要聲明function 關鍵字super
調用,ES6 規定,子類的構造函數必須執行一次super方法,若是子類沒有定義constructor方法,這個構造函數會被默認添加並調用super。 若是咱們聲明瞭constructor函數,就必須在構造函數裏調用super,只有在正常調用super(props)方法後才能夠訪問this對象,在constructor中若是要訪問this.props須要在super中傳入props,固然也能夠直接經過props訪問。可是不管有沒有定義constructor,super是否傳入props參數,在react的其餘生命週期中this.props都是可使用的,這是React自動附帶的。字段名 = 引用值
。 在 constructor 方法被執行前, 實例上已經被賦值了該字段內容。
字段名 = state
對象內容來聲明state對象。 因爲箭頭函數沒有本身
this,在這裏它會指向當前類的實例。借用公有類字段的提案,咱們能夠直接聲明一個 箭頭函數來修正方法的this指向。 這樣咱們就無需在構造函數裏去建立state。也不須要在構造函數裏寫一大堆function綁定this。若是沒有其餘的操做,咱們就徹底能夠省略構造函數。
PureComponent
內部是繼承React.Component來的,在React.Component組件中咱們可使用shouldComponentUpdate來判斷是否重發從新渲染,而 React.PureComponent 內部使用 shallowEqual 進行淺比較。 淺比較會比較更新先後的state和props的長度是否一致,判斷是否新增或者減小了props或state的數據個數。 而後它還會調用內部的objectis
方法淺層對比先後的state和prop,objectis相似於es6的 Object.is方法, Object.is 相似於 === 全等運算符,只是在比較 +0 跟 -0 時表現的不太同樣, === 返回的是true 而他是false。node
上圖是一個很簡單的函數組件例子,雖說函數組件本質上就是 一個 JavaScript 函數, 在例子裏看起來沒有任何使用react的api或者方法,可是咱們仍然引入了react,這是由於在組件內部返回的react 元素 使用了 jsx,他實質上是React.createElement
的語法糖,配置好babel就能夠爲咱們編譯jsx,簡化了咱們寫createElement的過程。react
函數組件不須要聲明類,能夠避免大量的譬如extends或者constructor這樣的代碼 也不須要處理 this 指向的問題。 更加純粹的是一個函數就是一個組件,React 官方說的 React 組件一直更像是函數,咱們寫函數式組件彷佛也是更加貼近react的原則。 引用透明性是函數式編程的一個概念,我我的以爲函數組件遵循了純函數的概念。webpack
引用透明性是函數式編程裏的概念。 這是一個 redux 裏的 reducer 函數。在 redux 裏 reducer
須要被定義爲一個純函數,它符合純函數的幾個定義:git
不少時候一開始咱們寫的代碼或者組件都是比較簡單的,咱們可能會選 函數組件來完成一個 簡單的功能模塊。可是越到後面可能功能就變的越發的複雜了,函數組件內可能須要一些本身的狀態或者生命週期了。 這時候想要實現這些功能可能就須要把它藉助 高階組件 或者 render props 幫它包裝一層class 的父組件,這樣它就間接的擁有了狀態跟生命週期。可是這也都只是在函數組件外借助了 class 組件的能力。es6
因爲函數組件在每次渲染時候,組件內部都會從上到下從新執行一遍,它也沒有辦法有本身內部的狀態,也沒法產生反作用,爲了加強函數組件,hook
就出現了。github
Vue 在放出可能到來 3.0 更新的內容,上圖就是此次更新變更比較大的 funtion based api
.web
對比右側2.0的寫法, template 就是 以前的模板語法。比較特殊的就是 setup 函數。 這裏的value是一個包裝對象,它就是組件內部的狀態,這個看起來跟react 的 usestate hook 仍是很是像的。 onMounted 對應的就是之前的生命週期函數 mounted,方法最後的返回對象有點像以前的data方法裏的內容被綁定到了template模板語法上,setup 看起來就是一個簡單的函數。typescript
function based api
借鑑了
react hook
的思想。 因爲
typescript對函數的類型推導能力比較好,以前vue組件比較流行的那種對象的寫法如今看起來也變成了setup這樣一個函數了。 至於更靈活的邏輯複用能力,這個在後面會看到是如何進行邏輯複用的。
React 16.8
的新增特性。它是在函數組件的基礎上引入了一些新API,可讓你在不編寫
class 的狀況下使用
state 以及其餘的 React 特性。
咱們看到這裏使用了一個 useState
的API,它能夠在調用時傳入參數,而且返回一個數組。數組中有兩項內容,第一個是狀態(state)、第二個是設置狀態(setState),使用es6 數組解構的特性,咱們能夠根據咱們的須要去語義化命名,useState中的init參數只會在方法在第一次初始化之後,即便函數組件被更新,它的state也不會被重置,因此它能夠一直保留着當前的狀態。 這也就讓函數組件擁有了內部狀態,以及生命週期。
在react 的 class 組件中,咱們會定義一個數組類型的 state,在對修改了引用中data裏的一些值後,調用this.setState 方法會觸發從新渲染,可是在一樣的操做在hook裏並不會觸發更新。
useEffect的規則以下:
React內部會建立對應的 hook 節點,react 第一次初始化組件時內部會將這些節點結構經過 next 依次鏈接起來,造成一個單向鏈表結構,每一次調用setter 就 dispach 一個對應的action方法,將action存儲在queue中。
在後續觸發渲染時,react 會調用 queue 隊列中的內容,queue 也是一個鏈表結構,它是收集咱們調用setter方法,queue 會依次執行內部的action,從而獲取到最新的狀態值,狀態值會被更新到memorizedState上,而後將狀態反應到對應的hook字段中造成綁定。因此當咱們打亂或者增長減小hooks時,會形成hook內部順序錯誤,從而致使沒法正常工做。
上圖是組合成的一個hooks單向鏈表結構,內部依次經過next指向下一個hook。
嘗試經過修改hook數量,在第一次初始化時候咱們調用了三個usestate hook,react也會在它內部依次收集了三個hook。 第一次渲染時,頁面能夠正常的渲染出內容,當咱們點擊了一個 setter 方法,從新觸發了渲染時,會因爲 hook 數量比以前的少而致使頁面錯誤,沒法正常渲染。因此保證每次都是相同的調用順序才能正確的使用hook。
componentDidMount: 當第二個參數爲空數組時,回調只會被觸發一次,相似於componentDidMount。
useRef返回一個可變的ref對象,它不只能夠綁定dom的引用,也能夠用來存儲一些值。其.current
屬性被初始化爲傳遞的參數(initialValue)。返回的對象將持續整個組件的生命週期。變動 .current
屬性不會引起組件從新渲染。
componentWillUnmount 前面提到每一個 useEffect 均可以返回一個清除函數。配合這一特性,咱們能夠任然將第二個參數設置爲一個空數組,這樣清除函數會在組件卸載前被調用,咱們能夠在這裏面清除一些事件監聽器等。更方便的是咱們能夠將 didMount 和 unMount 寫在同一個 useEffect 鉤子中。
setState的第二個參數 咱們知道在使用setState方法時,能夠傳入第二個參數,這個參數是個回調函數,它在設置完 state 之後 會被調用。 咱們在hook裏也能夠經過用useEffect 鉤子傳入要監聽的 state,當該state更新之後,回調函數會被調用。
React 規定 自定義hook 須要用 use 開頭來定義,自定義hook雖然不是一個組件,它不須要返回 React Node 元素節點,若是返回了元素,它就又變成的一個函數組件,可是雖然這樣,它一樣的能夠在方法內部使用 狀態 usestate 和生命週期 useeffect 等其餘的 hooks。他擁有本身的內部狀態和生命週期。
比較特殊的是 自定義hook 返回的內容能夠任何類型,你能夠單純的返回一個值,也能夠返回一個對象或者數組甚至是方法,返回的內容取決於在調用你建立的自定義hook時所須要的一些屬性。
咱們在這裏定義了一個名爲 useOnline 的自定義hook, 咱們用它來判斷當前的網絡鏈接狀態。首先hook的方法名是以use開頭的,後面的名字能夠根據你的意願來定義,大部分時候hook都會遵循駝峯命名法,只要是以use開頭,後面的定義是沒有限制的。不過我嘗試了一下即便不使用use開頭建立的自定義hook其實也是正常運行的。react 約定以use開頭是爲了經過一些自動檢查工具來來校驗 這些use開頭的hook內部是否違反了 hook的使用規則。不過仍是最好遵循使用use開頭,駝峯命名這樣一個約定。
而後調用 usestate 建立一個 自定義hook內部的狀態, 傳入了 navigator online 初始化當前的網絡狀態,而且在自定義 hook 內部擁有了本身的狀態。
接着在使用 useeffect 鉤子內,咱們須要監聽網絡狀態的變化,聯網或者斷網的監聽方法只須要在組件建立時調用一次便可,因此咱們在傳遞useeffect的第二個參數時,只傳遞了一個空的數組,這樣它就只會在 didmount 時被調用一次。
一樣的在銷燬組件時,咱們也須要清除掉這些監聽事情。在 effect 鉤子的返回函數中清理掉這兩個監聽方法便可
最後咱們將 當前的狀態值 做爲自定義hook的返回值,這樣就完成了一個監聽網絡狀態的自定義hook。
咱們在一個最簡單的函數組件中引入這個hook。 而後在函數組件內咱們調用這個自定義hook,hook會返回當前的網絡狀態,這是一個很簡單的函數組件,咱們只渲染當前的網絡狀態。
當咱們渲染出組件時候他渲染出了當前的網絡狀態, 當咱們切換爲離線狀態時,能夠看組件被從新渲染出了當前的網絡狀態值。這樣,當咱們建立出一個自定義hook時 就能夠在不少地方調用直接複用這段代碼,達到了邏輯複用的目的。
不過你們可能以爲這不就是抽象一個方法麼? 好像沒有自定義hook 咱們也能夠把一些方法抽象到一些工具函數中, 寫一些 helper 或者 utils來完成這些功能 。 可是實際上是不同的,自定義的hook強大之處在於擁有狀態,當狀態值改變時,它能夠觸發調用組件的從新渲染,並且自定義hook能夠跟隨着組件的生命週期,在不一樣的生命鉤子階段,咱們能夠處理一些事件。
咱們能夠選擇本身去 實現 一個 useDidMount 自定義hook,實現起來也很是簡單。只須要在鉤子內部調用 useeffect hook,將它的第一個參數傳遞爲咱們自定義鉤子的回調函數參數,將第二個可選的參數設爲一個空數組,這樣就只會在 didmount時候被調用一次。
這個開源項目幫咱們收集了一系列已經封裝好的自定義hook,好比這些生命週期鉤子,咱們只須要引入便可實現這些生命週期。包括一些 didMount, unmount, update 等鉤子。
分享一個React Hook弧形進度條組件react-arc-progress,這個以前是一個es6方式寫的插件,而後以前爲了跟進 react hook,將它改形成了一個 react 組件。
重複的造輪子確定是沒有意義的,因此要添加一些獨特的功能讓它變得更不同些:
GitHub地址,請給個star吧 ◔ ‸◔