内容简介:react之类的mvvm框架有个痛点想必大家都遇到过,那就是祖孙组件之间的通信现在组件之间的通信规范是:仅仅是父子两个组件之间这没有问题
react之类的mvvm框架有个痛点想必大家都遇到过,那就是祖孙组件之间的通信
现在组件之间的通信规范是:
- 父 -> 子:属性绑定props
- 子 -> 父:事件广播(vue之类的emit)react那还是调用父类的props[fn]
仅仅是父子两个组件之间这没有问题
可是祖孙组件之间呢?
react中有个虫洞的概念,相当于直通车,组件【祖先】=> 组件【孙子】,而不需要中间的组件来代理props
下面就先介绍下高端的虫洞(直通车)
直接show code
三个组件App.js,Son.js,GrandSon.js,下面介绍的是用虫洞从App props直通GrandSon,而不需要Son来做代理属性
// 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; 复制代码
至此就实现了虫洞了,可是需要注意两点:
- GrrandSon不能为纯函数组件,这样是不能注入的
- App组件和GrandSon组件需要定义类属性contextTypes,App组件需要定义getChildContext
那么问题来了,为啥要声明contextTypes? 原因是,GrandSon组件除了App这个爷爷组件外,还有Son这个爸爸组件。那么grandSonDesc是从哪个组件继承而来呢,contextTypes就是做这个标识作用,而且多个父组件的context会做merge,也是根据定义contextTypes来的
好的,到这里感觉很爽,虫洞直通车传输props,但是我要说的是,这个实现在react17将被废弃!!!
为何老版本虫洞将被废弃?
如果一个属性将被废弃,多半是跟它的性能有关了,可以试想下,虫洞传输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,来看一下控制台输出
三秒之后GrandSon的显示变成了i am grandSonDesc啊啊啊啊啊啊啊啊,而控制台输出son updated
这说明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…
以上所述就是小编给大家介绍的《React性能优化之Context》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 性能优化第一课:性能指标
- 【前端性能优化】vue性能优化
- Golang 性能测试 (2) 性能分析
- 【前端性能优化】02--vue性能优化
- Java性能 -- 性能调优标准
- Java性能 -- 性能调优策略
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Little Schemer - 4th Edition
Daniel P. Friedman、Matthias Felleisen / The MIT Press / 1995-12-21 / USD 40.00
This delightful book leads you through the basic elements of programming in Scheme (a Lisp dialect) via a series of dialogues with well-chosen questions and exercises. Besides teaching Scheme, The Lit......一起来看看 《The Little Schemer - 4th Edition》 这本书的介绍吧!