高階函式HOF和高階元件HOC(Higher Order Func/Comp)
阿新 • • 發佈:2020-01-05
一、什麼是高階函式(元件),作用是什麼?
子類使用父類的方法可以通過繼承的方式實現,那無關聯元件通訊(redux)、父類使用子類方法(反向繼承)呢
為了解決類(函式)功能交叉/功能複用等問題,通過傳入類/函式返回類/函式(繼承)的方式使得類擁有自身未定義的方法。
例如react-redux
的connect方法使用了高階元件:
React Redux
的connect:
const HOC = connnect(mapStateToProps)(Comp); // connect為柯里化函式 實際為 => function connect(mapStateToProps) { // ... return function(Comp) { // ... } } // 使用箭頭函式則為 const connect = mapStateToProps => Comp => {...};
二、通過高階函式實現兩個無關函式的通訊
需求介紹
存在一個類SubClass
(子類),該類範圍內有資料state
物件,且有setState和getState
兩個函式方法。現在希望通過SupClass1
(超/父類1)去呼叫SubClass
(子類)的setState
方法,並在SupClass2
(超/父類2)裡通過getState
方法輸出結果。
注意,子為sub,父為sup
檔案目錄
├ ├── SubClass.js # 子類 ├ ├── SupClass1.js # 父類1 ├ ├── SupClass2.js # 父類2 ├── index.html
給SubClass
類增加資料state,並賦予查詢和修改的能力
// SubClass.js class SubClass { constructor(args = {}) { this.state = { ...args, }; } // 賦值時需要提供鍵和值 setState = (key, val) => { this.state = { [key]: val, }; }; getState = (key) => { if (key in this.state) { return this.state[key]; } // 當然我們希望嚴謹點 const err = '無效key值'; throw err; }; }
我們試試SubClass
功能如何
// index.html
const subcls = new SubClass({name: 'xiaobe'});
const res = subCls.getState('name');
console.log('res', res);
// 輸出xiaobe,妥妥的
接下來我們給SupClass1
賦予setState
的能力
class SuperClass1 {
set(key, val) {
// SuperClass1裡沒有setState方法!
this.setState(key, val);
}
}
如果直接執行類裡的get
方法肯定是會出錯的。所以我們需要先對SupClass1
做點事情。
需要給SuperClass1
類裡增加方法setState
,可以使用繼承
// SuperClass1.js
class SuperClass1 extends SubClass {
constructor(props) {
super(props);
}
set(key, val) {
// 父類1上使用子類的setState方法
this.setState(key, val);
}
}
// index.html
const supCls1 = new SuperClass1({name: 'sup-xiaobe'});
const res = supCls1.getState('name');
console.log(res);
// 也能輸出sup-xiaobe
但如果單純使用繼承的方式會造成很多的麻煩。例如子類和父類如果有同名方法,預設子類會覆蓋基類(父類的其他叫法)的同名方法,如果基類方法使用了函式繫結或箭頭函式,其this
的指向就改變了,指向了基類,導致自身同名方法失效。
因此我們還是需要通過高階元件實現;
首先我們先給子類SubClass
增加一個HOC入口
class SubClass {
// ...
HOC(cls) {
// 需要呼叫SubClass類的方法,所以需要存一份其this
const sub_this = this;
// 父類除了以下新增的兩個方法,其他無任何變化地返回!
return class extends cls {
constructor(props) {
super(props);
// 此處this指向該子類,sub_this指向SubClass類
this.getState = sub_this.getState;
this.setState = sub_this.setState;
}
}
}
// ...
}
接著我們來父類1SupClass1
例項化前升級(呼叫HOC)!
// index.html
const subCls = new SubClass();
// 在子類例項化後給父類加上HOC方法
const supClsHoc1 = subCls.HOC(SuperClass1);
// 例項化父類
const supCls1 = new supClsHoc1();
// 重新定義state.name
supCls1.set('name', 'sup-xiaobe');
console.log(supCls.getState('name'));
// 輸出sup-xiaobe
同理地完成SupClass2
// SupClass2.js
class SuperClass2 {
get(key) {
return this.getState(key);
}
}
// 最終的index.html
const subCls = new SubClass({name: 'xiaobe'});
const supClsHoc1 = subCls.HOC(SuperClass1);
const supClsHoc2 = subCls.HOC(SuperClass2);
const supCls1 = new supClsHoc1();
const supCls2 = new supClsHoc2();
supCls1.set('name', 'sup-xiaobe');
const res = supCls2.get('name');
console.log('res', res);
這麼一個基礎簡單的元件通訊就完成了。
根據這個思路可以封裝一個類似全域性變數的Store.js
思考個問題