一、mixin
什么是mixin:创造一种类似多重继承的效果。事实上,说它是组合更为贴切。
1.封装mixin方法实例:
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
对于广义的mixin方法,就是用赋值的方式将mixin对象里的方法都挂载到原对象上,来实现对象的混入。
2.在React中使用mixin
React在使用createClass构建组件时提供了mixin属性。(ES6 classes形式构建组件时,不支持mixin)
实例:
import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin'; //官方封装的mixin对象
React.creatClass({
mixins:[PureRenderMixin],reder(){
return <div>foo</div>;
}
});
注:mixins属性可以指定多个mixin。但,如果两个mixin(也就是两个对象)中有名称相同的方法,会报命名冲突错误。
使用createClass实现的mixin可以为组件做两件事:
(1)定义工具方法。用mixin混入写好的工具方法。在需要用到工具方法的组件中设置mixin,即可使用相应工具方法。
(2)生命周期继承,props、state的合并。如果多个mixin对象中,都定义了同一个生命周期,react会智能地将它们合并起来执行。
3.ES6 Classes 与 decorator
es6 classes语法,用decorator实现mixin。
注:decorator与Java中pre-defined annotation的区别是,decorator是运用在运行时的方法。
4.mixin存在的问题
(1)破坏了原有组件的封装。
mixin中的方法会带来新的state和props,及其他未知操作,在使用组件中不可知,无法有目的地控制。
(2)命名冲突。
多个mixin中,或mixin与当前组件,可能存在相同命名的方法,从而命名冲突。
(3)增加复杂性。
当添加了越来越多的mixin,就会引入越来越多的方法,从而造成代码逻辑复杂,不易维护。
二、高阶组件
1.高阶函数:
概念:接受函数作为输入,或是输出一个函数,的函数。
如常用的map、reduce、sort等,都是高阶函数。
2.高阶组件
概念:类似于高阶函数。接受React组件作为输入,输出一个新的React组件。
实现方法:
(1)属性代理:高阶组件通过被包裹的React组件来操作props。
定义高阶组件:
import React,{Component} from 'React';
const MyContainer = (WrappedComponent) =>
class extends Component {
render() {
return <WrappedComponent {...this.props} />;
}
}
高阶组件:MyContainer
被包裹组件:WrappedComponent
{...this.props}是WrappedComponent的props对象。除了原封不动传递WrappedComponent的props,在高阶组件中,可以设置其他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读取的是,调用WrappedComponent时传入的props。注意{...this.props}和{...newProps}书写的先后顺序。如果this.props和newProps中有相同的prop,后面的会覆盖前面的。
}
}
对于WrappedComponent来说,只要套用这个高阶组件,我们的新组件中就会多一个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;
生命周期执行过程(类似于堆栈调用):
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调用顺序(类似于队列):
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输出结果
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;
}
}
网友评论