高階組件

首次使用場景

項目初期只有一個添加商品模塊,因業務迭代,從多圖商品中分離出視頻商品,當前存在的問題:html

  1. 版本迭代勢必勢必同時修改兩個模塊;
  2. 大量邏輯,方法重複。

方案篩選

鑑於以上問題,尋找的解決方案有:react

  1. 公共邏輯代碼抽離;
  2. 公共容器組件抽離;
  3. Mixin;
  4. 高階組件。

公共邏輯抽離方案,公共邏輯中包含了state、props、以及setState,若是提取公共邏輯代碼,勢必從新處理相關狀態,對原有模塊破壞性大。es6

公共容器組件方案,合併兩個模塊公共部分,把上傳部分分離成多圖上傳組件,視頻上傳組件,經過傳入參數區分類型,也就意味着合併路由名稱,添加參數區分,修改爲本高。redux

Mixin方案,但其方案存在缺陷。詳情,看這裏app

最後能選擇的最優方案就是高階組件,侵入性小,函數式思想(一樣的輸入,返回一樣的輸出、可預測性強),ide

概念介紹

高階函數

其知足高階函數的至少兩個條件:函數

  • 接受一個或多個函數做爲輸入
  • 輸出一個函數

高階組件

定義:類比高階函數的定義,高階組件就是接受一個組件做爲參數,在函數中對組件作一系列的處理,隨後返回一個新的組件做爲返回值。學習

高階組件解讀

示例1 (屬性代理模式)this

const HOC = (WrappedComponent) => {
  return class extends Component {
    render() {
      return <WrappedComponent {...this.props}/>
    }
  }
}

示例2 (反向繼承模式)代理

const HOC = (WrappedComponent) => {
  return class extends WrappedComponent {
    render() {
      return super.render();
    }
  }
}

what? 屬性代理、反向繼承,繼承就算了,怎麼還反向繼承,別急放下看

屬性代理

簡單講就是包裹組件,操做props,基本上組件嵌套、傳參什麼的都幹過。

上代碼

const HOC = (WrappedComponent) => {
  return class extends Component {
    render() {
      return <WrappedComponent {...this.props}/>
    }
  }
}

class WrappedComponent extends Component{
    render(){
        //....
    }
}

//高階組件使用
export default HOC(WrappedComponent)

屬性操做

上代碼

const HOC = (WrappedComponent) => {
  return class extends Component {
    render() {
        const newProps = {
            name: "HOC"
        }
      return <WrappedComponent {...this.props} {...newProps}/>
    }
  }
}

class WrappedComponent extends Component{
    render(){
        //....
    }
}

//高階組件使用
export default HOC(WrappedComponent)

組件傳參基本都幹過

refs引用

const HOC = (WrappedComponent) => {
  return class extends Component {
    render() {
      return <WrappedComponent ref={this.onRef} {...this.props}/>
    }
  }
}

基本上都這個幹過,使用組件實例方法。

抽象State

上代碼

const HOC = (WrappedComponent) => {
  return class extends Component {
      onChange = (data = {}) => {
          this.setState(data)
      }
    render() {
        const {name = ''} = this.state;
        const newProps = {
            name: {
                value: name,
                onChange: (e)=>this.onChange({name: e.target.value})
            }
        }
        return <WrappedComponent {...this.props} {...newProps}/>
    }
  }
}

class WrappedComponent extends Component{
    render(){
        const {name} = this.props;
       return <input {...name} />
    }
}

//高階組件使用
export default HOC(WrappedComponent)

細細品味上面寫法的精髓,當你須要操做大量表單的時候,會發現它的好。

剛開始沒理解抽象State的含義,經過寫筆記搞明白了,就是把須要在原組件,經過state動態賦值的操做,抽象到高階組件中經過props傳值。

總結: 屬性代理的模式,跟日常寫組件的模式差很少,只不過加了些技巧。

反向繼承

再看看上面的示例

const HOC = (WrappedComponent) => {
  return class extends WrappedComponent {
    render() {
      return super.render();
    }
  }
}

super.render()這種模式只在es6類繼承的時候經過super.method(),用在這裏實在是妙。

從寫法上看,繼承了傳入組件,使用super.render()天然是執行了傳入組件的render方法,也就是渲染了傳入組件對應的頁面,有趣的事情開始了。

操做state以及props。

操做state,我理解,但操做props,什麼鬼,直到看到這樣一段代碼:

//該例子來源於 React 高階組件(HOC)入門指南 掘金
const HOCFactoryFactory = (...params) => {
    // 能夠作一些改變 params 的事
    return (WrappedComponent) => {
        return class HOC extends Component {
            render() {
                return <WrappedComponent {...this.props} />;
            }
        }
    }
}

HOCFactoryFactory(params)(WrappedComponent)

//相似場景 redux
connect(params)(Index)

又明白了。

渲染劫持

別人寫的代碼

//例子來源於《深刻React技術棧》

const HOC = (WrappedComponent) =>
    class extends WrappedComponent {
        render() {
            const elementsTree = super.render();
            let newProps = {};
            if (elementsTree && elementsTree.type === 'input') {
                newProps = {value: 'may the force be with you'};
            }
            const props = Object.assign({}, elementsTree.props, newProps);
            const newElementsTree = React.cloneElement(elementsTree, props, elementsTree.props.children);
            return newElementsTree;
    }
}
class WrappedComponent extends Component{
    render(){
        return(
            <input value={'Hello World'} />
        )
    }
}
export default HOC(WrappedComponent)

跟操做DOM差很少(我的理解),目前沒有用到這個的場景,不作贅述。

高階組件基本使用場景介紹完了,回到正題,聊聊,我在實際項目中是怎麼用的。

說幾個數據:

改造模塊前

多圖商品模塊代碼,900行。視頻商品模塊代碼,1000行

改造模塊後

多圖商品模塊代碼,554行。視頻商品模塊代碼,650行

抽離出的高階組件代碼 387行

當前水平只能到這一步了。

我採用了反向繼承的方案,屬性代理,只能知足操做props,但不能操做state,你們或許會有疑問,人家不是能夠抽象state,是的,瞅清楚,是抽象不是操做。

還有就是沒辦法屬性代理沒辦法使用原組件靜態方法。大神提供了批量複製靜態方法的庫hoist-non-react-statics

最終知足我操做props,尤爲是操做state的可行性方案,就是高階組件的反向繼承。

目前研究學習並實踐的內容就到這裏了,若是後續有補充的,也會持續更新。

相關文章
相關標籤/搜索