最近開始搞搞Taro陋守,發(fā)現(xiàn)Taro當中好像沒有mixin耶o(╥﹏╥)o,于是我開始去查閱文檔捅膘,發(fā)現(xiàn)react在瘋狂地diss mixin翘地,原諒我才疏學淺申尤,mixin在我看來只是命名沖突會有點煩,但盡量避免的話用起來還是很爽的衙耕。(可能沒有經(jīng)歷過大項目吧)
那么昧穿,對于我們小項目就是想用mixin咋辦?react就瘋狂地給我們安利高階組件(hoc)了臭杰。我們照著官網(wǎng)寫個示例:
// withTest.js
import { Component } from '@tarojs/taro'
function withTest(Comp) {
return class extends Component {
render() {
return <Comp />
}
}
}
// A.js
import withTest from '../withTest'
@withTest
class A extends Component {}
export default A
在react環(huán)境里用hoc完全沒問題粤咪,但是Taro環(huán)境就不一樣了,它直接不調(diào)用hoc里返回class的render方法了渴杆,甚至還給你報了個錯寥枝!
解決這個報錯呢,可以這樣:
function withTest(Comp) {
return class extends Comp {
render() {
return <Comp />
}
}
}
雖說這樣解決了報錯磁奖,但render方法它始終不肯執(zhí)行囊拜,其他的生命周期諸如componentWillMount等會執(zhí)行。于是我去看了隔壁redux的connect源碼比搭,畢竟人家可以注入props到組件冠跷,人家也是高階組件,要向它學習:
// 摘要代碼
return class Connect extends Component {
constructor (props, isPage) {
super(Object.assign(...arguments, mergeObjects(mapStateToProps(store.getState(), props), initMapDispatch)), isPage)
Object.keys(initMapDispatch).forEach(key => {
this[`__event_${key}`] = initMapDispatch[key]
})
}
_constructor () {
if (!this.$scope) {
if (super._constructor) {
super._constructor(this.props)
}
return
}
const store = getStore()
Object.assign(this.props, mergeObjects(mapStateToProps(store.getState(), this.props), initMapDispatch))
unSubscribe = store.subscribe(stateListener.bind(this))
if (super._constructor) {
super._constructor(this.props)
}
}
componentWillUnmount () {
if (super.componentWillUnmount) {
super.componentWillUnmount()
}
if (unSubscribe) {
unSubscribe()
}
unSubscribe = null
}
}
什么嘛身诺,原來connect根本就沒有調(diào)render嘛蜜托,那么我們也不要去糾結于render方法了,干就完了霉赡。
披著高階組件的外衣橄务,mixin來了!
用法一(直接在類里寫方法)
// withTest.js
function withTest(Comp) {
return class extends Comp {
a() { console.log('a'); }
b() {
this.a();
console.log('b');
}
}
}
// A.js
@withTest
class A extends Component {
componentWillMount() {
this.b();
// a
// b
}
}
用法二(state)
// 借助一個深拷貝對象的方法
const mergeObjects = function(obj1, obj2) {
const result = Object.assign({}, obj1);
if (isObject(obj1) && isObject(obj2)) {
for (const p in obj2) {
if (isObject(obj1[p]) && isObject(obj2[p])) {
result[p] = mergeObjects(obj1[p], obj2[p]);
} else {
result[p] = obj2[p];
}
}
}
return result;
};
// withTest.js
function withTest(Comp) {
return class extends Comp {
constructor(props) {
super(props);
this.state = mergeObjects(this.state, { a: 1 });
}
changeA(fn) {
this.setState({ a: 2 }, () => fn && fn());
}
}
}
// A.js
@withTest
class A extends Component {
constructor(props) {
super(props);
this.state = { a: 10, b: 2 };
}
componentWillMount() {
this.changeA(() => console.log(this.state));
// a: 2
// b: 2
}
}