深度學(xué)習(xí)React高階組件
作者:忘言
來源:SegmentFault 思否社區(qū)
混合蛋白
在了解高階組件之前我們先講一下mixin很多初級(jí)工程師對(duì)mixin的概念并不是很了解,首先解釋一下mixin
mixin:在項(xiàng)目中有些一碼相同的代碼會(huì)重復(fù)使用,我們就可以進(jìn)行抽離,方便維護(hù),為了解決這個(gè)問題就是包裝成mixin方法,但是后來發(fā)現(xiàn)有mixin有很多缺點(diǎn)端,也許可以說高階組件就是mixin的衍生品,讓我們進(jìn)入今天的主題
高階組件
高階組件:本身是一個(gè)函數(shù),這個(gè)函數(shù)接受一個(gè)組件做為參數(shù),并且返回一個(gè)組件
實(shí)現(xiàn)方式:屬性代理和反向繼承
示例:
function Hoc(WrappedComponent) {//hoc就是是個(gè)高階組件 接受一個(gè)組件做為參數(shù)return class extends Component {//返回一個(gè)組件render() {return (這是一個(gè)高階組件
)}}}
那么高階組件有什么用?
- 代碼規(guī)范
- 抽離州
- 操作道具
- 獲取實(shí)例
- 布局更改
接下來我們一個(gè)個(gè)例子查看它的好處
現(xiàn)在有一個(gè)組件ConfirmBox點(diǎn)擊按鈕后消失
class Dialog extends Component {constructor(props) {super(props);this.state = {show:true,msg:'這是一個(gè)對(duì)話框',title:'對(duì)話框'}}handleConfirm = () => {this.setState({show:!this.state.show})}render() {return ({this.state.title}
{this.state.msg}
)}}
屬性代理
現(xiàn)在我們使用高階組件把ConfirmBox組件里的state和回調(diào)函數(shù)抽離出來
屬性代理可以做什么?
- 抽離州
- 操作道具
- 獲取實(shí)例
- 布局更改
接下來對(duì)props進(jìn)行操作
function Hoc(WrappedComponent) {//hoc就是是個(gè)高階組件 接受一個(gè)組件做為參數(shù)return class extends Component {//返回一個(gè)組件constructor(props) {super(props);this.state = {show:true,msg:'這是一個(gè)對(duì)話框',title:'對(duì)話框'}}handleConfirm = () => {this.setState({show:!this.state.show})}render() {return (這是一個(gè)高階組件
)}}}class ConfirmBox extends Component {constructor(props) {super(props);}render() {return ({this.props.title}
{this.props.msg}
)}}
現(xiàn)在我們已經(jīng)把state和回調(diào)函數(shù)已經(jīng)抽離到高階組件中
function Hoc(WrappedComponent) {//hoc就是是個(gè)高階組件 接受一個(gè)組件做為參數(shù)return class extends Component {//返回一個(gè)組件constructor(props) {super(props);this.state = {show:true,msg:'這是一個(gè)對(duì)話框',title:'對(duì)話框'}}handleConfirm = () => {this.setState({show:!this.state.show})}render() {const newProps = {show:true,msg:'這是新的props'}return (這是一個(gè)高階組件
)}}}class ConfirmBox extends Component {constructor(props) {super(props);}render() {return ({this.props.title}
{this.props.msg}
)}}
到這里不知道會(huì)不會(huì)有人感覺這個(gè)和陣營(yíng)的UI和邏輯抽離很像,其實(shí)是沒錯(cuò)的,UI和業(yè)務(wù)邏輯拆分也類似,為什么那還要有高階組件呢
這里需要強(qiáng)調(diào)地點(diǎn)一下高階組件的英文函數(shù)意味著參數(shù)是動(dòng)態(tài)的這一點(diǎn)很重要,如果有兩個(gè)組件有同樣的邏輯通過高階組件只需要改變實(shí)參就可以實(shí)現(xiàn)而UI和業(yè)務(wù)邏輯分解就不行。
假設(shè):現(xiàn)在有一個(gè)ConfirmBox2和ComfirmBox1的邏輯一樣那我們直接改變參數(shù)就可以了
Hoc(ConfirmBox2)簡(jiǎn)單一行我們就把邏輯推理給了ComfirmBox2
使用高階組件相對(duì)比較靈活,這里我可能找的例子不好,請(qǐng)各位讀者見諒。通過ref訪問組件實(shí)例
{...newProps} title={this.state.title}handleConfirm={this.handleConfirm}ref={ref => this.myInstance = ref}>
這樣我們就得到了組件實(shí)習(xí)了
反向繼承(不推薦使用)
反向繼承:既然有繼承兩字肯定和extends脫不了干系,反向繼承就是通過繼承傳進(jìn)來的組件參數(shù)并且在render調(diào)用super.render實(shí)現(xiàn)的
反向繼承:可以做什么?
- 操作狀態(tài)
- 渲染劫持
最簡(jiǎn)單的例子:
function Hoc(WrappedComponent) {//hoc就是是個(gè)高階組件 接受一個(gè)組件做為參數(shù)return class extends WrappedComponent {//繼承傳進(jìn)來的組件render() {return (super.render();//調(diào)用super.render)}}}
操作state:根據(jù)狀態(tài)的show判斷是否顯示組件
function Hoc(WrappedComponent) {//hoc就是是個(gè)高階組件 接受一個(gè)組件做為參數(shù)return class extends WrappedComponent {//返回一個(gè)組件static displayName = `HOC(${WrappedComponent.displayName || WrappedComponent.name})`componentWillMount() {// 可以方便地得到state,做一些更深入的修改。this.setState({msg: '這是hoc修改的值'});}render() {return ({ super.render()})}}}
渲染劫持
function Hoc(WrappedComponent) {//hoc就是是個(gè)高階組件 接受一個(gè)組件做為參數(shù)return class extends WrappedComponent {//返回一個(gè)組件static displayName = `HOC(${WrappedComponent.displayName || WrappedComponent.name})`componentWillMount() {// 可以方便地得到state,做一些更深入的修改。this.setState({msg: '這是hoc修改的值'});}render() {if(this.state.show) {return super.render()}else {return null}}}}
反向代理:為什么不推薦使用,因?yàn)椴僮鳡顟B(tài)容易覆蓋,并且生命周期函數(shù)也會(huì)覆蓋
function Hoc(WrappedComponent) {//hoc就是是個(gè)高階組件 接受一個(gè)組件做為參數(shù)return class extends WrappedComponent {//返回一個(gè)組件static displayName = `HOC(${WrappedComponent.displayName || WrappedComponent.name})`componentWillMount() {// 可以方便地得到state,做一些更深入的修改。this.setState({msg: '這是hoc修改的值' //修改了msg的值});}componentDidMount(){console.log("hoccomponentDidMount")}render() {if(this.state.show) {return super.render()}else {return null}}}}class ConfirmBox extends Component {constructor(props) {super(props);this.state = {show:true,msg:'這是一個(gè)對(duì)話框',title:'對(duì)話框'}}handleConfirm = () => {this.setState({show:!this.state.show})}componentDidMount() {console.log("comfirmbox componentDidMount")}render() {return ({this.state.title}
{this.state.msg}
)}}
從圖片可以修剪被包裹組件的componentDidMount生命周期函數(shù)組覆蓋了,如果要調(diào)用需要使用super.componentDidMount去調(diào)用,而且狀態(tài)也被覆蓋了另外,最重要的一點(diǎn)反向繼承不能保證子組件完全被渲染,這是什么意思?就是被包裹組件里的可能會(huì)丟失。
高階組件使用場(chǎng)景
頁面渲染
function Hoc(WrappedComponent) {//hoc就是是個(gè)高階組件 接受一個(gè)組件做為參數(shù)return class Test extends Component {//返回一個(gè)組件static displayName = `HOC(${WrappedComponent.displayName || WrappedComponent.name})`constructor(props) {super(props);this.state = {show:true,msg:'這是一個(gè)對(duì)話框',title:'對(duì)話框'}}handleConfirm = () => {this.setState({show:!this.state.show})}componentDidMount() {console.log(this.myInstance)}render() {const newProps = {show:true,msg:'這是新的props'}if(this.state.show) {return{...newProps} title={this.state.title}handleConfirm={this.handleConfirm}ref={ref => this.myInstance = ref}>}else {return null}}}}
邏輯復(fù)用:現(xiàn)在假設(shè)有兩個(gè)確認(rèn)框組件,他們的邏輯一樣,只有樣式不同,那我們就可以使用高階組件來實(shí)現(xiàn)
import React,{Component} from 'react'import './Hoc.css'function Hoc(WrappedComponent) {//hoc就是是個(gè)高階組件 接受一個(gè)組件做為參數(shù)return class Test extends Component {//返回一個(gè)組件static displayName = `HOC(${WrappedComponent.displayName || WrappedComponent.name})`constructor(props) {super(props);this.state = {show:true,msg:'這是一個(gè)對(duì)話框',title:'對(duì)話框'}}handleConfirm = () => {this.setState({show:!this.state.show})}componentDidMount() {console.log(this.myInstance)}render() {const newProps = {show:true,msg:'這是新的props'}if(this.state.show) {return{...newProps} title={this.state.title}handleConfirm={this.handleConfirm}ref={ref => this.myInstance = ref}>}else {return null}}}}class ConfirmBox extends Component {constructor(props) {super(props);}render() {return ({this.props.title}
{this.props.msg}
)}}class ConfirmBox2 extends Component {constructor(props) {super(props);}render() {return ({this.props.title}{this.props.msg}
)}}export default {comfirmBox:Hoc(ConfirmBox),comfirmBox2:Hoc(ConfirmBox2)}


可以拋光組件只是樣式不同,邏輯相同我們就可以使用高階組件來實(shí)現(xiàn)邏輯替換
點(diǎn)擊左下角閱讀原文,到?SegmentFault 思否社區(qū)?和文章作者展開更多互動(dòng)和交流。
-?END -

