1.react是什么?
React是Facebook开源的一个用于构建用户界面的Javascript库,已经 应用于Facebook及旗下Instagram。
和庞大的AngularJS不同,React专注于MVC架构中的V,即视图。 这使得React很容易和开发者已有的开发栈进行融合。
React顺应了Web开发组件化的趋势。应用React时,你总是应该从UI出发抽象出不同 的组件,然后像搭积木一样把它们拼装起来
这个项目本身也越滚越大,从最早的UI引擎变成了一整套前后端通吃的 Web App 解决方案。衍生的 React Native 项目,目标更是宏伟,希望用写 Web App 的方式去写 Native App。如果能够实现,整个互联网行业都会被颠覆,因为同一组人只需要写一次 UI ,就能同时运行在服务器、浏览器和手机
英文网:http://facebook.github.io/react/docs/getting-started.html
文档最新且更新快(推荐大家看这个)
中文网:http://reactjs.cn/react/docs/getting-started.html
文档陈旧版本低(大家如果看不懂英文可以先看这个)
为什么使用react?
我们创造 React 是为了解决一个问题:构建随着时间数据不断变化的大规模应用程序。为了达到这个目标,React 采用下面两个主要的思想。
1、简单
仅仅只要表达出你的应用程序在任一个时间点应该长的样子,然后当底层的数据变了,React 会自动处理所有用户界面的更新。
2、声明式 (Declarative)
数据变化后,React 概念上与点击“刷新”按钮类似,但仅会更新变化的部分。
3、构建可组合的组件
React 都是关于构建可复用的组件。事实上,通过 React 你唯一要做的事情就是构建组件。得益于其良好的封装性,组件使代码复用、测试和关注分离(separation of concerns)更加简单。
更多原因 http://facebook.github.io/react/blog/2013/06/05/why-react.html
react网站案例:智客网
http://www.kongkonghu.com/choice
https://github.com/webpack/react-starter
入门视频:
https://www.youtube.com/watch?v=7eLqKgp0eeY
https://www.youtube.com/watch?v=fZKaq623y38&list=PLQDnxXqV213JJFtDaG0aE9vqvp6Wm7nBg
https://www.youtube.com/watch?v=QQK5hpUuOuA&list=PLUAEXpf1UDMkzPOiNJBrlqsUryn7n2cnK
参考资料:
https://github.com/dingyiming/learn-Js-react/issues/1
2.react的四个概念
1.virtual DOM(实现跨平台、页面渲染速度快)
1> 虚拟DOM是React的基石。
之所以引入虚拟DOM,一方面是性能的考虑。Web应用和网站不同,一个Web应用 中通常会在单页内有大量的DOM操作,而这些DOM操作很慢。
在React中,应用程序在虚拟DOM上操作,这让React有了优化的机会。简单说, React在每次需要渲染时,会先比较当前DOM内容和待渲染内容的差异, 然后再决定如何最优地更新DOM。这个过程被称为reconciliation。
除了性能的考虑,React引入虚拟DOM更重要的意义是提供了一种一致的开发方 式来开发服务端应用、Web应用和手机端应用:
因为有了虚拟DOM这一层,所以通过配备不同的渲染器,就可以将虚拟DOM的内容 渲染到不同的平台。而应用开发者,使用JavaScript就可以通吃各个平台了。
相当棒的思路!
2>Virtual DOM速度快的说明
在Web开发中,我们总需要将变化的数据实时反应到UI上,这时就需要对DOM进行操作。而复杂或频繁的DOM操作通常是性能瓶颈产生的原因(如何 进行高性能的复杂DOM操作通常是衡量一个前端开发人员技能的重要指标)。React为此引入了虚拟DOM(Virtual DOM)的机制:在浏览器端用Javascript实现了一套DOM API。基于React进行开发时所有的DOM构造都是通过虚拟DOM进行,每当数据变化时,React都会重新构建整个DOM树,然后React将当前 整个DOM树和上一次的DOM树进行对比,得到DOM结构的区别,然后仅仅将需要变化的部分进行实际的浏览器DOM更新。而且React能够批处理虚拟 DOM的刷新,在一个事件循环(Event Loop)内的两次数据变化会被合并,例如你连续的先将节点内容从A变成B,然后又从B变成A,React会认为UI不发生任何变化,而如果通过手动控 制,这种逻辑通常是极其复杂的。尽管每一次都需要构造完整的虚拟DOM树,但是因为虚拟DOM是内存数据,性能是极高的,而对实际DOM进行操作的仅仅是 Diff部分,因而能达到提高性能的目的。这样,在保证性能的同时,开发者将不再需要关注某个数据的变化如何更新到一个或多个具体的DOM元素,而只需要 关心在任意一个数据状态下,整个界面是如何Render的。
http://blog.csdn.net/yczz/article/details/49585313
2.react组件
1>组件化的概念
虚拟DOM(virtual-dom)不仅带来了简单的UI开发逻辑,同时也带来了组件化开发的思想,所谓组件,即封装起来的具有独立功能的UI部 件。React推荐以组件的方式去重新思考UI构成,将UI上每一个功能相对独立的模块定义成组件,然后将小的组件通过组合或者嵌套的方式构成大的组件, 最终完成整体UI的构建。例如,Facebook的instagram.com整站都采用了React来开发,整个页面就是一个大的组件,其中包含了嵌套 的大量其它组件,大家有兴趣可以看下它背后的代码。
如果说MVC的思想让你做到视图-数据-控制器的分离,那么组件化的思考方式则是带来了UI功能模块之间的分离。我们通过一个典型的Blog评论界面来看MVC和组件化开发思路的区别。
对于MVC开发模式来说,开发者将三者定义成不同的类,实现了表现,数据,控制的分离。开发者更多的是从技术的角度来对UI进行拆分,实现松耦合。
对于React而言,则完全是一个新的思路,开发者从功能的角度出发,将UI分成不同的组件,每个组件都独立封装。
在React中,你按照界面模块自然划分的方式来组织和编写你的代码,对于评论界面而言,整个UI是一个通过小组件构成的大组件,每个组件只关心自己部分的逻辑,彼此独立。
组件的四个特性:
有自定义的标签
高内聚的资源
独立的作用域
规范化的接口
2>组件化开发特性
React认为一个组件应该具有如下特征:
(1)可组合(Composeable):一个组件易于和其它组件一起使用,或者嵌套在另一个组件内部。如果一个组件内部创建了另一个组件,那么说父组件拥有(own)它创建的子组件,通过这个特性,一个复杂的UI可以拆分成多个简单的UI组件;
(2)可重用(Reusable):每个组件都是具有独立功能的,它可以被使用在多个UI场景;
(3)可维护(Maintainable):每个小的组件仅仅包含自身的逻辑,更容易被理解和维护;
(4)可测试(Testable):因为每个组件都是独立的,那么对于各个组件分别测试显然要比对于整个UI进行测试容易的多。
3>组件定义
在React中定义一个组件也是相当的容易,组件就是一个 实现预定义接口的JavaScript类:
1、 组件渲染
ReactDOM.render 是 React 的最基本方法,用于将模板转为 HTML 语言,并插入指定的 DOM 节点。
ReactDOM.render( <h1>Hello, world!</h1>, document.getElementById('example') );
而这个方法, 必须而且只能返回一个有效的React元素。这意味着,如果你的组件是由多个元素构成的,那么你必须在外边包一个顶层 元素,然后返回这个顶层元素。比如我们创建一个布局组件:
render:function(){ return React.createElement( "div",null, React.createElement("div",null,"header"), React.createElement("div",null,"content"), React.createElement("div",null,"footer") ); }
2、ES5方式定义组件
"use strict"; var HelloMessage = React.createClass({ displayName: "HelloMessage", render: function render() { return React.createElement( "div", null, "Hello ", this.props.name ); } }); ReactDOM.render(React.createElement(HelloMessage, { name: "John" }), mountNode);
3、Jsx中定义组件
var HelloMessage = React.createClass({ render: function() { return <div>Hello {this.props.name}</div>; } }); ReactDOM.render(<HelloMessage name="John" />, mountNode);
4、ES6中定义组件
import './Hello.css'; import './Hello.scss'; import React, {Component} from 'react'; // 内联样式 let style={ backgroundColor:'blue' } export default class Hello extends Component { constructor(props) { super(props); this.state = { count: 'es6'}; } render() { return ( <div> <h1 style={style}>Hello world{this.state.count}</h1> <br/> <image/> </div> ) } }
5、注意事项
(1)你的React组件名称的首字母应当大写,关于大小写的差异你会在后面发现。
(2)你应该会注意到div元素的样式类是用 className而不是class声明的,这是因为class 是JavaScript的保留字,渲染后,真实的DOM还会是:
<div class="ez-led">Hello, React!</div>
3>jsx语法:
1.什么是jsx?
在用React写组件的时候,通常会用到JSX语法,粗看上去,像是在Javascript代码里直接写起了XML标签,实质上这只是一个语法糖,每一个 XML标签都会被JSX转换工具转换成纯Javascript代码,当然你想直接使用纯Javascript代码写也是可以的,只是利用JSX,组件的结 构和组件之间的关系看上去更加清晰
2.jsx语法使用:
HTML 语言直接写在 JavaScript 语言之中,不加任何引号,这就是 JSX 的语法,它允许 HTML 与 JavaScript 的混写。
var names = ['Alice', 'Emily', 'Kate']; ReactDOM.render( <div> { names.map(function (name) { return <div>Hello, {name}!</div> }) } </div>, document.getElementById('example') );
上面代码体现了 JSX 的基本语法规则:遇到 HTML 标签(以 <
开头),就用 HTML 规则解析;遇到代码块(以 {
开头),就用 JavaScript 规则解析。
JSX 允许直接在模板插入 JavaScript 变量。如果这个变量是一个数组,则会展开这个数组的所有成员
var arr
=
[
<h1
>Hello world
!</h1
>,
<h2
>React is awesome
</h2
>,
];
ReactDOM
.render(
<div
>{arr
}</div
>,
document
.getElementById('example')
);
上面代码的arr
变量是一个数组,结果 JSX 会把它的所有成员,添加到模板
4>单项数据流:Data Flow
* 1.传统的mvc
到了 Flux 当中, 除了名字改变了, 重要的是大量的 Model 归到了 Store, View 也统一了,从而得到了所谓单向的数据流, 就是 Model 和 View 之间关系非常清晰了。这样需要人为管理的状态就一下少了很多, 结果体现在开发应用的效率当中:
* 2.flux
1、详细学习地址:https://hulufei.gitbooks.io/react-tutorial/content/flux.html
2、React 标榜自己是 MVC 里面 V 的部分,那么 Flux 就相当于添加 M 和 C 的部分,Flux 是 Facebook 使用的一套前端应用的架构模式。
3、一个 Flux 应用主要包含四个部分:
(1)dispatcher 处理动作分发,维护 Store 之间的依赖关系
(2)stores 数据和逻辑部分
(3)views React 组件,这一层可以看作 controller-views,作为视图同时响应用户交互
(4)actions 提供给 dispatcher 传递数据给 store
4、单向数据流
先来了解一下 Flux 的核心“单向数据流“怎么运作的:
Action -> Dispatcher -> Store -> View
更多时候 View 会通过用户交互触发 Action,所以一个简单完整的数据流类似这样:
整个流程如下:
- 首先要有 action,通过定义一些 action creator 方法根据需要创建 Action 提供给 dispatcher
- View 层通过用户交互(比如 onClick)会触发 Action
- Dispatcher 会分发触发的 Action 给所有注册的 Store 的回调函数
- Store 回调函数根据接收的 Action 更新自身数据之后会触发一个 change 事件通知 View 数据更改了
- View 会监听这个 change 事件,拿到对应的新数据并调用 setState 更新组件 UI
所有的状态都由 Store 来维护,通过 Action 传递数据,构成了如上所述的单向数据流循环,所以应用中的各部分分工就相当明确,高度解耦了。
这种单向数据流使得整个系统都是透明可预测的。
Redux官方中文文档:http://camsong.github.io/redux-in-chinese/index.html
Reflux:https://segmentfault.com/a/1190000002793786?utm_source=tuicool
3.react快速开始学习:
1.创建项目文件夹
npm init // 初始化npm配置文件
2.依赖环境
在项目根目录下打开命令窗口下载react和react-dom依赖
npm install react react-dom --save
3.创建目录结构
4.简单的hello world demo
看官网英文官网的:http://facebook.github.io/react/index.html
Var React=require(‘react’); Var ReactDOM=require(‘react-dom’); var HelloMessage = React.createClass({ render: function() { return <div>Hello {this.props.name}</div>; } }); ReactDOM.render(<HelloMessage name="John" />, mountNode);
5.代码的编译方式(语法转换)
因为现在都是使用jsx和es6,所以我们需要对js代码进行编译。
编译转换有分为浏览器中转换和离线转换,但是基本上公司不会用在浏览器中引入转换js转换,所以我们只介绍离线转换
1>react-tools转换
这是react自己提供的,而且是老版本的,因为中文官网还是老版本的api,所以介绍的是这种方式。
npm install -g react-tools // 首先安装依赖 jsx --watch src/ build/ // 用命令进行转换,有兴趣的大家自己看一下jsx -h 参考地址:http://reactjs.cn/react/docs/getting-started.html
2>babel转换
英文官网的文档比较新,已经推荐使用babel来进行转换
1、下载依赖
npm install --global babel-cli // 安装babel npm install babel-preset-react -dev-save// 安装babel转换jsx的包 npm install babel-preset-es2015 -dev-save// 安装babel转化ES6的包 注意:加了-dev之后,运行npm install不会下载开发依赖,你需要运行 npm install –dev //从github上下载之后运行这句才能下载开发依赖
2、运行命令进行编译
babel --presets react src --watch --out-dir build // 更多命令可运行babel –h查看或者官网
3、将编译之后的js文件在index.html文件中引入
3>gulp-react
https://github.com/sindresorhus/gulp-react
4>webpack(我用这种)
4.主要知识内容
1>视图相关概念
- Props(属性,就是element上的attrs,换个名字property,变成复数,即props)
- State(写过view组件的基本都会知道,按钮有三态,Normal,Highlight,Selected,包括extjs,jquery里的大部分ui框架都是有状态的。)
- Event(其实还应该算一个就是dom事件,上面的例子就把onChange的handler编译后的handleChange方法,这要感谢jsx)
了解了上面这些,就可以写代码了,因为
- 属性,解决了view的定义问题,即语义描述
- 状态,是view的有穷状态机,根据状态决定组件ui和行为
- 事件,是view里元素的行为
有穷状态机:http://baike.baidu.com/view/115336.htm
2 > jsx语法详解
<1>HTML 转义(了解)
React 会将所有要显示到 DOM 的字符串转义,防止 XSS。所以如果 JSX 中含有转义后的实体字符比如 ©
(©) 最后显示到 DOM 中不会正确显示,因为 React 自动把 ©
中的特殊字符转义了。有几种解决办法:
- 直接使用 UTF-8 字符 ©
- 使用对应字符的 Unicode 编码
- 使用数组组装
<div>{['cc ', <span>©</span>, ' 2015']}</div>
- 直接插入原始的 HTML
<div dangerouslySetInnerHTML={{__html: 'cc © 2015'}} />
dangerouslySetInnerHTML参考文档
http://reactjs.cn/react/tips/dangerously-set-inner-html.html
<2>自定义 HTML 属性(了解)
如果在 JSX 中使用的属性不存在于 HTML 的规范中,这个属性会被忽略。如果要使用自定义属性,可以用 data-
前缀。文档估计有问题
可访问性属性的前缀 aria-
也是支持的。
与dom的区别文档:http://reactjs.cn/react/docs/dom-differences.html
<3>支持的标签和属性
如果你要使用的某些标签或属性不在这些支持列表里面就可能被 React 忽略,必须要使用的话可以提 issue,或者用前面提到的 dangerouslySetInnerHTML
。
支持列表:http://reactjs.cn/react/docs/tags-and-attributes.html
1、并不是所有的html标签和属性都能在jsx语法中使用
2、基本上你能用到的标签的属性,jsx语法都支持
3、有些特殊的属性需要注意,必须class属性要变为className属性
所有的属性都是驼峰命名的,class
属性和 for
属性分别改为 className
和 htmlFor
,来符合 DOM API 规范。
<4>属性扩散
有时候你需要给组件设置多个属性,你不想一个个写下这些属性,或者有时候你甚至不知道这些属性的名称,这时候 spread attributes 的功能就很有用了。
var props = {}; props.foo = x; props.bar = y; var component = <Component {...props} />;
属性也可以被覆盖,写在后面的属性值会覆盖前面的属性。
var props = { foo: 'default' }; var component = <Component {...props} foo={'override'} />; console.log(component.props.foo); // 'override'
<5> 自闭合标签(组件标签可以使用单闭合标签也可以使用双闭合标签)
如果只有一个组件,就用单闭合标签形式,如果有多个组件嵌套就用双闭合标签形式
http://reactjs.cn/react/tips/self-closing-tag.html
<6> 注释
在 JSX 里使用注释也很简单,就是沿用 JavaScript,唯一要注意的是在一个组件的子元素位置使用注释要用 {}
包起来
var content = ( <Nav> {/* child comment, put {} around */} <Person /* multi line comment */ name={window.isLoggedIn ? window.name : ''} // end of line comment /> </Nav> );
3>React的API
<1> 顶层API
http://facebook.github.io/react/docs/top-level-api.html
<2> 组件API
http://facebook.github.io/react/docs/component-api.html
4>组件的生命周期(特别重要)
组件的生命周期,另外的名字是状态回调,和上面讲的状态的唯一差别,上面的状态是它里面的元素,而组件的生命周期是它自己
https://hulufei.gitbooks.io/react-tutorial/content/component-lifecycle.html
<1> 组件的生命周期分成三个状态:
- Mounting:已插入真实 DOM
- Updating:正在被重新渲染
- Unmounting:已移出真实 DOM
<2> 处理函数
React 为每个状态都提供了两种处理函数,will函数在进入状态之前调用,did 函数在进入状态之后调用,三种状态共计五种处理函数。
- componentWillMount()
- componentDidMount()
- componentWillUpdate(object nextProps, object nextState)
- componentDidUpdate(object prevProps, object prevState)
- componentWillUnmount()
此外,React 还提供两种特殊状态的处理函数。
- componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用
- shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用
<3> 函数调用顺序图
从上图中我们可以看出来,组件再初始化一次之后就不会再运行上图运行中文字以上的方法,反而里面会有事件监听,从而执行shouleComponentUpdate事件。
<4>代码使用
ES5写法
var Hello = React.createClass({ getInitialState() { return { liked: false }; }, render: function() { console.log(this.state.liked); return( <div> <h1 style={style}>Hello world</h1> <br/> <image/> </div> ) } }); module.exports=Hello;
ES6写法
export default class Hello extends Component { constructor(props) { super(props); this.state = { count: 'es6'}; } render() { return ( <div> <h1 style={style}>Hello world{this.state.count}</h1> <br/> <image/> </div> ) } }
<5> 参考文章
生命周期详细介绍:http://www.cnblogs.com/CHONGCHONG2008/p/5099483.html
http://reactjs.cn/react/docs/component-specs.html
<6>注意点
在ES6中用ES5的写法会报错
5>ES5/ES6最新写法对照表
React的:
http://www.tuicool.com/articles/equ2my
ReactNative的
6>事件处理
<1> 使用
onClick这种进行驼峰命名ES5和ES6的写法不一样,在ES6中要用bind方法绑定this(具体可参照ES5和ES6写法对照表)
import React, { Component } from 'react'; import { render } from 'react-dom'; export default class LinkButton extends Component { constructor(props) { super(props); this.state = {liked: false}; } handleClick(e) { this.setState({ liked: !this.state.liked }); } render() { const text = this.state.liked ? 'like' : 'haven\'t liked'; return ( <p onClick={this.handleClick.bind(this)}> You {text} this. Click to toggle. </p> ); } }
<2>参数传递
ES6写法:给事件处理函数传递额外参数的方式:bind(this, arg1, arg2, ...)
render: function() { return <p onClick={this.handleClick.bind(this, param1,param2,param3)}>; }, handleClick: function(param1,param2,param3, event) { // handle click }
<3>React 支持的事件列表
http://reactjs.cn/react/docs/events.html
7>Dom操作
<1>方法一:findDOMNode()方法(了解)
首先我们要了解 ReactDOM.render 组件返回的是对组件的引用也就是组件实例(对于无状态状态组件来说返回 null),注意 JSX 返回的不是组件实例,它只是一个 ReactElement 对象。
当组件加载到页面上之后(mounted),你都可以通过 react-dom 提供的 findDOMNode() 方法拿到组件对应的 DOM 元素。
import { findDOMNode } from 'react-dom'; // Inside Component class componentDidMound() { const el = findDOMNode(this); } findDOMNode() 不能用在无状态组件上。
<2>方法二:refs属性
另外一种方式就是通过在要引用的 DOM 元素上面设置一个 ref
属性指定一个名称,然后通过 this.refs.name
来访问对应的 DOM 元素。
如果 ref
是设置在原生 HTML 元素上,它拿到的就是 DOM 元素,如果设置在自定义组件上,它拿到的就是组件实例,这时候就需要通过 findDOMNode
来拿到组件的 DOM 元素。
因为无状态组件没有实例,所以 ref 不能设置在无状态组件上,一般来说这没什么问题,因为无状态组件没有实例方法,不需要 ref 去拿实例调用相关的方法,但是如果想要拿无状态组件的 DOM 元素的时候,就需要用一个状态组件封装一层,然后通过 ref
和 findDOMNode
去获取。
import React, { Component } from 'react'; export default class MyInputFocus extends Component { constructor(props) { super(props); this.state={ userInput: '' }; } handleChange(e) { console.log(this.refs.theInput.value); this.setState({ userInput: e.target.value }); } clearAndFocusInput() { this.setState({ userInput: '' }, () => { this.refs.theInput.focus(); }); } render() { return ( <div> <div onClick={this.clearAndFocusInput.bind(this)}> Click to Focus and Reset </div> <input ref="theInput" value={this.state.userInput} onChange={this.handleChange.bind(this)} /> </div> ); } } MyInputFocus.defaultProps={ autoPlay:false, maxLoops:10, } MyInputFocus.propTypes = { autoPlay: React.PropTypes.bool.isRequired, maxLoops: React.PropTypes.number.isRequired, }
<3>注意事项
- 你可以使用 ref 到的组件定义的任何公共方法,比如 this.refs.myTypeahead.reset()
- Refs 是访问到组件内部 DOM 节点唯一可靠的方法
- Refs 会自动销毁对子组件的引用(当子组件删除时)
- 不要在 render 或者 render 之前访问 refs
- 不要滥用 refs,比如只是用它来按照传统的方式操作界面 UI:找到 DOM -> 更新 DOM
8>和其他库配合使用
http://reactjs.cn/react/tips/use-react-with-other-libraries.html
9>组件的 DOM 事件监听
这篇文章是讲如何给 DOM 元素绑定 React 未提供的事件
var Box = React.createClass({ getInitialState: function() { return {windowWidth: window.innerWidth}; }, handleResize: function(e) { this.setState({windowWidth: window.innerWidth}); }, componentDidMount: function() { window.addEventListener('resize', this.handleResize); }, componentWillUnmount: function() { window.removeEventListener('resize', this.handleResize); }, render: function() { return <div>Current window width: {this.state.windowWidth}</div>; } }); React.render(<Box />, mountNode);
http://reactjs.cn/react/tips/dom-event-listeners.html
1、注意添加dom事件的位置
2、在组件退出的时候,取消监听事件
10>数据获取
http://facebook.github.io/react/tips/initial-ajax.html
11>表单
表单不同于其他 HTML 元素,因为它要响应用户的交互,显示不同的状态,所以在 React 里面会有点特殊。
<1>状态属性
表单元素有这么几种属于状态的属性:
- value,对应 <input> 和 <textarea> 所有
- checked,对应类型为 checkbox 和 radio 的 <input> 所有
- selected,对应 <option> 所有
在 HTML 中 <textarea> 的值可以由子节点(文本)赋值,但是在 React 中,要用 value 来设置。
表单元素包含以上任意一种状态属性都支持 onChange 事件监听状态值的更改。
针对这些状态属性不同的处理策略,表单元素在 React 里面有两种表现形式。
<2>受控组件
对于设置了上面提到的对应“状态属性“值的表单元素就是受控表单组件,比如:
render: function() {
return <input type="text" value="hello"/>;
}
一个受控的表单组件,它所有状态属性更改涉及 UI 的变更都由 React 来控制(状态属性绑定 UI)。比如上面代码里的 <input> 输入框,用户输入内容,用户输入的内容不会显示(输入框总是显示状态属性 value 的值 hello),这有点颠覆我们的认知了,所以说这是受控组件,不是原来默认的表单元素了。
如果你希望输入的内容反馈到输入框,就要用 onChange 事件改变状态属性 value 的值:
getInitialState: function() { return {value: 'hello'}; }, handleChange: function(event) { this.setState({value: event.target.value}); }, render: function() { var value = this.state.value; return <input type="text" value={value} onChange={this.handleChange} />; } 使用这种模式非常容易实现类似对用户输入的验证,或者对用户交互做额外的处理,比如截断最多输入140个字符: handleChange: function(event) { this.setState({value: event.target.value.substr(0, 140)}); }
<3>非受控属性
和受控组件相对,如果表单元素没有设置自己的“状态属性”,或者属性值设置为 null,这时候就是非受控组件。
它的表现就符合普通的表单元素,正常响应用户的操作。
同样,你也可以绑定 onChange 事件处理交互。
如果你想要给“状态属性”设置默认值,就要用 React 提供的特殊属性 defaultValue,对于 checked 会有 defaultChecked,<option> 也是使用 defaultValue。
<4>为什么要有受控组件
引入受控组件不是说它有什么好处,而是因为 React 的 UI 渲染机制,对于表单元素不得不引入这一特殊的处理方式。
在浏览器 DOM 里面是有区分 attribute 和 property 的。attribute 是在 HTML 里指定的属性,而每个 HTML 元素在 JS 对应是一个 DOM 节点对象,这个对象拥有的属性就是 property(可以在 console 里展开一个 DOM 节点对象看一下,HTML attributes 只是对应其中的一部分属性),attribute 对应的 property 会从 attribute 拿到初始值,有些会有相同的名称,但是有些名称会不一样,比如 attribute class
对应的 property 就是 className
。(详细解释:.prop,.prop() vs .attr())
回到 React 里的 <input>
输入框,当用户输入内容的时候,输入框的 value
property 会改变,但是 value
attribute 依然会是 HTML 上指定的值(attribute 要用 setAttribute
去更改)。
React 组件必须呈现这个组件的状态视图,这个视图 HTML 是由 render
生成,所以对于
render: function() { return <input type="text" value="hello"/>; }
在任意时刻,这个视图总是返回一个显示 hello
的输入框。
<5> <select>
的处理
在 HTML 中 <select>
标签指定选中项都是通过对应 <option>
的 selected
属性来做的,但是在 React 修改成统一使用 value
。
所以没有一个 selected
的状态属性。
<select value="B">
<option value="A">Apple
</option>
<option value="B">Banana
</option>
<option value="C">Cranberry
</option>
</select>
你可以通过传递一个数组指定多个选中项:<select multiple={true} value={['B', 'C']}>
12>参数传递的判断
http://facebook.github.io/react/docs/transferring-props.html
13>组合组件
使用组件的目的就是通过构建模块化的组件,相互组合组件最后组装成一个复杂的应用。
在 React 组件中要包含其他组件作为子组件,只需要把组件当作一个 DOM 元素引入就可以了。
http://reactjs.cn/react/docs/multiple-components.html
<1> 循环插入子元素
如果组件中包含通过循环插入的子元素,为了保证重新渲染 UI 的时候能够正确显示这些子元素,每个元素都需要通过一个特殊的 key 属性指定一个唯一值。为了内部 diff 的效率。
var TodoList = React.createClass({ render: function() { var createItem = function(item) { return <li key={item.id}>{item.text}</li>; }; return <ul>{this.props.items.map(createItem)}</ul>; } }); module.export=TodoList
(1)当 React 校正带有 key 的子级时,它会确保它们被重新排序(而不是破坏)或者删除(而不是重用)。 务必
把 key
添加到子级数组里组件本身上,而不是每个子级内部最外层 HTML 上。
(2)也可以传递 object 来做有 key 的子级。object 的 key 会被当作每个组件的 key。但是一定要牢记 JavaScript 并不总是保证属性的顺序会被保留。实际情况下浏览器一般会保留属性的顺序,除了 使用 32位无符号数字做为 key 的属性。数字型属性会按大小排序并且排在其它属性前面。一旦发生这种情况,React 渲染组件的顺序就是混乱。可能在 key 前面加一个字符串前缀来避免:
render: function() { var items = {}; this.props.results.forEach(function(result) { // 如果 result.id 看起来是一个数字(比如短哈希),那么 // 对象字面量的顺序就得不到保证。这种情况下,需要添加前缀 // 来确保 key 是字符串。 items['result-' + result.id] = <li>{result.text}</li>; }); return ( <ol> {items} </ol> ); }
<2>子级
组件标签里面包含的子元素会通过父元素的props.children 传递进来。
HTML 元素会作为 React 组件对象、JS 表达式结果是一个文字节点,都会存入 Parent
组件的 props.children
。
props.children
通常是一个组件对象的数组,但是当只有一个子元素的时候,props.children
将是这个唯一的子元素,而不是数组了
var NotesList = React.createClass({ render: function() { return ( <ol> { React.Children.map(this.props.children, function (child) { return <li>{child}</li>; }) } </ol> ); } }); ReactDOM.render( <NotesList> <span>hello</span> <span>world</span> </NotesList>, document.body );
上面代码的 NoteList 组件有两个 span 子节点,它们都可以通过 this.props.children 读取,运行结果如下。
这里需要注意, this.props.children 的值有三种可能:如果当前组件没有子节点,它就是 undefined ;如果有一个子节点,数据类型是 object ;如果有多个子节点,数据类型就是 array 。所以,处理 this.props.children 的时候要小心。
React 提供一个工具方法 React.Children 来处理 this.props.children 。我们可以用 React.Children.map 来遍历子节点,而不用担心 this.props.children 的数据类型是 undefined 还是 object。更多的 React.Children 的方法,请参考官方文档。
14>propsType
http://www.reactjs.cn/react/docs/reusable-components.html
15>Context
http://facebook.github.io/react/docs/context.html
16>动画
http://facebook.github.io/react/docs/animation.html
http://blog.csdn.net/lihongxun945/article/details/46778723
https://zhuanlan.zhihu.com/p/20419592
17>获取react常用插件的网址
https://js.coach/react/react-infinite
18>diff算法
http://blog.csdn.net/lihongxun945/article/details/46640503
http://reactjs.cn/react/docs/reconciliation.html
http://blog.csdn.net/yczz/article/details/49585283
http://blog.csdn.net/yczz/article/details/49886061
19>Web Components
http://www.oschina.net/p/polymer
http://facebook.github.io/react/docs/webcomponents.html
20>服务器渲染
http://zhuanlan.zhihu.com/p/20669111?from=groupmessage&isappinstalled=0
21>组件间通信
<1>非父子组件间的通信
使用全局事件 Pub/Sub 模式,在 componentDidMount
里面订阅事件,在 componentWillUnmount
里面取消订阅,当收到事件触发的时候调用 setState
更新 UI。
这种模式在复杂的系统里面可能会变得难以维护,所以看个人权衡是否将组件封装到大的组件,甚至整个页面或者应用就封装到一个组件。
一般来说,对于比较复杂的应用,推荐使用类似 Flux 这种单项数据流架构,参见Data Flow。Flux和redux
<2>数据流Flux
Github地址:https://github.com/facebook/flux
React redux react-redux react-router webpack+gulp ES6 babel
Mocha+chai node
React native Flex fetch 原生 找插件
22>react-router
<1>学习网址
github地址:https://github.com/reactjs/react-router
最好是去github上看文档,因为随着时间的推移,版本的变更,市面上的一些文档已经没有及时性和准确性了。Github上已经有好几个版本的了,我们学习最新版本的。以后如果有问题先检查版本是不是升级导致的问题。
gitbook地址:http://react-guide.github.io/react-router-cn/
https://segmentfault.com/a/1190000006063554
<2>react-router简介
React Router 是一个基于 React之上的强大路由库,它可以让你向应用中快速地添加视图和数据流,同时保持页面与 URL 间的同步。
<3>之前页面跳转的实现(了解)
http://react-guide.github.io/react-router-cn/docs/Introduction.html
<4>基础配置
1、他会把route的第一个组件加载到根组件的this.chileren里面
2、下面这种写法会报错
<a><Link to="/indox/messages/1">message</Link></a>
3、刷新的错误
React-router升级说明
2.X https://github.com/reactjs/react-router/blob/master/upgrade-guides/v2.0.0.md#no-default-history
History文档
https://github.com/mjackson/history
利用reauest模块实现服务代理:
利用fetch获取数据: