react之類的mvvm框架有個痛點想必你們都遇到過,那就是祖孫組件之間的通訊html
如今組件之間的通訊規範是:前端
僅僅是父子兩個組件之間這沒有問題
但是祖孫組件之間呢?vue
react中有個蟲洞的概念,至關於直通車,組件【祖先】=> 組件【孫子】,而不須要中間的組件來代理propsreact
直接show code數組
三個組件App.js,Son.js,GrandSon.js,下面介紹的是用蟲洞從App props直通GrandSon,而不須要Son來作代理屬性bash
// App.js的代碼
import React from 'react';
import Son from './son';
import PropTypes from 'prop-types';
class App extends React.Component{
constructor(){
super();
this.state = {
grandSonDesc: 'i am grandSonDesc'
};
}
getChildContext(){
return {
grandSonDesc: this.state.grandSonDesc
}
}
render(){
return <Son />
}
}
App.childContextTypes = {
grandSonDesc: PropTypes.string
}
export default App;
複製代碼
// Son.js
import React from 'react';
import GrandSon from './grandSon';
const Son = () => {
return <GrandSon />
}
export default Son;
複製代碼
// GrandSon.js
import React from 'react';
import PropTypes from 'prop-types';
class GrandSon extends React.Component{
render(){
return <div>{this.context.grandSonDesc}</div>
}
}
GrandSon.contextTypes = {
grandSonDesc: PropTypes.string
};
export default GrandSon;
複製代碼
至此就實現了蟲洞了,但是須要注意兩點:框架
那麼問題來了,爲啥要聲明contextTypes? 緣由是,GrandSon組件除了App這個爺爺組件外,還有Son這個爸爸組件。那麼grandSonDesc是從哪一個組件繼承而來呢,contextTypes就是作這個標識做用,並且多個父組件的context會作merge,也是根據定義contextTypes來的mvvm
好的,到這裏感受很爽,蟲洞直通車傳輸props,可是我要說的是,這個實如今react17將被廢棄!!!ide
若是一個屬性將被廢棄,多半是跟它的性能有關了,能夠試想下,蟲洞傳輸props,其實son組件沒有任何更新,那麼當grandSonDesc變化時,Son組件會不會被更新?直接show code吧函數
// App.js
import React from 'react';
import Son from './son';
import PropTypes from 'prop-types';
class App extends React.Component{
constructor(){
super();
this.state = {
grandSonDesc: 'i am grandSonDesc'
};
}
componentDidMount(){
setTimeout(() => {
this.setState({
grandSonDesc: 'i am grandSonDesc啊啊啊啊啊啊啊啊'
});
}, 3000);
}
getChildContext(){
return {
grandSonDesc: this.state.grandSonDesc
}
}
render(){
return <Son />
}
}
App.childContextTypes = {
grandSonDesc: PropTypes.string
}
export default App;
複製代碼
// Son.js
import React from 'react';
import GrandSon from './grandSon';
class Son extends React.Component{
componentDidUpdate(){
console.log('son updated!');
}
render(){
return <GrandSon />
}
}
export default Son;
複製代碼
// GrandSon.js
import React from 'react';
import PropTypes from 'prop-types';
class GrandSon extends React.Component{
componentDidUpdate(){
console.log('grandson updated!');
}
render(){
return <div>{this.context.grandSonDesc}</div>
}
}
GrandSon.contextTypes = {
grandSonDesc: PropTypes.string
};
export default GrandSon;
複製代碼
三秒以後GrandSon的顯示變成了i am grandSonDesc啊啊啊啊啊啊啊啊,而控制檯輸出son updated在版本的代碼中,App.js在三秒鐘以後去更新grandSonDesc,而後在Son和GrandSon組件中加上componentDidUpdate更新以後的log,來看一下控制檯輸出
這說明Son組件也被更新了,那麼蟲洞若是中間層組件比較多的話,豈不是很浪費性能嗎?
那麼既然性能很差,世界頂級前端團隊就要開始優化了,那麼就有了二代蟲洞,直接上代碼介紹下二代蟲洞吧,仍是原來的配方App+Son+GrandSon,惟一多的是一個context的配置文件
// App.js
import React from 'react';
import Son from './son';
import Context from './context';
import PropTypes from 'prop-types';
class App extends React.Component {
constructor(){
super();
this.state = {
grandSonDesc: 'i am grandSon'
};
}
render(){
return (
<div className="App">
<Context.Provider value={this.state}>
<Son />
</Context.Provider>
</div>
);
}
}
App.contextType = Context;
export default App;
複製代碼
// Son.js
import React, { PureComponent } from 'react';
import GrandSon from './grandSon';
import PropTypes from 'prop-types';
class Son extends PureComponent{
render(){
return <GrandSon />
}
}
export default Son;
複製代碼
// GrandSon.js
import React, { PureComponent } from 'react';
import Context from './context';
class GrandSon extends PureComponent{
render(){
return <div>
<Context.Consumer>
{value => value.grandSonDesc}
</Context.Consumer>
</div>
}
}
export default GrandSon
複製代碼
// context.js
import { createContext } from 'react';
let Context = createContext();
export default Context;
複製代碼
代碼敲完了,能夠start看看效果了,能夠發現照樣跑起來了
那麼問題來了,你說一代蟲洞性能差,憑什麼嘛?
// App.js
import React from 'react';
import Son from './son';
import Context from './context';
import PropTypes from 'prop-types';
class App extends React.Component {
constructor(){
super();
this.state = {
grandSonDesc: 'i am grandSon'
};
}
componentDidMount(){
setTimeout(() => {
this.setState({
grandSonDesc: 'i am grandSon啊啊啊啊啊啊啊啊啊啊'
});
}, 3000);
}
render(){
return (
<div className="App">
<Context.Provider value={{grandSonDesc: this.state.grandSonDesc}}>
<Son />
</Context.Provider>
</div>
);
}
}
App.contextType = Context;
export default App;
複製代碼
// Son.js
import React, { PureComponent } from 'react';
import GrandSon from './grandSon';
import PropTypes from 'prop-types';
class Son extends PureComponent{
componentDidUpdate(){
console.log('son updated');
}
render(){
return <GrandSon />
}
}
export default Son;
複製代碼
// GrandSon.js
import React, { PureComponent } from 'react';
import Context from './context';
class GrandSon extends PureComponent{
componentDidUpdate(){
console.log('grandson updated');
}
render(){
return <div>
<Context.Consumer>
{value => value.grandSonDesc}
</Context.Consumer>
</div>
}
}
export default GrandSon
複製代碼
能夠發現,3秒以後grandSonDesc變了,兩個子組件的componentDidUpdated都沒進
這就是兩種蟲洞的實現方式,到這裏差很少講完了,關於更多新版context的用法能夠參考官網 reactjs.org/docs/contex…