前言
創(chuàng)新互聯(lián)建站長期為成百上千客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊從業(yè)經(jīng)驗10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為田林企業(yè)提供專業(yè)的成都網(wǎng)站設(shè)計、成都做網(wǎng)站、外貿(mào)網(wǎng)站建設(shè),田林網(wǎng)站改版等技術(shù)服務(wù)。擁有十載豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。
在最近做的一個react項目中,遇到了一個比較典型的需要重構(gòu)的場景:提取兩個組件中共同的部分。
最開始通過使用嵌套組件和繼承的方式完成了這次重構(gòu)。
但是后來又用高階組件重新寫了一遍,發(fā)現(xiàn)更好一點。
在這里記錄下這兩種方式以便之后參考和演進(jìn)。
本次重構(gòu)的場景
因為場景涉及到具體的業(yè)務(wù),所以我現(xiàn)在將它簡化為一個簡單的場景。
現(xiàn)在有兩個黑色箱子,箱子上都有一個紅色按鈕,A箱子充滿氣體,按了按鈕之后箱子里面氣體變紅,B箱子充滿泥土,按了之后箱子里面泥土變紅。
那么現(xiàn)在上一個簡單的重構(gòu)前代碼:
BoxA.jsx
import React, { Component, PropTypes } from 'react' class BoxA extends Component { state={ color:'black' } handleClick=()=>{ this.setState({ color:'red' }) } handleShake=()=>{ /* 搖動后氣體沒聲音 */ } render() { return ( /* 這里面當(dāng)然沒有onShake這種事件,理解意思就行了 */ <div style={{backgroundColor:'black'}} onShake={this.handleShake}> <button onClick={this.handleClick} style={{backgroundColor:'red'}}></button> <div> /* 氣體組件,沒毛病 */ <氣體 color={this.state.color} /> </div> </div> ) } }
BoxB.jsx
import React, { Component, PropTypes } from 'react' class BoxB extends Component { state={ color:'black' } handleClick=()=>{ this.setState({ color:'red' }) } handleShake=()=>{ /* 搖動后泥土有聲音 */ } render() { return ( <div style={{backgroundColor:'black'}} onShake={this.handleShake}> <button onClick={this.handleClick} style={{backgroundColor:'red'}}></button> <div> <泥土 color={this.state.color} /> </div> </div> ) } }
使用嵌套組件進(jìn)行重構(gòu)
看看上面的代碼,即使在業(yè)務(wù)簡化的情況下都有很多重復(fù)的,所以得重構(gòu)。
對于這種很明顯的箱子類問題,一般都會采用嵌套組件的方式重構(gòu)。
Box.jsx
import React, { Component, PropTypes } from 'react' class Box extends Component { static propTypes = { children: PropTypes.node, onClick: PropTypes.func, onShake: PropTypes.func } render() { return ( <div style={{backgroundColor:'black'}} onShake={this.props.onShake}> <button onClick={this.props.onClick} style={{backgroundColor:'red'}}></button> <div> {this.children} </div> </div> ) } }
BoxA.jsx
import React, { Component, PropTypes } from 'react' import Box from './Box.jsx' class BoxA extends Component { state={ color:'black' } handleClick=()=>{ this.setState({ color:'red' }) } handleShake=()=>{ /* 搖動后氣體沒聲音 */ } render() { return ( <Box onClick={this.handleClick} onShake={this.props.handleShake}> <氣體 color={this.state.color} /> </Box> ) } }
BoxB.jsx
import React, { Component, PropTypes } from 'react' class BoxB extends Component { state={ color:'black' } handleClick=()=>{ this.setState({ color:'red' }) } handleShake=()=>{ /* 搖動后泥土有聲音 */ } render() { return ( <Box onClick={this.handleClick} onShake={this.props.handleShake}> <泥土 color={this.state.color} /> </Box> ) } }
使用繼承組件的方式進(jìn)行重構(gòu)
對于很多場景而言,使用了嵌套組件后,可能就不需要或者沒法進(jìn)一步進(jìn)行組件提煉了。
然而完成這波操作后,我們發(fā)現(xiàn)嵌套組件BoxA和BoxB依然存在重復(fù)代碼,即按下按鈕變紅這部分代碼。
這部分代碼可以使用嵌套組件與被嵌套組件的通信機(jī)制來處理,技術(shù)上而言依然可以將這部分代碼用嵌套組件的方式來解決。
但是為了保證組件的單一職責(zé),即箱子就是個帶紅色按鈕可以搖動的箱子,我們不知道里面以后會放什么進(jìn)去,就不能說不管以后里面放什么,只要我一按紅色按鈕,里面的物質(zhì)都會變紅。
這部分代碼肯定是不能放在嵌套組件Box里,因為它直接操作著被嵌套的內(nèi)容。
那么在這里我們可以使用繼承組件的方式。
Box.jsx
import React, { Component, PropTypes } from 'react' class Box extends Component { static propTypes = { children: PropTypes.node, onClick: PropTypes.func, onShake: PropTypes.func } render() { return ( <div style={{backgroundColor:'black'}} onShake={this.props.onShake}> <button onClick={this.props.onClick} style={{backgroundColor:'red'}}></button> <div> {this.children} </div> </div> ) } }
BasicBox.jsx
import React, { Component, PropTypes } from 'react' class BasicBox extends Component { state={ color:'black' } handleClick=()=>{ this.setState({ color:'red' }) } }
BoxA.jsx
import React, { Component, PropTypes } from 'react' import Box from './Box.jsx' class BoxA extends BasicBox { handleShake=()=>{ /* 搖動后氣體沒聲音 */ } render() { return ( <Box onClick={this.handleClick} onShake={this.props.handleShake}> <氣體 color={this.state.color} /> </Box> ) } }
BoxB.jsx
import React, { Component, PropTypes } from 'react' class BoxB extends BasicBox { handleShake=()=>{ /* 搖動后泥土有聲音 */ } render() { return ( <Box onClick={this.handleClick} onShake={this.props.handleShake}> <泥土 color={this.state.color} /> </Box> ) } }
通過修改后的代碼,就可以將BoxA和BoxB中相同的部分提取到BasicBox中。
這樣我們相當(dāng)于將一個功能塊提取了出來,你可以繼承BasicBox(這個命名可能不好,容易引起混淆),如果不使用state的值也完全沒有任何問題。
但是這樣做也許會帶了一些別的問題。
我們自己去看這段代碼的時候其實不難理解,不過之后讓其他人對這塊代碼做修改時,后來的人就會感到奇怪,BoxA中突然間使用了一個不知道從哪里來的handleClick。
使用高階組件進(jìn)行重構(gòu)
為了解決上面的問題,后來又使用高階組件的方式玩了一遍:
hocBox.jsx
import React, { Component, PropTypes } from 'react' hocBox=(WrappedComponent)=>{ return class Box extends Component{ static propTypes = { onShake: PropTypes.func } state={ color:'black' } handleClick=()=>{ this.setState({ color:'red' }) } render() { return ( <div style={{backgroundColor:'black'}} onShake={this.props.handleShake}> <button onClick={this.handleClick} style={{backgroundColor:'red'}}></button> <div> <WrappedComponent color={this.state.color} /> </div> </div> ) } } }
BoxA.jsx
import React, { Component, PropTypes } from 'react' import Box from './hocBox.jsx' const 氣體WithBtnBox=hocBox(氣體) class BoxA extends BasicBox { handleShake=()=>{ /* 搖動后氣體沒聲音 */ } render() { return ( <氣體WithBtnBox onShake={this.handleShake} /> ) } }
BoxB.jsx
import React, { Component, PropTypes } from 'react' import Box from './hocBox.jsx' const 泥土WithBtnBox=hocBox(泥土) class BoxA extends BasicBox { handleShake=()=>{ /* 搖動后泥土有聲音 */ } render() { return ( <泥土WithBtnBox onShake={this.handleShake} /> ) } }
高階組件的使用就像設(shè)計模式中的裝飾者模式(Decorator Pattern)。
總結(jié)
以上的兩種方式中,高階組件的方式對于后來者在修改上更友好一點。
但是用嵌套+繼承的方式理解起來其實更容易一點,特別是去重構(gòu)一個復(fù)雜的組件時,通過這種方式往往更快,拆分起來更容易。(我個人更傾向于這種,不知道是不是C#玩多了,更喜歡這樣的玩法,而對高階組件這種方式總是感覺很奇怪)
本篇文章算是自己的一次重構(gòu)筆記吧,寫的只是個人的一點理解,如果有更好的辦法或者疏漏的地方歡迎批評指正。
好了,以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對創(chuàng)新互聯(lián)的支持。
網(wǎng)頁名稱:React組件重構(gòu)之嵌套+繼承及高階組件詳解
網(wǎng)頁鏈接:http://muchs.cn/article44/gedche.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供軟件開發(fā)、網(wǎng)站導(dǎo)航、網(wǎng)站設(shè)計公司、網(wǎng)站制作、企業(yè)網(wǎng)站制作、網(wǎng)站策劃
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)