###入门印象
- 传统组件化的特点是把组件和原生DOM节点的渲染割裂起来
- 现代的组件架构鼓励原生DOM节点和自定义组件的统一渲染融合,比如React以及未来的Web Components规范
- React最为人称道的是,它是一个专注于组件架构的类库。
- 要想用好React,我们必须跳出以往的思维,拥抱React的理念和思想,比如状态,虚拟DOM,组合优于继承,单向数据流。
- React专注于组件架构,所以模块系统可以直接采用CommonJS,测试框架可以使用Mocha,生态圈则可以直接依托npm,工具可以采用现成的Browserify或Webpack。
- React本质上是一个“状态机”,可以帮助开发者管理复杂的随着时间而变化的状态。它以一个精简的模型实现了这一点。React只关心两件事:更新DOM和响应事件。
- React不处理Ajax、路由和数据处理,也不规定数据组织的方式,它不是一个MVC框架。事实上,它已经在数个MVC框架中被用来渲染视图了。
- React 不是一个完整的MVC,MVVM框架
- React 跟 Web Components不冲突
- React 的特点就是轻
###JSX
- 在React中,组件是用于分离关注点的,而不是被当作模版或处理显示逻辑的。
- React包含了一种可选的类HTML标记语言。
- JSX即JavaScript XML,一种在React组件内部构建标签的类XML语法。
- JSX 会转换为原生的JS函数,因此有一些关键词我们是不能用的
- for 要转换成 htmlFor
- class 要转换成 className
- React把所有的内联样式都规范化为了驼峰形式,与JS中DOM的style属性一样。
var R = React.DOM;
React在React.DOM.*
命名空间下提供了一系列的工厂,如:R.div(),R.hr(),R.h2(null,'label text')
;- React 自动绑定了组件所有方法的作用域,因此你不需要手动绑定。
this.props.children
React将开始标签和结束标签之间的所有的子节点保存在一个名为this.props.children
的特殊组件属性中。React.createClass()
###版本演进
- React 「一分为二」
原本的 react 被拆分为 react 及 react-dom 两个 package。
- 其中 react package 中包含React.createElement、 .createClass、 .Component, .PropTypes, .Children 这些 API。
- 而 react-dom package 中包含 ReactDOM.render、 .unmountComponentAtNode、 .findDOMNode。
原本在服务端渲染用的两个 API .renderToString 和 .renderToStaticMarkup 被放在了 react-dom/server 中。
此外,原本 React.addons 下面的工具全部变成了独立的 package
- react-addons-clone-with-props
- react-addons-create-fragment
- react-addons-css-transition-group
- react-addons-linked-state-mixin
- react-addons-perf
- react-addons-pure-render-mixin
- react-addons-shallow-compare
- react-addons-test-utils
- react-addons-transition-group
- react-addons-update
- ReactDOM.unstable_batchedUpdates (在 react-dom 中)
- refs 变成了真正的 DOM 节点。当我们需要获取 React 组件上某个 DOM 节点时,React 提供了 refs 方法方便我们快速引用。为了方便我们使用,React 还「贴心」地对 refs 做了一层封装,使用 。this.refs.xxx.getDOMNode() 或 React.findDOMNode(this.refs.xxx) 可以获取到真正的 DOM 节点。
- react-tools 及 JSXTransformer.js 已弃用。
- React.initializeTouchEvents 已弃用。
- props 一旦创建永远不可修改,因此 .setProps 及 .replaceProps 已废弃。
- children 不可以传对象类型,推荐传入数组,或使用 React.createFragment 方法(其实就是转换为了数组)。
- React.addons.classSet 已经移除,使用 classnames package 替代。
###生命周期函数
创建时
- getDefaultProps() // 对于那些没有被父辈组件指定props属性的新建实例来说,这个方法返回的对象可用于为实例设置默认的props值
- getInitialState() // 初始化每个实例的state
- componentWillMount() // 该方法在完成首次渲染之前被调用,这也是在render方法调用前可以修改组件state的最后一次机会
- render() // 创建一个虚拟DOM,用来表示组件的输出。对于一个组件来说,render是唯一一个必需的方法,并且有特定的规则。(是什么规则?)
- componentDidMount() // 在render方法成功调用并且真实的DOM已经被渲染出来之后,你可以在componentDidMount内部通过(?)来访问到它。(this.getDOMNode())
存在时
- componentWillReceiveProps() // 任意时刻,组件的props都可以通过父辈组件来修改,在这个函数中你也将获得更改props对象以及更新state的机会
- shouldComponentUpdate()
- componentWillUpdate() // 组件会在接收到新的props或者state进行渲染之前,调用该方法,不可以在该方法中更新state或者props
- componentDidUpdate() //
销毁时
- componentWillUnmount() // 在组件被销毁之前调用这个方法,来做一些清除工作
![[react]](/2016/09/13/React入门/react1.png)
###数据流
- 在React中,数据的流向是单向的,从父节点传递到子节点,因而组件是简单且易把握的,他们只需从父节点获取props渲染即可。
- React内部还具有自己的状态state,这些状态只能在组件内修改。
- 你可以把React组件看成一个函数,它接受props和state作为参数,返回一个虚拟的DOM表现。
- 使用
props
把任意类型的数据传递给组件。 - 可以通过this.props访问props,但绝对不可以通过这种方式修改它,一个组件绝对不可以自己修改自己的props。
- propTypes 通过在组件中定义一个配置对象,React提供了一种验证props的方式。
- state只存在于组件内部
- 千万不能直接修改this.state,永远记得要通过this.setState方法来修改。
- props are immutable: they are passed from the parent and are “owned” by the parent.
- To implement interactions, we introduce mutable
state
to the component.this.state
is private to the component and can be changed by callingthis.setState()
. When the state updates,the component rerenders itself. - 使用
props
在整个组件树中传递数据和配置 - 避免在组件内部修改
this.props
或调用this.setProps
,请把props
当作只读的(immutable) - 使用
props
来做事件处理器,与子组件通信 - 使用
state
存储简单的视图状态 - 使用
this.setState
来设置状态,而不要使用this.state
直接修改状态 - 不要尝试把
props
复制到state
中,要尽可能把props
当作数据源。 - 更新组件内部状态会触发组件重绘。
- 更新组件状态有两种方案,组件的
setState()
和replaceState()
,更多的情况下会使用setState()
,仅仅是把传入的对象合并到已有的state对象上。
###事件处理
- React 通过将事件处理器绑定到组件上来处理事件,在事件被触发的同时,更新组件的内部状态(state),组件内部状态(state)的更新会触发组件重绘。
- React 绑定事件处理器的语法和HTML语法非常类似,但性能是不一样的。
###组件
- 在传统HTML中,元素是构成页面的基础单元,但在React中,构成页面的基础单元是React组件。你可以把React组件理解成混入了JS表达能力的HTML元素,实际上写React代码主要就是构建组件,就像编写HTML文档时使用元素一样。
- 复合(composability)
- 本质上,一个组件就是一个JS函数,它接受属性(props)和状态(state)作为参数,并输出渲染好的HTML。
- 组件的核心理念就是可预测性和可预知性。
- 在React中,表单组件有两种类型:约束组件和无约束组件。
- 无约束组件可以用在基本的无须任何验证或者输入控制的表单中。
- 约束组件的模式与React其他类型组件的模式一致,表单组件的状态交由React组件控制,状态值被存储在state中。
###动画
- 动画可以让用户体验变得更加流畅与自然。
- TransitionGroup(插件) + CSS3 => CSSTransitionGroup(CSS渐变组)
- CSSTransitionGroup 会在合适的渲染、重渲染时间点有策略地添加和移除元素的class,以此来简化将CSS动画应用于渐变的过程。而你唯一需要做的是给些class写明合适的样式。
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
<ReactCSSTransitionGroup transitionName='xx'>{...}</ReactCSSTransitionGroup>
- 使用渐变组需要注意两点:1、渐变组会延迟子组件的移除直到动画完成。2、渐变组的每一个子组件都必须设置一个唯一的
key
属性。 - 默认情况下,渐变组同时启用了进入和退出的动画,可以通过给组件添加
transitionEnter={false}
或者transitionLeave={false}
属性来控制。
###实例
- 官网留言组件,数据流,事件绑定,如果看不懂、迷糊,很简单,那就反复看上几十遍,手敲十几遍,就什么都懂了。
- 官方案例基本思想:React构件组件,jQuery之Ajax获取数据,Express搭建服务器。
|
|
###官方示例(react-15.3.2)
- 总体来说需要三个文件的支持,react.js、react-dom.js、babel.js,解释就是,react是核心,react-dom是操作DOM,babel.js是编译(因为jsx或者es6大部分浏览器还无法直接识别的缘故)。
- 如果你直接使用babel.js插入到html中,那么这样是没有什么问题的,但是只能用于开发环境,如果是上线的话,是需要提前编译好,而不是在浏览器中来编译。如何手工来编译呢,那么先安装命令吧,
npm isntall -g babel-cli
,这是全局安装babel命令;接着再安装语言版本,这个直接放在工程中的开发依赖中好了,使用这个命令npm install --save-dev babel-preset-react
,然后就可以命令行来编译了,babel example.js --presets react --out-dir=build
,这个命令的意思是编译example.js并输出到build目录下。 - basic-jsx(内置jsx),basic-jsx-external(外部jsx),basic-jsx-harmony(使用es6语法的jsx),basic-jsx-precompile(预编译jsx语法)
- jquery-bootstrap(react和bootstrap结合)
- jquery-mobile(react和jquery mobile结合)
###技术栈(babel)
- 在React实例中发现这样一段 JS 引入
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
,这是什么意思? - 使用babel-standalone模块提供的浏览器版本,将其插入网页,网页中实时将ES6代码转为ES5,对性能会有影响。生产环境需要加载已经转码完成的脚本。浏览器会提示:
You are using the in-browser Babel transformer. Be sure to precompile your scripts for production - https://babeljs.io/docs/setup/
- 在react 0.14前,浏览器端实现对jsx的编译依赖jsxtransformer.js 。
- 在react 0.14后,这个依赖的库改为browser.js,页面script标签的type也由text/jsx改为text/babel,但是以上只能用来测试学习react,生产环境需要借助编译工具事先将jsx编译成js,对应的这个工具也由react-tool更换为babel。
.babelrc
babel的配置文件,必需的,放置在根目录下。包含两个字段,"presets"
和"plugins"
,其中 presets 很重要,官方提供了三个规则集,如下:
|
|
###ERROR集合
- 在 render 中的标签需要闭合,自闭合标签也需要闭合。
Uncaught Invariant Violation: Minified React error #37;
浏览器提示这种错误,最后在ReactDOM.render()发现错误,第二个参数指定的容器不存在,导致错误。- React 对
this
的态度,React 自动绑定了组件所有方法的作用域,因此你永远都不需要手动绑定。但是,如果产生了闭包,就需要手动来绑定了。
|
|
###工作流程
一个是编译:将 JSX (或者你用了 ES6 的特性的话也需要这一步)编译到被浏览器广泛支持的 ES5 的代码。
第二个是进行模块绑定:因为浏览器不识得这些模块(通常是编译成 ES5 的 CommonJS 规范实现的模块,这并不是浏览器支持的东西),不知道怎么去加载他们,模块绑定就是根据模块之间的依赖关系,将其“合并”到单个或者几个 JS 文件,让程序能直接被浏览器执行。
第一个编译的步骤可以直接交给 Babel 搞定。
第二个步骤的话,目前推荐用 webpack 做比较方便。
再之就是用 Gulp 控制那两个工具去处理源代码和输出了,总体上是这么个流程。
细节的比如 uglify,sourcemap 之类的事情都可以通过上述工具便捷地完成。
###番外(ESLint)
- ESLint 支持JSX语法的检测,包含JSLint等功能,作者为
红宝书的作者
- 全局安装
npm install eslint -g
- 配置文件
.eslintrc
,新建此文件在你需要的根目录下即可(并填入相应的配置项) - 忽略文件
.eslintignore
.eslintrc
的基本配置项如下所示:- 1234567891011121314151617{"extends": "eslint:recommended","env":{"node":true,"es6":true},"rules": {"semi": ["error", "always"],"quotes": "off","no-console":"off","no-unused-vars":"off","no-unreachable":"off","no-redeclare":"warn"}}
如需要自动修复一些不规范的代码问题,例如没有分号的问题,可以在目录终端下输入命令
eslint . --fix
来进行修复
###番外($.ajax)
- 是jQuery最底层的Ajax实现
- 语法
$.ajax(options)
,options为参数对象,这个对象中包含了所需要的请求设置以及回调函数等信息,参数以key/value的形式存在,所有参数都是可选的。 - 介绍一个体验优化参数,
global
参数,它的value是boolean类型的,默认为true,表示触发全局Ajax事件,设置为false将不会触发全局Ajax事件 - 全局Ajax事件有6个:
ajaxStart(callback)
ajaxStop(callback)
ajaxComplete(callback)
ajaxError(callback)
ajaxSend(callback)
ajaxSuccess(callback)
- 使用这些全局Ajax事件就是在用户发起Ajax请求后,为了让用户知道服务器正在处理数据,了解当前的变化,不至于让用户感到茫然,及时给用户一些反馈。
- 比如在
ajaxStart()
中启动一个新的类名,在此类名下,按钮或者某块区域给出动态提示,接着在ajaxStop()
中移除这个类名,表示完成了Ajax请求。
###资源链接
- React工程目录搭建
- 最好的文档 官方文档 (可能需要翻墙访问)