一、mixin
什么是mixin:創(chuàng)造一種類似多重繼承的效果芭商。事實(shí)上语盈,說(shuō)它是組合更為貼切。
1.封裝mixin方法實(shí)例:
const mixin = function(obj,mixins){
????const newObj = obj;
????newObj.prototype = Object.create(obj.prototype);
????for(let prop in mixins){
????????if(mixins.hasOwnProperty(prop)){
????????????newObj.prototype[prop] = mixins[prop];
????????}
????}
????return newObj;
}
const BigMixin = {
????fly:()=>{
????????console.log('I can fly');
????}
}
const Big = function(){
????console.log('new big');
}
const FlyBig = mixin(Big,BigMixin); // new big
const flyBig = new FlyBig(); // I can fly?
對(duì)于廣義的mixin方法赘方,就是用賦值的方式將mixin對(duì)象里的方法都掛載到原對(duì)象上烧颖,來(lái)實(shí)現(xiàn)對(duì)象的混入。
2.在React中使用mixin
React在使用createClass構(gòu)建組件時(shí)提供了mixin屬性窄陡。(ES6 classes形式構(gòu)建組件時(shí)炕淮,不支持mixin)
實(shí)例:
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin'; //官方封裝的mixin對(duì)象
React.creatClass({
? ? mixins:[PureRenderMixin],? ? reder(){
? ? ? ? return <div>foo</div>;
????}? ??
});
注:mixins屬性可以指定多個(gè)mixin。但跳夭,如果兩個(gè)mixin(也就是兩個(gè)對(duì)象)中有名稱相同的方法涂圆,會(huì)報(bào)命名沖突錯(cuò)誤。
使用createClass實(shí)現(xiàn)的mixin可以為組件做兩件事:
(1)定義工具方法币叹。用mixin混入寫(xiě)好的工具方法润歉。在需要用到工具方法的組件中設(shè)置mixin,即可使用相應(yīng)工具方法颈抚。
(2)生命周期繼承踩衩,props、state的合并贩汉。如果多個(gè)mixin對(duì)象中驱富,都定義了同一個(gè)生命周期,react會(huì)智能地將它們合并起來(lái)執(zhí)行雾鬼。
3.ES6 Classes 與 decorator
es6 classes語(yǔ)法萌朱,用decorator實(shí)現(xiàn)mixin。
注:decorator與Java中pre-defined annotation的區(qū)別是策菜,decorator是運(yùn)用在運(yùn)行時(shí)的方法晶疼。
4.mixin存在的問(wèn)題
(1)破壞了原有組件的封裝酒贬。
? ? mixin中的方法會(huì)帶來(lái)新的state和props,及其他未知操作翠霍,在使用組件中不可知锭吨,無(wú)法有目的地控制。
(2)命名沖突寒匙。
? ? 多個(gè)mixin中零如,或mixin與當(dāng)前組件,可能存在相同命名的方法锄弱,從而命名沖突考蕾。
(3)增加復(fù)雜性。
? ? 當(dāng)添加了越來(lái)越多的mixin会宪,就會(huì)引入越來(lái)越多的方法肖卧,從而造成代碼邏輯復(fù)雜,不易維護(hù)掸鹅。
二塞帐、高階組件
1.高階函數(shù):
概念:接受函數(shù)作為輸入,或是輸出一個(gè)函數(shù)巍沙,的函數(shù)葵姥。
如常用的map、reduce句携、sort等榔幸,都是高階函數(shù)。
2.高階組件
概念:類似于高階函數(shù)务甥。接受React組件作為輸入牡辽,輸出一個(gè)新的React組件。
實(shí)現(xiàn)方法:
(1)屬性代理:高階組件通過(guò)被包裹的React組件來(lái)操作props敞临。
定義高階組件:
import React,{Component} from 'React';
const MyContainer = (WrappedComponent) =>
? ? class extends Component {
? ? ? ? render() {
? ? ? ? ? ? return <WrappedComponent {...this.props} />;
????????}
????}
高階組件:MyContainer
被包裹組件:WrappedComponent
{...this.props}是WrappedComponent的props對(duì)象态辛。除了原封不動(dòng)傳遞WrappedComponent的props,在高階組件中挺尿,可以設(shè)置其他props奏黑,并傳遞給WrappedComponent。例如:
import React,{Component} from 'React';
const MyContainer = (WrappedComponent) =>? ?
????class extends Component {? ? ? ?
????????render() {?
? ? ? ? ? ? ?const newProps = {
? ? ? ? ? ? ? ? ?text:newText,? ? ? ?
? ? ? ? ? ? ?};? ? ? ? ?
????????????return ?<WrappedComponent {...this.props} {...newProps} />;? ??
?//注:this.props讀取的是编矾,調(diào)用WrappedComponent時(shí)傳入的props熟史。注意{...this.props}和{...newProps}書(shū)寫(xiě)的先后順序。如果this.props和newProps中有相同的prop窄俏,后面的會(huì)覆蓋前面的蹂匹。
?????}???
?}
對(duì)于WrappedComponent來(lái)說(shuō),只要套用這個(gè)高階組件凹蜈,我們的新組件中就會(huì)多一個(gè)text的prop限寞。
使用高階組件:
import React,{Component} from 'React';
class MyComponent extends Component{
? ? //......
}
export default MyContainer(MyComponent);
或
import React,{Component} from 'React';
@MyContainer
class MyComponent extends Component{? ?
? ? render(){ }
}
export default?MyComponent;
生命周期執(zhí)行過(guò)程(類似于堆棧調(diào)用):
didmount -> HOC didmount -> (HOCs didmount) ->?
(HOCs will unmount) -> HOC will unmount -> unmount
(2)反向繼承:高階組件繼承于被包裹的React組件忍啸。
定義高階組件:
const MyContainer = (WrappedComponent) =>
? ? class extends WrappedComponent {
? ? ? ? render(){
? ? ? ? ? ? return super.render();
????????}
? ? }
HOC調(diào)用順序(類似于隊(duì)列):
didmount -> HOC didmount => (HOCs didmount) ->?
will unmount -> HOC will unmount -> (HOCs will unmount)
渲染劫持示例:
NO1:條件渲染
const MyContainer = (WrappedComponent) =>
????class extends WrappedComponent {
? ? ? ? render(){
? ? ? ? ? ? if(this.props.loggedIn){
? ? ? ? ? ? ? ? return super.render();
????????????}else{
? ? ? ? ? ? ? ? return null;
????????????}
????????}
????}
NO2:修改render輸出結(jié)果
const MyContainer = (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;
????????}
????}