文档章节

React.js 组件的 props vs state

曾建凯
 曾建凯
发布于 2016/12/05 12:19
字数 1602
阅读 167
收藏 5
点赞 0
评论 0

看到一篇无比蛋疼的文章:https://www.oschina.net/translate/exploring-reacts-state-propagation。我不针对翻译,只是针对这篇文章想提出的概念,说了跟没说一样,傻傻的。

要搞清楚React.js的props和state,必须要结合组件(组件类)从初始化到装载(mount)的过程来说。

组件类

假定我们通过以下的代码,创建了一个组件:

var SimpleComponent = React.createClass({
	getDefaultProps: function() {
		return {
			name: ''
		};
	},
	getInitialState: function() {
		return {
		};
	},
	render: function() {
		return <div>A simple component named {this.props.name}</div>;
	}
});

这里SimpleComponent是一个组件类。

组件虚拟对象

当我们要使用这个组件类的时候,可以写这样的代码:

<SimpleComponent name="abc"/>

实际上上述代码会转移成下面的js代码:

React.createElement(SimpleComponent, null)

通过React.createElement函数创建的,并不是SimpleComponent的组件类实例(即不是new SimpleComponent),而是一个不可写入的静态对象(Object),并且这个静态对象,具有props,没错,就是SimpleComponent组件类定义的getDefaultProps所返回的值。

我将这个静态对象称为组件虚拟对象,他持有了SimpleComponent的初始化所需的props,并且我有理由怀疑他是全局唯一的(当然我没精力去验证了)。

所以,要知道,当我们在jsx文件中,写了大量看似html标签的结构,他实际上并没有逐个创建对应的组件实例,取而代之的,仅仅是构造一大堆组件虚拟对象(静态Object)和传入参数而已。

注意,这个时候组件虚拟对象是没有state的。

组件实体(实例)

当一个组件虚拟对象被装载(mount)后——这里所谓装载,就是将一个或一大段组件虚拟对象插入到实际的DOM节点中时,才会创建出真实的组件实体(实例)。

创建组件的实体的时候,才会真正将调用参数传入(比如上面的name=abc),并且混入组件虚拟对象上的props。

当组件被实体化后,才真正的拥有state。

而我们实际在编写SimpleComponent这个组件类的方法时,都是假定针对的是组件实体的状态下进行的。

最后,总结为一个流程图来说明的话:

props只读、不可变?

我只能说,这是一个误区。首先,假定你拥有React Development tools的话,通过修改React.js的组件props,也能促使组件发生变化。就好像这样:

这个问题,仔细想想就能明白是别人给你挖了个坑(不是React.js,而是这些所谓的教程)。假定我们设计两个组件:

var AComponent = React.createClass({
	getDefaultProps: function() {
		return {
			name: ''
		};
	},
	getInitialState: function() {
		return {
			name: this.props.name
		};
	},
	render: function() {
		return <div>I'm {this.props.name}</div>;
	}
});

var BComponent = React.createClass({
	getDefaultProps: function() {
		return {
			name: ''
		};
	},
	getInitialState: function() {
		return {
			name: this.props.name
		};
	},
	render: function() {
		return <div>
			<AComponent name={this.state.name} />
			<button type="button" onClick={e => this.setState({name: 'Jack'})}>change name</button>
		</div>;
	}
});

在B组件内,是使用state.name作为A组件的props.name传入的,如果是只读、不可变的话,那么B组件的按钮被点击后,B组件的state.name改变了,永远也不可能触发到A组件state更新了。

所以,严格来说,props不可变,只在组件虚拟对象这个阶段,因为那是一个不可写入的静态对象。

更进一步,从组件类到组件实例,实际上是完成了从props将数据传递给state。这是一个必然性的数据流向,无论多少次组件嵌套,这种数据流向都不会改变。所以一般而言,很少会去动(注意这里只是说动,但没有说不去读)一个组件实例的props,而直接操作state。

传统的OOP编程,并没有严格的数据流向,到底是属性到方法,还是方法到属性,还是属性到属性,完全由开发者自己掌控,你爱怎么写,就怎么写。这在前端组件的源码中,形成了很大的伪装性,当发生错误的时候,你完全不知道该从哪里开始着手,需要花一定的时间去解读、调试,然后才能定位问题(当然有好的规范可以相对的缓解类似的问题)。

而React.js则提供一种简单明确的机制(而且他只提供了这个机制而已),这也是React.js开发过程中会形成的一个思维定式。每当你开始编写一个组件,你就需要设计,这个组件应该具有哪些动态(交互性)特征需要放入state,而这些state又是怎么从props传递过去的。仅此而已,剩下的就是组件的界面逻辑开发而已。

state - 状态

这个应该不用多介绍了吧,React.js的卖点,组件实例的界面和自身的state动态结合,而且性能还相当的好。

不过其实这里也有一个小坑,就是当你在设计一个组件的时候,应该认真的思考哪些特征属于动态的。如果你在state里装载了大量的数据,要监控这些state的更新,还是相当的时间(其实真正很大的数据,大概会有3-5ms的延迟,但这个数据真的很大了)。所以,特别注意:

setState方法是异步的!!!

setState方法是异步的!!!

setState方法是异步的!!!

重要的事情说三次,是的,所以如果你这样写,可能会导致你的界面发生不可预料的后果:

this.setState(bigData);
// ...干点别的事情

正确的写法应该这样:

this.setState(bigData, function() {
	// ...干点别的事情
});

当你使用React.js开发的时间长了的话,慢慢的也会调整自己的思维方式,更加集中的设计state。这个下面还会提到。

es6 or typescript

如果可能的话,如果改用es6或者ts,上面的代码,将会简单很多很多:

class SimpleComponentES6 extends React.Component {
	constructor(props) {
		super(props);
		this.state = {
			name: this.props.name || ''
		}
	}
	
	render() {
		return <div>A simple component named {this.props.name}</div>;
	}
}

代码是不是顿时清晰了很多?

ts现在已经迈进2.0时代了,各方面都比过去完善了很多。假如你的项目,超过1000行JS,最好能换成ts,因为ts的语言特性,会让你的代码的自动提示得更加明确,而不像js或者es6,有的没的相似的不是的方法、属性提示你一大堆。

 

© 著作权归作者所有

共有 人打赏支持
曾建凯
粉丝 323
博文 57
码字总数 90297
作品 0
广州
技术主管
React.js 实战之深入理解组件

sublime 插件安装 用Package Control安装 按下调出命令面板 输入 调出 选项并回车,然后在列表中选中要安装的插件 function形式 state属性 props属性介绍:...

紫霞等了至尊宝五百年 ⋅ 06/02 ⋅ 0

React.js 模式

前言 我想找一个好的前端前端框架,找了很久。这个框架将能够帮助我写出具有可扩展性、可维护性 UI 的代码。通过对 React.js 优势的理解,我认为“我找到了它”。在我大量的使用过程中,我发...

卢林 ⋅ 2016/09/25 ⋅ 0

React.js 2016 最佳实践 徬梓阅读 1584收藏 71

译者按:近几个月React相关话题依旧火热,相信越来越多的开发者在尝试这样一项技术,我们团队也在PC和移动端不断总结经验。2016来了,这应该是 React走向成熟的一年,不管你是新手,还是已经...

我家有宝 ⋅ 2016/01/27 ⋅ 0

40 行代码内实现一个 React.js

作者:胡子大哈 原文链接:http://huziketang.com/blog/posts/detail?postId=58aea515204d50674934c3ac 转载请注明出处,保留原文链接和作者信息。 ================================== 目录...

胡子大哈 ⋅ 2017/02/23 ⋅ 0

React 入门实例教程

作者: 阮一峰 日期: 2015年3月31日 现在最热门的前端框架,毫无疑问是 React 。 上周,基于 React 的 React Native 发布,结果一天之内,就获得了 5000 颗星,受瞩目程度可见一斑。 React ...

引鸩怼孑 ⋅ 2015/09/15 ⋅ 0

React.js实现原生js拖拽效果及思考

一、起因&思路 不知不觉,已经好几天没写博客了。。。近来除了研究React,还做了公司官网。。。 一直想写一个原生js拖拽效果,又加上近来学react学得比较嗨。所以就用react来实现这个拖拽效果...

