繼續上一次基礎篇, 分享一些關於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 可以做很多...
}