1 React简介
1.1背景介绍
React首次被提出是来自于Facebook 2014年的F8开发者大会上。现在基于HTML页面开发越来越复杂。
当用传统方式解决来自于服务器上和用户输入的交互数据动态的反应到复杂界面上的时候,代码量变得越来越大,越来越难以维护,常常显得力不从心!基于此Google提出了AngularJS框架,但其整体是一个MVVM框架,有些过重,不适用于那些对性能比较高的web站。其UI组件的封装相对复杂,不利于重用。而React却很好的解决了这个问题!
React不是一个完整的MVC,MVVM框架,其只负责View层。设计理念的不同决定了React比AngularJS轻得多!React运用一个虚拟的DOM实现了一个非常强大的渲染系统。但它并不仅仅是性能的提升,其思想是组件化开发!组件其就是封装起来具有独立功能的UI控件。React推崇的就是用组件的方式重新思考UI的构成,将UI上每一个独立功能的模块定义成组件,然后将小的组件通过组合或者嵌套的方式最终构成一个大的组件,完成整体UI的构建。
1.2应用场景
- 复杂场景下的高性能
- 重用组件库,组件组合
1.3 React特点
- 声明式设计 -- React采用声明范式,可以轻松描述应用。(目标取决于行动。)
- 高效 -- React通过对DOM的模拟,最大限度地减少与DOM的交互。
- 灵活 -- React可以与已知的库或框架很好地配合。
- .JSX -- JSX 是 JavaScript 语法的扩展。React 开发不一定使用 JSX ,但建议使用它。
- 组件 -- 通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中。
- 单向响应的数据流 -- React 实现了单向响应的数据流,从而减少了重复代码,这也是它为什么比传统数据绑定更简单。
1.4 React官网与安装
更多详细介绍请参考react官网https://facebook.github.io/react/index.html
Download之后解压可以看到:
2 React实例
2.1 HTML模板
在JavaScript代码里写着XML格式的代码称为JSX;为了兼容把 JSX 转成标准的 JavaScript ,我们把<script> 标签的 type 属性为 text/babel ;
实例中我们引入了三个库: react.min.js 、react-dom.min.js 和 browser.min.js:
react.min.js -- React 的核心库
react-dom.min.js -- 提供与 DOM 相关的功能
browser.min.js -- 用于将 JSX 语法转为 JavaScript 语法(这个比较耗时,上线时建议放到cdn上)
2.2 JSX
像这样在JavaScript里面类似于HTML标签的东西,它既不是一个字符串常量,也不是一个传统意义上的声明的变量,这种语法就叫做JSX(JavaScript XML)。一种在React组件内部构建标签的类XML语法。是Facebook 为React框架开发的一套语法糖(功能大致是为代码增加可读性)。JSX为我们带来的一大便利就是我们可以直接在JS中写类DOM的结构,比我们用原生的JS去拼接字符串再用正则替换等方式等等来渲染模板,方便和简单太多!除了”<h1></h1>”这样的原生HTML标签,还可以定义生成类似于HTML标签的自定义标签。
2.3 react components
React 允许将代码封装成组件(component),然后像插入普通 HTML 标签一样,在网页中插入这个组件。React.createClass 方法就用于生成一个组件类。
变量 HelloMessage 就是一个组件类。模板插入 <HelloMessage /> 时,会自动生成 HelloMessage 的一个实例。所有组件类都必须有自己的 render 方法,用于输出组件。
React Components最终要呈现到页面上,通过调用ReactDOM.render这个函数,
第一个参数是要渲染的React Components,第二个参数渲染完之后是要插入的位置的容器Element,上面代码这我们把HelloMessage 这个components插入到ID为test2的div里面。
注意,组件类的第一个字母必须大写,否则会报错,比如HelloMessage不能写成helloMessage。另外,组件类只能包含一个顶层标签,否则也会报错。也就是说上面代码中return 返回的h1标签只能是最外层,它不能有兄弟节点!
回过头来说创建我们用React.createClass 方法创建一个组件类,它的参数是一个JS的object。其中最重要的key是render,值是一个function,这个function返回值直接决定了这个Components被渲染出来是个什么样的结构!上面代码中其返回值是个h1元素,里面的值是文本 Hello {this.props.name},{}里面是要取得js文本表达式的值,this表示这个实例,props则是我们在使用这个react Components时在其(<HelloMessage name="world"/>)上面添加的属性的集合。比如 name 属性就可以通过 this.props.name 读取。
添加组件属性,有一个地方需要注意,就是 class 属性需要写成 className ,for 属性需要写成 htmlFor ,这是因为 class 和 for 是 JavaScript 的保留字。
2.4 this.props.children
this.props 对象的属性与组件的属性一一对应,但是有一个例外,就是this.props.children属性。它表示组件的所有子节点。
上面代码的 NoteList 组件有两个 span 子节点,它们都可以过 this.props.children 读取,运行结果如下。
2.5 PropTypes
随着应用不断变大,保证组件被正确使用变得非常有用。为此我们引入propTypes。React.PropTypes 提供很多验证器来验证传入数据的有效性。当向props传入无效数据时,JavaScript控制台会抛出警告。
上面的Mytitle组件有一个title属性。PropTypes 告诉 React,这个 title 属性是必须的,而且它的值必须是字符串。现在,我们设置 title 属性的值是一个数值。title属性就通不过验证了。控制台会显示一行错误信息。
React.PropTypes 的种类:
此外,getDefaultProps 方法可以用来设置组件属性的默认值。
上面代码会输出 Hello World。
2.6 获取真实的DOM节点
React Components包含下面代码的div、input标签,它代表的并不是一个真实的DOM节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM,只有插入文档后才会变成真实的DOM节点。根据 React 的设计,所有的 DOM 变动,都先在虚拟 DOM 上发生,然后再将实际发生变动的部分,反映在真实 DOM上,这种算法叫做 DOM diff ,它可以极大提高网页的性能表现。但是,有时需要从组件获取真实 DOM 的节点,这时就要用到 ref 属性。
2.7 this.state
每一个React组件都可以拥有自己的state,state与props的区别在于前者只存在于组件的内部。State可以用来确定一个元素的视图状态。
State可以通过setState来修改,也可以用上面出现的getInitialState方法提供一组默认值。只要setState被调用,render就会被调用。如果render函数的返回值有变化,虚拟DOM就会更新,真实的DOM也会被更新,最终用户就会在浏览区中看到变化。
千万不能直接修改this.state,永远记得要通过this.setState方法修改。
放在state和props的各是那些部分:
不要在state中保存计算出的值,而应该只保存最简单的数据,即那些组件正常工作时的必要数据。比如勾选状态,如果没有它就无法勾选复选框;比如输入框的值等等。不要尝试把props复制到state中。要尽可能把props当成数据源。
2.8 组件的生命周期
在组件的整个生命周期中,随着该组件的props或者state发生改变,它的DOM表现也将有相应的变化。一个组件就是一个状态机:对于特定的输入,它总会返回一致的输出。
React为每个组件提供了生命周期钩子函数去相应不同的时刻--创建时、存在期及销毁时我们在这里将按照这些时刻出现的顺序依次介绍--从实例化开始到活动期间,直到最后被销毁。
Mounted:React Components被render解析生成对应的DOM节点并被插入浏览器的DOM结构的一个过程;
Update:只得是一个Mounted的React Components被重新render的过程;
Unmounted:一个Mounted的React Components对应的DOM节点被从DOM结构中移除的这样一个过程;
每一个状态React都封装了对应的hook函数:
componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用
shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用
React 为每个状态都提供了两种处理函数,will 函数在进入状态之前调用,did 函数在进入状态之后调用,三种状态共计五种处理函数。
上面代码在Hello组件加载以后,通过 componentDidMount 方法设置一个定时器,每隔100毫秒,就重新设置组件的透明度,从而引发重新渲染。
React生命周期方法提供了精心设计的钩子函数,会伴随组件的整个生命周期。和状态机类似,每个组件都被设计成了能够在整个生命周期中输出稳定、语义化的标签。
2.9 子组件向父组件传值
工作中往往会遇到这样的问题,子组件如何向父组件传值?其实很简单,概括起来就是:react中state改变了,组件才会update。父写好state和处理该state的函数,同时将函数名通过props属性值的形式传入子,子调用父的函数,同时引起state变化。
看下面的例子:这里如下图,用户邮箱为父,绿色框为子。 父组件为用户输入的邮箱设好state,即“{email: ''}”,同时写好处理state的函数,即“handleEmail”,这两个名称随意起;再将函数以props的形式传到子组件,子组件只需在事件发生时,调用父组件传过来的函数即可。
有时候往往需要对数据做处理,再传给父组件,比如过滤或者自动补全等等,下面的例子对用户输入的邮箱做简单验证,自动过滤非数字、字母和"@."以外的字符。
如果还存在孙子组件的情况下就用this.props传。