基于react框架使用的一些细节要点的思考


Posted in Javascript onMay 31, 2017

这篇文章主要是写关于学习react中的一些自己的思考:

1.setState到底是同步的还是异步的?

2.如何在子组件中改变父组件的state

3.context的运用,避免“props传递地狱”

4.组件类里有私有变量a,它到底改放在this.a中还是this.state对象中(作为属性a)呢?

1.setState到底是同步的还是异步的?

class MyComponent extends React.Component{
 constructor(props) {
  super(props)
  this.state ={
  value:0
  }
 }
handleClick = () => {
  this.setState({value:1})
   console.log('在handleClick里输出' + this.state.value);
}
render(){
   console.log('在render()里输出' + this.state.value);
return (<div>
   <button onClick ={this.handleClick}>按钮</button>
  </div>)
  }
}
export default MyComponent
//省略渲染过程,下面也一样

在这里我们点击按钮时,调用handleClick函数,首先调用this.setState()设置value,随即把this.state.value输出,结果是什么?

你可能会想,这还不简单——“在handleClick里输出1”呗,然而你错了,它的结果为:

基于react框架使用的一些细节要点的思考

事实上,setState()的调用是异步的,这意味着,虽然你调用了setState({value:0}),但this.state.value并不会马上变成0,而是直到render()函数调用时,setState()才真正被执行。结合图说明一下:

基于react框架使用的一些细节要点的思考
你可能又会问了:要是我在render()前多次调用this.setState()改变同一个值呢?(比如value)

我们对handleClick做一些修改,让它变得复杂一点,在调用handleClick的时候,依次调用handleStateChange1 ,handleStateChange2,handleStateChange3,它们会调用setState分别设置value为1,2,3并且随即打印

handleStateChange1 = () => {
  this.setState({value:1})
  console.log('在handleClick里输出' + this.state.value);
}
handleStateChange2 = () => {
  this.setState({value:2})
  console.log('在handleClick里输出' + this.state.value);
}
handleStateChange3 = () => {
  this.setState({value:3})
  console.log('在handleClick里输出' + this.state.value);
}
handleClick = () => {
  this.handleStateChange1();
  this.handleStateChange2();
  this.handleStateChange3();
}
那么输出结果会是什么呢?如果setState是同步调用的,那么结果显然为
在handleClick里输出1
在handleClick里输出2
在handleClick里输出3
但是结果为:,证明它是异步的
基于react框架使用的一些细节要点的思考
这下好理解了吧,配合这幅图:

基于react框架使用的一些细节要点的思考

2.如何在子组件中改变父组件的state呢?

这是我们经常会遇到的问题之一,解决办法是:在父组件中写一个能改变父组件state的方法,并通过props传入子组件中
class Son extends React.Component{
 render(){
  return(<div onClick = {this.props.handleClick}>
    {this.props.value}
    </div>)
   }
}
class Father extends React.Component{
 constructor(props){
   super(props)
   this.state ={
    value:'a'
    }
  }
 handleClick = () => {
   this.setState({value:'b'})
  }
 render(){
   return (<div style ={{margin:50}}>
      <Son value = {this.state.value} handleClick = {this.handleClick}/>
     </div>)
   }
}
点击子组件Son,内容由a变成b,说明父组件的state被修改了

基于react框架使用的一些细节要点的思考

基于react框架使用的一些细节要点的思考

3.context的运用,避免“props传递地狱”
3.1假设一个比较极端的场景:你需要从你的子组件里调用父父父父父组件的属性或方法,怎么办!当组件嵌套层级过深的时候,不断地传props作为实现方式简直就是噩梦!我称之为“props传递地狱”(这个词是我瞎编的,参考自“回调函数地狱”)
我们接下来实现的是这样一个需求,把gene属性(基因)从组件GrandFather -->Father --> Son传递,如果用props传递:
class Son extends React.Component{
 render(){
  return (<h3 style ={{marginTop:30}}>我从我的爷爷那里得到了基因--{this.props.gene}</h3>)
  }
 }
