React高階元件替代Mixins
minins將死,ES6的Class不對其進行支援,HOC就是解決辦法。
那什麼是高階元件?首先你得先了解請求ES6中的class
只是語法糖
,本質還是原型繼承
。能夠更好的進行說明,我們將不會修改元件
的程式碼。而是透過提供一些能夠包裹元件
的元件
, 並透過一些額外的功能來增強元件
。這樣的元件
我們稱之為高階元件(Higher-Order Component)。
ES7中的新特性decorator(裝飾器)
就是使用高階元件模式,transform-decorators-legacy
是目前babel外掛轉換decorator
的,可以研究下。下面看下如何實現React的PureRender功能(高階元件和decorator一起講解)。
PureRenderDecorator
,decorator其實就是一個高階元件。
import _ from 'lodash';
function shallowEqual(objA, objB) {
if (objA === objB) {
return true;
}
if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
return false;
}
const keysA = Object.keys(objA);
const keysB = Object.keys(objB);
if (keysA.length !== keysB.length) {
return false;
}
const bHasOwnProperty = hasOwnProperty.bind(objB);
for (let i = 0; i < keysA.length; i++) {
const keyA = keysA[i];
if (objA[keyA] === objB[keyA]) {
continue;
}
// special diff with Array or Object
if (_.isArray(objA[keyA])) {
if (!_.isArray(objB[keyA]) || objA[keyA].length !== objB[keyA].length) {
return false;
} else if (!_.isEqual(objA[keyA], objB[keyA])) {
return false;
}
} else if (_.isPlainObject(objA[keyA])) {
if (!_.isPlainObject(objB[keyA]) || !_.isEqual(objA[keyA], objB[keyA])) {
return false;
}
} else if (!bHasOwnProperty(keysA[i]) || objA[keysA[i]] !== objB[keysA[i]]) {
return false;
}
}
return true;
}
function shallowCompare(instance, nextProps, nextState) {
return !shallowEqual(instance.props, nextProps) || !shallowEqual(instance.state, nextState);
}
function shouldComponentUpdate(nextProps, nextState) {
return shallowCompare(this, nextProps, nextState);
}
/* eslint-disable no-param-reassign */
function pureRenderDecorator(component) {
//覆蓋了component中的shouldComponentUpdate方法
component.prototype.shouldComponentUpdate = shouldComponentUpdate;
return component;//Decorator不用返回,直接使用高階元件需要return
}
/*****
*使用ES6 class 語法糖如下,decorator的沒試過,decorator請使用上面的,不要return
*let pureRenderDecorator = component => class {
* constructor(props) {
* super(props);
* component.prototype.shouldComponentUpdate = shouldComponentUpdate;
* }
* render(){
* var Component = component;//自定義元件使用時要大寫
* return (
* <Component {...this.props}/>
* )
* }
*}
******/
export { shallowEqual };
export default pureRenderDecorator;
如何使用?假設要使用的元件是Test
-
直接使用
import React from 'react'; import { pureRenderDecorator } from "./pureRenderDecorator"; class Test extends React.Component { // component code here } export default pureRenderDecorator(Test)
-
透過
decorator
import React from 'react'; import { pureRenderDecorator } from "./pureRenderDecorator"; @pureRenderDecorator export default class Test extends React.Component { // component code here }