LuckyWinty ⋅ 2016/03/29 ⋅ 0

2015年最热门前端框架React 入门实例教程

现在最热门的前端框架,毫无疑问是 React 。 上周,基于 React 的 React Native 发布,结果一天之内,就获得了 5000 颗星,受瞩目程度可见一斑。 React 起源于 Facebook 的内部项目,因为该公...

数通畅联 ⋅ 2015/11/23 ⋅ 0

如何存储 React 组件的数据

主要讲解这几个部分:state、store、static、this、module-global data 前言 随着 React 和 Redux 的到来,一个共同的问题被问到: 我应该将数据保存在 Redux Store 中呢?还是应该保存成本地...

卢林 ⋅ 2016/10/16 ⋅ 0

2016年度——React.js 最佳实践

最近React(web/native)依旧如火如荼,相信大家都跃跃欲shi,我们团队也开始在React领域有所尝shi. 2016年应该是 React 逐渐走向成熟的一年,让我们一起来看看国外的开发者们都总结了哪些"最佳实...

力谱宿云 ⋅ 2016/03/24 ⋅ 3

React 入门实例教程

现在最热门的前端框架,毫无疑问是 React 。 上周,基于 React 的 React Native 发布,结果一天之内,就获得了 5000 颗星,受瞩目程度可见一斑。 React 起源于 Facebook 的内部项目,因为该公...

ifeixiang ⋅ 2015/09/15 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

收集自网络的wordpress 分页导航的代码教程(全网最全版)

wordpress 分页导航是用来切换文章的一个功能,添加了 wordpress 分页导航后,用户即可自由到达指定的页面数浏览分类文章,而这样的一个很简单功能却有很多朋友在用插件:WP-PageNavi,插件的...

Rhymo-Wu ⋅ 38分钟前 ⋅ 0

微服务 WildFly Swarm 入门

Hello World 就像前面章节中的其他框架一样,我们希望添加一些基本的 Hello-world 功能,然后在其上逐步添加更多的功能。让我们从在我们的项目中创建一个 HolaResources 开始。您可以使用您的...

woshixin ⋅ 45分钟前 ⋅ 0

Maven的安装和Eclipse的配置

1. 下载Maven 下载地址 2. 解压压缩包,放到自己习惯的硬盘中 此处我将其放到了 D:\Tools 目录下。 3. 配置环境变量 右键此电脑 -> 属性 -> 高级系统设置 -> 环境变量。 在系统变量中新建,变...

影狼 ⋅ 52分钟前 ⋅ 0

python pip使用国内镜像的方法

国内源 清华:https://pypi.tuna.tsinghua.edu.cn/simple 阿里云:http://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/ 华中理工大学:http://......

良言 ⋅ 53分钟前 ⋅ 0

对于url变化的spa应该如何使用微信jssdk

使用vue单页面碰上微信jssdk config验证失败的坑。第一次成功 之后切换页面全部失败,找到了解决方法,第一次验证成功后保存验证信息 切换页面时验证信息直接拿来用,加一个wx.error() 失败时...

孙冠峰 ⋅ 57分钟前 ⋅ 0

Spring Cloud Gateway 一般集成

SCF发布,带来很多新东西,不过少了点教程,打开方式又和以前的不一样,比如这个SCG,压根就没有入门指导,所以这里写一个,以备后用。 一、集成 pom.xml <dependency> <groupI...

kut ⋅ 今天 ⋅ 0

建造模式

《JAVA与模式》之建造模式

Cobbage ⋅ 今天 ⋅ 0

WePY框架开发的小程序如何在微信web开发者工具中运行起来

一、首先需要安装node.js,安装步骤如下: 首先下载安装包 https://nodejs.org/en/download/ 点击下载相应的zip版本 然后将文件夹解压到任意目录 比如我这里解压到了:C:\Program Files\node...

Helios51 ⋅ 今天 ⋅ 0

使用EnumSet 代替位域(32)

1、位域(Bit field):使用or 运算将几个常量合并到一个集合中 位操作,可以有效地执行 AND 、OR 这样的位操作 但是 位域比int 常量枚举缺点更多 2、java.util 包里面的EnumSet 类是有效的替...

职业搬砖20年 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部