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;
复制代码
在版本的代码中,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…