摘要:已經(jīng)被廢除,具體缺陷可以參考二為了解決的缺陷,第二種解決方案是高階組件簡(jiǎn)稱。我們定義了父組件,存在自身的,并且將自身的通過(guò)的方式傳遞給了子組件。返回一個(gè)標(biāo)識(shí)該的變量,以及更新該的方法。
??為了實(shí)現(xiàn)分離業(yè)務(wù)邏輯代碼,實(shí)現(xiàn)組件內(nèi)部相關(guān)業(yè)務(wù)邏輯的復(fù)用,在React的迭代中針對(duì)類(lèi)組件中的代碼復(fù)用依次發(fā)布了Mixin、HOC、Render props等幾個(gè)方案。此外,針對(duì)函數(shù)組件,在React v16.7.0-alpha 中提出了hooks的概念,在本身無(wú)狀態(tài)的函數(shù)組件,引入獨(dú)立的狀態(tài)空間,也就是說(shuō)在函數(shù)組件中,也可以引入類(lèi)組件中的state和組件生命周期,使得函數(shù)組件變得豐富多彩起來(lái),此外,hooks也保證了邏輯代碼的復(fù)用性和獨(dú)立性。
??本文從針對(duì)類(lèi)組件的復(fù)用解決方案開(kāi)始說(shuō)起,先后介紹了從Mixin、HOC到Render props的演進(jìn),最后介紹了React v16.7.0-alpha 中的 hooks以及自定義一個(gè)hooks
Mixin
HOC
Render props
React hooks的介紹以及如何自定義一個(gè)hooks
原文地址在我的博客中:https://github.com/forthealll...
歡迎star和fork~
一、MixinMixin是最早出現(xiàn)的復(fù)用類(lèi)組件中業(yè)務(wù)邏輯代碼的解決方案,首先來(lái)介紹以下如何適應(yīng)Mixin。下面是一個(gè)Mixin的例子:
const someMixins={ printColor(){ console.log(this.state.color); } setColor(newColor){ this.setState({color:newColor}) } componentDidMount(){ .. } }
下面是一個(gè)使用Mixin的組件:
class Apple extends React.Component{ //僅僅作為演示,mixins一般是通過(guò)React.createClass創(chuàng)建,并且ES6中沒(méi)有這種寫(xiě)法 mixins:[someMixins] constructor(props){ super(props); this.state={ color:"red" } this.printColor=this.printColor.bind(this); } render(){ return這是一個(gè)蘋(píng)果} }
在類(lèi)中mixin引入公共業(yè)務(wù)邏輯:
mixins:[someMixins]
從上面的例子,我們來(lái)總結(jié)以下mixin的缺點(diǎn):
Mixin是可以存在多個(gè)的,是一個(gè)數(shù)組的形式,且Mixin中的函數(shù)是可以調(diào)用setState方法組件中的state的,因此如果有多處Mixin的模塊中修改了相同的state,會(huì)無(wú)法確定state的更新來(lái)源
ES6 classes支持的是繼承的模式,而不支持Mixins
Mixin會(huì)存在覆蓋,比如說(shuō)兩個(gè)Mixin模塊,存在相同生命周期函數(shù)或者相同函數(shù)名的函數(shù),那么會(huì)存在相同函數(shù)的覆蓋問(wèn)題。
Mixin已經(jīng)被廢除,具體缺陷可以參考Mixins Considered Harmful
二、HOC??為了解決Mixin的缺陷,第二種解決方案是高階組件(high order component,簡(jiǎn)稱HOC)。
1、舉例幾種HOC的形式??HOC簡(jiǎn)單理解就是組件工廠,接受原始組件作為參數(shù),添加完功能與業(yè)務(wù)后,返回新的組件。下面來(lái)介紹HOC參數(shù)的幾個(gè)例子。
(1)參數(shù)僅為原始組件const redApple = withFruit(Apple);(2)參數(shù)為原始組件和一個(gè)對(duì)象
const redApple = withFruit(Apple,{color:"red",weight:"200g"});
但是這種情況比較少用,如果對(duì)象中僅僅傳遞的是屬性,其實(shí)完全可以通過(guò)組件的props實(shí)現(xiàn)值的傳遞,我們用HOC的主要目的是分離業(yè)務(wù),關(guān)于UI的展示,以及一些組件中的屬性和狀態(tài),我們一般通過(guò)props來(lái)指定比較方便
(3)參數(shù)為原始組件和一個(gè)函數(shù)const redApp=withFruit(App,()=>{console.log("I am a fruit")})(4)柯里化
最常見(jiàn)的是僅以一個(gè)原始組件作為參數(shù),但是在外層包裹了業(yè)務(wù)邏輯,比如react-redux的conect函數(shù)中:
class Admin extends React.Component{ } const mapStateToProps=(state)=>{ return { }; } const mapDispatchToProps=(dispatch)=>{ return { } } const connect(mapStateToProps,mapDispatchToProps)(Admin)2、HOC的缺點(diǎn)
HOC解決了Mixin的一些缺陷,但是HOC本身也有一些缺點(diǎn):
(1)難以溯源,且存在屬性覆蓋問(wèn)題??如果原始組件A,先后通過(guò)工廠函數(shù)1,工廠函數(shù)2,工廠函數(shù)3….構(gòu)造,最后生成了組件B,我們知道組件B中有很多與A組件不同的props,但是我們僅僅通過(guò)組件B,并不能知道哪個(gè)組件來(lái)自于哪個(gè)工廠函數(shù)。同時(shí),如果有2個(gè)工廠函數(shù)同時(shí)修改了組件A的某個(gè)同名屬性,那么會(huì)有屬性覆蓋的問(wèn)題,會(huì)使得前一個(gè)工廠函數(shù)的修改結(jié)果失效。
(2)HOC是靜態(tài)構(gòu)建的??所謂靜態(tài)構(gòu)建,也就是說(shuō)生成的是一個(gè)新的組件,并不會(huì)馬上render,HOC組件工廠是靜態(tài)構(gòu)建一個(gè)組件,這類(lèi)似于重新聲明一個(gè)組件的部分。也就是說(shuō),HOC工廠函數(shù)里面的聲明周期函數(shù),也只有在新組件被渲染的時(shí)候才會(huì)執(zhí)行。
(3)會(huì)產(chǎn)生無(wú)用的空組件 三、Render Prop??Render Props從名知義,也是一種剝離重復(fù)使用的邏輯代碼,提升組件復(fù)用性的解決方案。在被復(fù)用的組件中,通過(guò)一個(gè)名為“render”(屬性名也可以不是render,只要值是一個(gè)函數(shù)即可)的屬性,該屬性是一個(gè)函數(shù),這個(gè)函數(shù)接受一個(gè)對(duì)象并返回一個(gè)子組件,會(huì)將這個(gè)函數(shù)參數(shù)中的對(duì)象作為props傳入給新生成的組件。
??這種方法跟直接的在父組件中,將父組件中的state直接傳給子組件的區(qū)別是,通過(guò)Render Props不用寫(xiě)死子組件,可以動(dòng)態(tài)的決定父組件需要渲染哪一個(gè)子組件。
或者再概括一點(diǎn):
Render Props就是一個(gè)函數(shù),做為一個(gè)屬性被賦值給父組件,使得父組件可以根據(jù)該屬性去渲染子組件。
(1)標(biāo)準(zhǔn)父子組件通信方法??首先來(lái)看常用的在類(lèi)組件中常用的父子組件,父組件將自己的狀態(tài)state,通過(guò)props傳遞給子組件。
class Son extends React.Component{ render(){ const {feature} = this.props; returnMy hair is {feature.hair} My nose is {feature.nose}} } class FatherToSon extends React.Component{ constructor(){ this.state = { hair:"black", nose:"high" } } render(){ return} }
??我們定義了父組件FatherToSon,存在自身的state,并且將自身的state通過(guò)props的方式傳遞給了子組件。
??這種就是常見(jiàn)的利用組件的props父子間傳值的方式,這個(gè)值可以是變量,對(duì)象,也可以是方法,但是僅僅使用只能一次性的給特定的子組件使用。如果現(xiàn)在有個(gè)Daughter組件也想復(fù)用父組件中的方法或者狀態(tài),那么必須新構(gòu)建一個(gè)新組件:
class FatherToDaughter extends React.Component{ constructor(){ this.state = { hair:"black", nose:"high" } } render(){ return} }
從上面的例子可以看出通過(guò)標(biāo)準(zhǔn)模式的父子組件的通信方法,雖然能夠傳遞父組件的狀態(tài)和函數(shù),但是無(wú)法實(shí)現(xiàn)復(fù)用。
(2)Render Props的引出我們根據(jù)Render Props的特點(diǎn):
Render Props就是一個(gè)函數(shù),做為一個(gè)屬性被賦值給父組件,使得父組件可以根據(jù)該屬性去渲染子組件。
重新去實(shí)現(xiàn)上述的(1)中的例子。
class FatherChild extends React.Component{ constructor(){ this.state = { hair:"black", nose:"high" } } render(){{this.props.render} } }
此時(shí)如果子組件要復(fù)用父組件中的屬性或者函數(shù),則可以直接使用,比如子組件Son現(xiàn)在可以直接調(diào)用:
( )} />
如果子組件Daughter要復(fù)用父組件的方法,可以直接調(diào)用:
( )} />
??從這個(gè)例子中可以看出,通過(guò)Render Props我們實(shí)現(xiàn)同樣實(shí)現(xiàn)了一個(gè)組件工廠,可以實(shí)現(xiàn)業(yè)務(wù)邏輯代碼的復(fù)用,相比與HOC,Render Props有以下幾個(gè)優(yōu)點(diǎn)。
不用擔(dān)心props的命名問(wèn)題
可以溯源,子組件的props一定是來(lái)自于直接父組件
是動(dòng)態(tài)構(gòu)建的
Render Props也有一個(gè)缺點(diǎn):
就是無(wú)法利用SCU這個(gè)生命周期,來(lái)實(shí)現(xiàn)渲染性能的優(yōu)化。
四、React hooks的介紹以及如何自定義一個(gè)hooks??hooks概念在React Conf 2018被提出來(lái),并將在未來(lái)的版本中被引入,hooks遵循函數(shù)式編程的理念,主旨是在函數(shù)組件中引入類(lèi)組件中的狀態(tài)和生命周期,并且這些狀態(tài)和生命周期函數(shù)也可以被抽離,實(shí)現(xiàn)復(fù)用的同時(shí),減少函數(shù)組件的復(fù)雜性和易用性。
??hooks相關(guān)的定義還在beta中,可以在React v16.7.0-alpha中體驗(yàn),為了渲染hooks定義的函數(shù)組件,必須執(zhí)行React-dom的版本也為v16.7.0-alpha,引入hooks必須先安裝:
npm i -s [email protected] npm i -s [email protected]
??hooks主要有三部分組成,State Hooks、Effect Hooks和Custom Hooks,下面分別來(lái)一一介紹。
(1)State Hooks??跟類(lèi)組件一樣,這里的state就是狀態(tài)的含義,將state引入到函數(shù)組件中,同時(shí)類(lèi)組件中更新state的方法為setState,在State Hooks中也有相應(yīng)的更新?tīng)顟B(tài)的方法。
function ExampleWithManyStates() { // 聲明各種state以及更新相應(yīng)的state的方法 const [age, setAge] = useState(42); const [fruit, setFruit] = useState("banana"); const [todos, setTodos] = useState([{ text: "Learn Hooks" }]); // ... }
??上述就聲明了3個(gè)State hooks,相應(yīng)的方法為useState,該方法創(chuàng)建一個(gè)傳入初始值,創(chuàng)建一個(gè)state。返回一個(gè)標(biāo)識(shí)該state的變量,以及更新該state的方法。
??從上述例子我們來(lái)看,一個(gè)函數(shù)組件是可以通過(guò)useState創(chuàng)建多個(gè)state的。此外State Hooks的定義必須在函數(shù)組件的最高一級(jí),不能在嵌套,循環(huán)等語(yǔ)句中使用。
function ExampleWithManyStates() { // 聲明各種state以及更新相應(yīng)的state的方法 if(Math.random()>1){ const [age, setAge] = useState(42); const [todos, setTodos] = useState([{ text: "Learn Hooks" }]); }else{ const [fruit, setFruit] = useState("banana"); const [todos, setTodos] = useState([{ text: "Learn Hooks" }]); } // ... }
??上述的方式是不被允許的,因?yàn)橐粋€(gè)函數(shù)組件可以存在多個(gè)State Hooks,并且useState返回的是一個(gè)數(shù)組,數(shù)組的每一個(gè)元素是沒(méi)有標(biāo)識(shí)信息的,完全依靠調(diào)用useState的順序來(lái)確定哪個(gè)狀態(tài)對(duì)應(yīng)于哪個(gè)變量,所以必須保證使用useState在函數(shù)組件的最外層,此外后面要介紹的Effect Hooks的函數(shù)useEffect也必須在函數(shù)組件的最外層,之后會(huì)詳細(xì)解釋。
(2)Effect Hooks??通過(guò)State Hooks來(lái)定義組件的狀態(tài),同樣通過(guò)Effect Hooks來(lái)引入生命周期,Effect hooks通過(guò)一個(gè)useEffect的方法,以一種極為簡(jiǎn)化的方式來(lái)引入生命周期。
來(lái)看一個(gè)更新的例子:
import { useState, useEffect } from "react"; function Example() { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }); return (); }You clicked {count} times
上述就是一個(gè)通過(guò)useEffect來(lái)實(shí)現(xiàn)組件中生命周期的例子,useEffect整合了componentDidMount和componentDidUpdate,也就是說(shuō)在componentDidMount和componentDidUpdate的時(shí)候都會(huì)執(zhí)行一遍useEffect的函數(shù),此外為了實(shí)現(xiàn)componentWillUnmount這個(gè)生命周期函數(shù),useEffect函數(shù)如果返回值是一個(gè)函數(shù),這個(gè)函數(shù)就被定義成在componentWillUnmount這個(gè)周期內(nèi)執(zhí)行的函數(shù)。
useEffect(() => { //componentDidMount和componentDidUpdate周期的函數(shù)體 return ()=>{ //componentWillUnmount周期的函數(shù)體 } });
如果存在多個(gè)useState和useEffect時(shí),必須按順序書(shū)寫(xiě),定義一個(gè)useState后,緊接著就使用一個(gè)useEffect函數(shù)。
useState("Mary") useEffect(persistForm) useState("Poppins") useEffect(updateTitle)
因此通useState一樣,useEffect函數(shù)也必須位于函數(shù)組件的最高一級(jí)。
(3)Effect Hooks的補(bǔ)充上述我們知道useEffect其實(shí)包含了componentDidMount和componentDidUpdate,如果我們的方法僅僅是想在componentDidMount的時(shí)候被執(zhí)行,那么必須傳遞一個(gè)空數(shù)組作為第二個(gè)參數(shù)。
useEffect(() => { //僅在componentDidMount的時(shí)候執(zhí)行 },[]);
上述的方法會(huì)僅僅在componentDidMount,也就是函數(shù)組件第一次被渲染的時(shí)候執(zhí)行,此后及時(shí)狀態(tài)更新,也不會(huì)執(zhí)行。
此外,為了減少不必要的狀態(tài)更新和渲染,可以如下操作:
useEffect(() => { //僅在componentDidMount的時(shí)候執(zhí)行 },[stateName]);
在上述的這個(gè)例子中,只有stateName的值發(fā)生改變,才會(huì)去執(zhí)行useEffect函數(shù)。
(4)Custom Hooks自定義hooks可以將useState和useEffect的狀態(tài)和生命周期函數(shù)抽離,組成一個(gè)新的函數(shù),該函數(shù)就是一個(gè)自定義的封裝完畢的hooks。
這是我寫(xiě)的一個(gè)hooks ---> dom-location,
可以這樣引入:
npm i -s dom-location
并且可以在函數(shù)組件中使用。這個(gè)自定義的hooks也很簡(jiǎn)單,就是封裝了狀態(tài)和生命周期函數(shù)。
import { useState, useEffect } from "react" const useDomLocation = (element) => { let [elementlocation,setElementlocation] = useState(getlocation(element)); useEffect(()=>{ element.addEventListener("resize",handleResize); return ()=>{ element.removeEventListener("resize", handleResize); } },[]); function handleResize(){ setElementlocation(getlocation(element)); } function getlocation(E){ let rect = E.getBoundingClientRect() let top = document.documentElement.clientTop let left= document.documentElement.clientLeft return{ top : rect.top - top, bottom : rect.bottom - top, left : rect.left - left, right : rect.right - left }; } return elementlocation }
然后直接在函數(shù)中使用:
import useDomLocation from "dom-location"; function App() { .... let obj = useDomLocation(element); }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/114140.html
摘要:已經(jīng)被廢除,具體缺陷可以參考二為了解決的缺陷,第二種解決方案是高階組件簡(jiǎn)稱。我們定義了父組件,存在自身的,并且將自身的通過(guò)的方式傳遞給了子組件。返回一個(gè)標(biāo)識(shí)該的變量,以及更新該的方法。 ??為了實(shí)現(xiàn)分離業(yè)務(wù)邏輯代碼,實(shí)現(xiàn)組件內(nèi)部相關(guān)業(yè)務(wù)邏輯的復(fù)用,在React的迭代中針對(duì)類(lèi)組件中的代碼復(fù)用依次發(fā)布了Mixin、HOC、Render props等幾個(gè)方案。此外,針對(duì)函數(shù)組件,在Reac...
摘要:已經(jīng)被廢除,具體缺陷可以參考二為了解決的缺陷,第二種解決方案是高階組件簡(jiǎn)稱。我們定義了父組件,存在自身的,并且將自身的通過(guò)的方式傳遞給了子組件。返回一個(gè)標(biāo)識(shí)該的變量,以及更新該的方法。 ??為了實(shí)現(xiàn)分離業(yè)務(wù)邏輯代碼,實(shí)現(xiàn)組件內(nèi)部相關(guān)業(yè)務(wù)邏輯的復(fù)用,在React的迭代中針對(duì)類(lèi)組件中的代碼復(fù)用依次發(fā)布了Mixin、HOC、Render props等幾個(gè)方案。此外,針對(duì)函數(shù)組件,在Reac...
摘要:此優(yōu)化有助于避免在每個(gè)渲染上進(jìn)行昂貴的計(jì)算。同樣也是一個(gè)函數(shù),接受兩個(gè)參數(shù),第一個(gè)參數(shù)為函數(shù),第二個(gè)參數(shù)為要比對(duì)的值,返回一個(gè)值。同理,第二個(gè)參數(shù)傳入的值沒(méi)有更新時(shí),不會(huì)執(zhí)行。以上代碼的地址為初體驗(yàn) 什么是Hooks?Hooks是react即將推出的功能,它允許您在不編寫(xiě)類(lèi)的情況下使用狀態(tài)和其他React功能。我的理解就是可以用寫(xiě)無(wú)狀態(tài)組件的方式去編寫(xiě)擁有狀態(tài)的組件。遺憾的是,正式版1...
摘要:官方也陳述,接下來(lái)的的工作會(huì)投入到中。從目前官方的文檔可以看出,從以下四個(gè)方面來(lái)提高的編碼。生命周期自定義方法的主要用途是替代之前版本的組件。說(shuō)明到目前為止,在已發(fā)布的版本中有該功能,想體驗(yàn)該功能,必須安裝。 React Hooks React在16.7.0-alpha.0版本中提到了Hooks的概念,目前還是Proposal階段。 官方也陳述,接下來(lái)的90%的工作會(huì)投入到React ...
閱讀 1992·2021-11-24 09:39
閱讀 2161·2021-09-22 15:50
閱讀 2084·2021-09-22 14:57
閱讀 738·2021-07-28 00:13
閱讀 1101·2019-08-30 15:54
閱讀 2385·2019-08-30 15:52
閱讀 2715·2019-08-30 13:07
閱讀 3815·2019-08-30 11:27