class Father extends React.Component{
 render(){
  return (<Son gene = {this.props.gene}/>)
 }
}
class GrandFather extends React.Component{
 constructor(props) {
  super(props)
  this.state ={
  gene:'[爷爷的基因]'
  }
 }
 render(){
  return (<Father gene = {this.state.gene}/>)
 }
}
demo:
基于react框架使用的一些细节要点的思考
【(。・`ω´・)虽然听起来有点怪怪的但是大家别介意哈】
实现是实现了,但你想想,假设不是从“爷爷”组件,而是从“太太太太爷爷”组件传下来,这多可怕!不过没关系,react提供了一个叫做context(上下文)的API,你在顶层组件的context中定义的属性,可以在所有的后代组件中,通过this.context.属性去引用!让我们一睹为快:
class Son extends React.Component{
 render(){
  console.log(this.context.color);
  return (<h3 style ={{marginTop:30}}>我从我的爷爷那里得到了基因--{this.context.gene}</h3>)
  }
}
Son.contextTypes ={
  gene:React.PropTypes.string
}
class Father extends React.Component{
 render(){
  return (<Son/>)
  }
}
class GrandFather extends React.Component{
 getChildContext(){
  return {gene:'[爷爷的基因]'}
 }
 render(){
  return (<Father />)
 }
}
GrandFather.childContextTypes = {
  gene: React.PropTypes.string
};
export default GrandFather
demo效果同上!这个时候你发现,我们在<GrandFather>组件和<Father>组件中都没有向下传递props,我们就从最下层的Son组件中获取了gene属性,是不是很方便!
解释下代码:
getChildContext()是你在顶层组件中定义的钩子函数,这个函数返回一个对象——你希望在后代组件中取用的属性就放在这个对象中,譬如这个例子中我希望在Son组件中通过this.context.gene取属性,所以在getChildContext()中返回{gene:'[爷爷的基因]'}
GrandFather.childContextTypes和Son.contextTypes 用于规定顶层组件和取顶层组件context的后代组件的属性类型
【注意】GrandFather.childContextTypes和Son.contextTypes 这两个对象必须要规定!否则context只能取到空对象!一开始我犯的这个错误简直让我狂吐三升血。。。。
有图有真相之context和props的区别
基于react框架使用的一些细节要点的思考
3.2context是否推荐使用?
虽然上面这个例子说明了context多么好用,但注意:官方并不推荐经常使用它,因为它会让你的应用架构变得不稳定(官方文档原话If you want your application to be stable, don't use context),在我看来,为什么在大多数情况下要使用props而不是实现数据流呢,因为props凭借组件和组件间严密的逻辑联系,使得你能够清晰地跟踪应用的数据流(it's easy to track the flow of data through your React components with props)当然了,如果你遇到上述的例子的情况,context还是大有裨益的
3.3需要改变context中的属性时候,不要直接改变它,而是使用this.state作为媒介,如果你试图在顶层组件的state中放入一个可变的属性你可以这样做:
getChildContext(){
  return {type:this.state.type}
}
3.4在上述我限制gene的类型时候我是这样写的:gene: React.PropTypes.string,使用了React内置的React.PropTypes帮助属性,此时我的版本为 "react": "15.4.2",在15.5的版本后这一帮助属性被废弃,推荐使用props-types库,像这样:
const PropTypes = require("Prop-Types");
GrandFather.childContextTypes = {
  gene: PropTypes.string
};
当然,在这之前你需要npm install prop-types
4.组件类里有私有变量a,它到底改放在this.a中还是this.state对象中(作为属性a)呢?
这得根据它是否需要实时的重渲染决定,如果该变量需要同步到变化的UI中,你应该把它放在this.state对象中,如果不需要的话,则把它放在this中(无代码无demo)

以上这篇基于react框架使用的一些细节要点的思考就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
驱动事件的addEvent.js代码
Mar 27 Javascript
jQuery 表单验证扩展代码(二)
Oct 20 Javascript
js判断60秒以及倒计时示例代码
Jan 24 Javascript
JQuery右键菜单插件ContextMenu使用指南
Dec 19 Javascript
JS中的hasOwnProperty()和isPrototypeOf()属性实例详解
Aug 11 Javascript
使用jsonp实现跨域获取数据实例讲解
Dec 25 Javascript
js 判断登录界面的账号密码是否为空
Feb 08 Javascript
微信小程序引用iconfont图标的方法
Oct 22 Javascript
JavaScript实现汉字转换为拼音及缩写的方法示例
Mar 28 Javascript
JS如何定义用字符串拼接的变量
Jul 11 Javascript
vue 实现tab切换保持数据状态
Jul 21 Javascript
微信小程序实现点赞业务
Feb 10 Javascript
Angular 通过注入 $location 获取与修改当前页面URL的实例
May 31 #Javascript
使用原生js写ajax实例(推荐)
May 31 #Javascript
Javascript创建类和对象详解
May 31 #Javascript
Javascript继承机制详解
May 30 #Javascript
Vue2.x中的Render函数详解
May 30 #Javascript
jQuery实现动态删除LI的方法
May 30 #jQuery
Vue.js实现在下拉列表区域外点击即可关闭下拉列表的功能(自定义下拉列表)
May 30 #Javascript
You might like
ThinkPHP3.1新特性之G方法的使用
2014/06/19 PHP
thinkPHP框架可添加js事件的分页类customPage.class.php完整实例
2017/03/16 PHP
jQuery 获取对象 根据属性、内容匹配, 还有表单元素匹配
2010/05/31 Javascript
JSON与XML优缺点对比分析
2015/07/17 Javascript
PhantomJS快速入门教程(服务器端的 JavaScript API 的 WebKit)
2015/08/06 Javascript
《JavaScript函数式编程》读后感
2015/08/07 Javascript
jquery实现简单实用的弹出层效果代码
2015/10/15 Javascript
JavaScript和jquery获取父级元素、子级元素、兄弟元素的方法
2016/06/05 Javascript
AngularJS中的包含详细介绍及实现示例
2016/07/28 Javascript
Vue.js仿Metronic高级表格(一)静态设计
2017/04/17 Javascript
vue v-on监听事件详解
2017/05/17 Javascript
网页爬虫之cookie自动获取及过期自动更新的实现方法
2018/03/06 Javascript
atom-design(Vue.js移动端组件库)手势组件使用教程
2019/05/16 Javascript
JS扁平化输出数组的2种方法解析
2019/09/17 Javascript
vuejs中父子组件之间通信方法实例详解
2020/01/17 Javascript
[49:35]KG vs SECRET 2019国际邀请赛小组赛 BO2 第一场 8.16
2019/08/19 DOTA
python3.3教程之模拟百度登陆代码分享
2014/01/16 Python
Python脚本实现格式化css文件
2015/04/08 Python
python操作xlsx文件的包openpyxl实例
2018/05/03 Python
Python实现定时执行任务的三种方式简单示例
2019/03/30 Python
PyCharm搭建Spark开发环境的实现步骤
2019/09/05 Python
使用python 对验证码图片进行降噪处理
2019/12/18 Python
python datetime时间格式的相互转换问题
2020/06/11 Python
Myprotein瑞士官方网站:运动营养和健身网上商店
2019/09/25 全球购物
魅力教师事迹材料
2014/01/10 职场文书
护士检查书
2014/01/17 职场文书
艺术节主持词
2014/04/02 职场文书
党员志愿者活动总结
2014/06/26 职场文书
2014教师“四风问题”对照检查材料思想汇报
2014/09/16 职场文书
四风问题对照检查材料
2014/09/22 职场文书
2015年成本会计工作总结
2015/10/14 职场文书
2016个人廉洁自律承诺书
2016/03/25 职场文书
游戏开发中如何使用CocosCreator进行音效处理
2021/04/14 Javascript
Golang之sync.Pool使用详解
2021/05/06 Golang
openstack云计算keystone组件工作介绍
2022/04/20 Servers
vue实现input输入模糊查询的三种方式
2022/08/14 Vue.js