继续上一次基础篇, 分享一些关于React的进阶技术
React 进阶部分
- ** context **
- ** setState vs forceUpdate **
- ** Mixins **
- ** HOC **
Components 相关
context
在 React 官方文档上有对 context
的说明:
Context is an advanced experimental feature. The API is likely to change in future releases
** context 如何工作? **
首先要在提供 context
的组件中定义 childContextTypes
和 getChildContext
childContextTypes
: 静态属性, 声明传递下去的context
的对象结构, 与propTypes
类似, 但该属性是必须的getChildContext
: 定义在prototype
上的方法, 返回将要传递下去的context
对象,每次状态改变或该组件接收到新的props
的时候该方法将被调用, 其实该方法是在render()
中执行的, 在组件的以下生命周期中能够访问context
componentWillReceiveProps(nextProps,nextContext){...}
shouldComponentUpdate(nextProps,nextState,nextContext){...}
componentWillUpdate(nextProps,nextState,nextContext){...}
componentDidUpdate(previousProps,previousContext){...}
** 使用 context
的缺点 **
- React 中的
context
可能在将来发生变化, 这样依赖它的代码过于脆弱 - React 的
context
是单个子树范围的全局变量, 这样无疑提高了代码的耦合, 在该子树之外也很难重用 - 如果提供
context
的组件的context
发生了变化, 使用context
组件的任何一个父组件使用了shouldComponentUpdate
返回了 false, 则使用者将不会发生更新
引入高阶组件能稍微缓解这些缺点
setState 接受 Function VS Object
为什么要传递函数到 setState
?
Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.
React可以将多个 setState()
调用批处理为单个更新以实现性能。
forceUpdate() VS setState()
** setState **
官方关于 setState
的描述
setState() enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state. This is the primary method you use to update the user interface in response to event handlers and server responses.
官方关于 forceUpdate
的描述
By default, when your component's state or props change, your component will re-render. If your render() method depends on some other data, you can tell React that the component needs re-rendering by calling forceUpdate(). Normally you should try to avoid all uses of forceUpdate() and only read from this.props and this.state in render().
** 区别 **
forceUpdate()
会跳过 shouldComponentUpdate()
, 不会修改当前的 state
, setState()
与之不同
代码复用
Mixins && HOC
Mixins
现已不推荐
React Mixins
[ _ 以下内容参考本文 _ ]
var LogMixin = {
componentWillMount: function () {
console.log('报告老板, 开始加载!');
},
componentDidMount: function () {
console.log('报告老板, 装载完毕!');
}
};
var AComponent = React.createClass({
mixins: [LogMixin],
render: function () {
return <h1>AComponent</h1>
}
});
var BComponent = React.createClass({
mixins: [LogMixin],
render: function () {
return <h1>BComponent</h1>
}
});
mixin
里的 this
指向组件
组件调用Mixins方法
var Mixin = {
log:function(){
console.log('Mixin log');
}
};
var Component = React.createClass({
mixins: [Mixin],
componentWillMount: function () {
this.log();
},
render: function () {
return <h1>Component</h1>
}
});
生命周期方法 [__ Mixins里的方法并不会覆盖组件的生命周期方法,会在先于组件生命周期方法执行。 __]
var Mixin = {
componentWillMount: function () {
console.log('Mixin Will Mount');
}
};
var Component = React.createClass({
mixins: [Mixin],
componentWillMount: function () {
console.log('Component Will Mount');
},
render: function () {
return <div>Component</div>
}
});
使用多个Mixin [__ 引入的顺序,决定了Mxins里生命周期方法的执行顺序。 __]
var AMixin = {
componentWillMount: function () {
console.log('AMixin Will Mount');
}
};
var BMixin = {
componentWillMount: function () {
console.log('BMixin Will Mount');
}
};
var Component = React.createClass({
mixins: [AMixin,BMixin],
componentWillMount: function () {
console.log('Component Will Mount');
},
render: function () {
return <div>Component</div>
}
});
不允许重复 [__ 除了生命周期方法可以重复以外,其他的方法都不可以重复,否则会报错 __]
不允许 Mixins
内的方法重复, 也不允许 Mixins
内的方法与组件的方法以及组件原型重复
换言之, __ 组件能访问到的方法不能被劫持 __
方法重复案例一
var AMixin = {
log: function () {
console.log('AMixin Log');
}
};
var BMixin = {
log: function () {
console.log('BMixin Log');
}
};
var Component = React.createClass({
mixins: [AMixin,BMixin],
render: function () {
return <div>Component</div>
}
});
方法重复案例二
var Mixin = {
log: function () {
console.log('Mixin Log');
}
};
var Component = React.createClass({
mixins: [Mixin],
log:function(){
console.log('Component Log');
},
render: function () {
return <div>Component</div>
}
});
HOC
如同 高阶函数
, 高阶组件
也是一个函数, 你可以使用 typeof
进行检测, 从定义上来讲它就是一个地地道道的函数, 在 React
家族中我们叫它组件, 它接受一个组件, 返回一个新组件, 注意这里的组件本质上就是函数, 与 React
元素的概念上的区别见上一讲 React基础提升
, 如果非要区分一下组件和函数的话, 那么组件是一种稍微特殊一点的函数, 它是构造函数, 但是 高阶组件
只是一个普通的函数, 从这层意义上讲, 高阶组件
并不是组件, 因为它不是构造函数, 只是一层 包装函数
, 看一下 高阶函数
的大概面貌:
let HOC = BaseComponent => class extends React.Component {
// do something
render() {
return <BaseComponent />
}
};
这里的 HOC 是高阶组件, 并不是它的返回值是高阶组件, 它的返回值只是一个很普通的 React
组件
1
const HOCSomeComponent = SomeComponent => class extends React.Component {
render = x => <SomeComponent { ...this.props } />
}
** 可以做什么? **
操作 props
const HOCSomeComponent = SomeComponent => class extends React.Component {
render() {
let tel = { mp: '13194099515' };
return <SomeComponent { ...this.props } { ...tel } />;
}
}
包裹 SomeComponent
const HOCSomeComponent = SomeComponent => class extends React.Component {
render() {
// 还可以传入多个组件
return (
<div>
<SomeComponent { ...this.props } />
</div>
)
}
}
2
反转继承
const HOCSomeComponent = SomeComponent => class extends SomeComponent {
render = x => super.render()
}
** 还可以做什么? **
渲染劫持
条件渲染
const HOCSomeComponent = SomeComponent => class extends SomeComponent {
render() {
if( someValue ) {
return super.render();
} else {
return null;
}
}
}
修改被包裹组件的输出树
const HOCSomeComponent = SomeComponent => class extends SomeComponent {
render() {
const ele = super.render();
let newProps = {};
if(ele[somekey] === someValue) {
newProps = { ... };
}
const props = { ...this.props, ...newProps };
return React.cloneElement(ele, props, ele.props.children);
}
}
操作 state
const HOCSomeComponent = SomeComponent => class extends SomeComponent {
constructor(props) {
super(props);
this.state = Object.assign({}, this.state, { ... });
}
render() {
return (
div>
{ super.render() }
</div>
)
}
}
...
{
... 不要限制你的思想, HOC 可以做很多...
}