項目初期只有一個添加商品模塊,因業務迭代,從多圖商品中分離出視頻商品,當前存在的問題:html
鑑於以上問題,尋找的解決方案有:react
公共邏輯抽離方案,公共邏輯中包含了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)
組件傳參基本都幹過
const HOC = (WrappedComponent) => { return class extends Component { render() { return <WrappedComponent ref={this.onRef} {...this.props}/> } } }
基本上都這個幹過,使用組件實例方法。
上代碼
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,什麼鬼,直到看到這樣一段代碼:
//該例子來源於 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的可行性方案,就是高階組件的反向繼承。
目前研究學習並實踐的內容就到這裏了,若是後續有補充的,也會持續更新。