const App = ( <Nav> {/* 节点注释 */} <Person /* 多行 注释 */ name={window.isLoggedIn ? window.name : ''} /> </Nav> );
但 HTML 中有一类特殊的注释——条件注释,它经常使用于判断浏览器的版本:html
<!--[if IE]> <p>Work in IE browser</p> <![endif]-->
上述方法能够经过使用 JavaScript 判断浏览器版原本替代: react
{ (!!window.ActiveXObject || 'ActiveXObject' in window) ? <p>Work in IE browser</p> : '' }
元素属性 算法
class 属性改成 className 浏览器
for 属性改成 htmlFor 缓存
React 组件的构建less
React.createClassdom
const Button = React.createClass({ getDefaultProps() { return { color: 'blue', text: 'Confirm', }; }, render() { const { color, text } = this.props; return ( <button className={`btn btn-${color}`}> <em>{text}</em> </button> ); } });
只用写成 <Button />,就能够被解析成 React.createElement(Button) 方法来建立 Button
实例,这意味着在一个应用中调用几回 Button,就会建立几回 Button 实例异步
ES6 classes函数
import React, { Component } from 'react'; class Button extends Component { constructor(props) { super(props); } static defaultProps = { color: 'blue', text: 'Confirm', }; render() { const { color, text } = this.props; return ( <button className={`btn btn-${color}`}> <em>{text}</em> </button> ); } }
React 的全部组件都继承自顶层类 React.Component。它的定义很是简洁,只是初始化了
React.Component 方法,声明了 props、context、refs 等,并在原型上定义了 setState 和
forceUpdate 方法。内部初始化的生命周期方法与 createClass 方式使用的是同一个方法
建立的。优化
无状态函数(stateless function)
function Button({ color = 'blue', text = 'Confirm' }) { return ( <button className={`btn btn-${color}`}> <em>{text}</em> </button> ); }
无状态组件只传入 props 和 context 两个参数;也就是说,它不存在 state,也没有生命周
期方法,组件自己即上面两种 React 组件构建方法中的 render 方法。不过,像 propTypes 和
defaultProps 仍是能够经过向方法设置静态属性来实现的。
在适合的状况下,咱们都应该且必须使用无状态组件。无状态组件不像上述两种方法在调用
时会建立新实例,它建立时始终保持了一个实例,避免了没必要要的检查和内存分配,作到了内部
优化。
React 数据流
若是顶层组件初始化 props,那么 React 会向下遍历整棵组件树,从新尝试渲染全部相关的子组件。
而 state 只关心每一个组件本身内部的状态,这些状态只能在组件内改变。
把组件当作一个函数,那么它接受了 props 做为参数,内部由 state 做为函数的内部参数,返回一个 Virtual DOM 的实现
若是说要渲染一个对 props 加工后的值,最简单的方法就是使用局部变量或直接在 JSX 中计算结果
React.Children 是 React 官方提供的一系列操做 children 的方法。它提供诸如 map、forEach、count 等实用函数,能够为咱们处理子组件提供便利
组件 props
件向子组件的传播。
React 生命周期
import React, { Component, PropTypes } from 'react'; class App extends Component { static propTypes = { // ... }; static defaultProps = { // ... }; constructor(props) { super(props); this.state = { // ... }; } componentWillMount() { // ... } componentDidMount() { // ... } render() { return <div>This is a demo.</div>; } }
componentWillMount 方法会在 render 方法以前执行,而 componentDidMount 方法会在 render 方法以后执行,这些都只会在组件初始化时运行一次
import React, { Component, PropTypes } from 'react'; class App extends Component { componentWillUnmount() { // ... } render() { return <div>This is a demo.</div>; }
在 componentWillUnmount 方法中,咱们经常会执行一些清理方法,如事件回收或是清除定
时器。
更新过程指的是父组件向下传递 props 或组件自身执行 setState 方法时发生的一系列更新动做
import React, { Component, PropTypes } from 'react'; class App extends Component { componentWillReceiveProps(nextProps) { // this.setState({}) } shouldComponentUpdate(nextProps, nextState) { // return true; } componentWillUpdate(nextProps, nextState) { // ... } componentDidUpdate(prevProps, prevState) { // ... } render() { return <div>This is a demo.</div>; } }
若是组件自身的 state 更新了,那么会依次执行 shouldComponentUpdate、componentWillUpdate 、
render 和 componentDidUpdate。
componentWillReceiveProps 方法。此方法能够做为 React 在 props 传入后,渲染以前 setState 的
机会。在此方法中调用 setState 是不会二次渲染的。
React 与 DOM
findDOMNode
DOM 真正被添加到 HTML 中的生命周期方法是 componentDidMount 和 componentDidUpdate 方法
假设要在当前组件加载完时获取当前 DOM,则可使用 findDOMNode:
import React, { Component } from 'react'; import ReactDOM from 'react-dom'; class App extends Component { componentDidMount() { // this 为当前组件的实例 const dom = ReactDOM.findDOMNode(this); } render() {} }
findDOMNode 只对已经挂载的组件有效。
render
ReactComponent render( ReactElement element, DOMElement container, [function callback] )
该方法把元素挂载到 container 中,而且返回 element 的实例(即 refs 引用)。固然,若是是无状态组件,render 会返回 null。当组件装载完毕时,callback 就会被调用。
当组件在初次渲染以后再次更新时,React 不会把整个组件从新渲染一次,而会用它高效的 DOM diff 算法作局部的更新。这也是 React 最大的亮点之一!
refs
在 JSX 中,咱们必须使用驼峰的形式来书写事件的属性名(好比onClick),而 HTML 事件则须要使用所有小写的属性名(好比 onclick)。
HTML 的属性值只能是 JavaScript 代码字符串,而在 JSX 中,props 的值则能够是任意类型,这里是一个函数指针。
在 React 底层,主要对合成事件作了两件事:事件委ี和自动绑定。
当组件挂载或卸载时,只是在这个统一的事件ᄢ听器上插入或删除一些对象;当事件发生时,首先被这个统一的事件ᄢ听器处理,而后在映射里找到真正的事件处理函数并调用。这样作简化了事件处理和回收机制,效率也有很大提高。
自动绑定
在使用 ES6 classes 或者纯函数时,这种自动绑定就不复存在了,咱们须要手动实现 this 的绑定。
bind 方法
import React, { Component } from 'react'; class App extends Component { handleClick(e, arg) { console.log(e, arg); } render() { // 经过bind方法实现,能够传递参数 return <button onClick={this.handleClick.bind(this, 'test')}>Test</button>; } }
若是方法只绑定,不传参,那 stage 0 ᕘ案中提供了一个便的方案①——Ԥ冒号语法,其做用与 this.handleClick.bind(this) 一致,而且 Babel 已经实现了该提案。
import React, { Component } from 'react'; class App extends Component { handleClick(e) { console.log(e); } render() { return <button onClick={::this.handleClick}>Test</button>; } }
import React, { Component } from 'react'; class App extends Component { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); } handleClick(e) { console.log(e); } render() { return <button onClick={this.handleClick}>Test</button>; } }
箭头函数不只是函数的“语法糖”,它还自动绑定了定义此函数做用域的 this,所以咱们不须要再对它使用 bind 方法。
import React, { Component } from 'react'; class App extends Component { const handleClick = (e) => { console.log(e); }; render() { return <button onClick={this.handleClick}>Test</button>; } } 或 import React, { Component } from 'react'; class App extends Component { handleClick(e) { console.log(e); } render() { return <button onClick={() => this.handleClick()}>Test</button> } }
在 React中使用原生事件
componentDidMount 会在组件已经完成安装而且在浏览器中存在真实的 DOM 后调用,此时咱们就能够完成原生事件的绑定。
值得注意的是,在 React 中使用 DOM 原生事件时,必定要在组件卸载时手动移除,不然极可能出现内存泄漏的问题。而使用合成事件系统时则不须要,由于 React 内部已经帮你妥ؒ地处理了。
合成事件与原生事件混用
componentDidMount() { document.body.addEventListener('click', e => { this.setState({ active: false, }); }); document.querySelector('.code').addEventListener('click', e => { e.stopPropagation(); }) } componentWillUnmount() { document.body.removeEventListener('click'); document.querySelector('.code').removeEventListener('click'); }
经过 e.target判断来避免
componentDidMount() { document.body.addEventListener('click', e => { if (e.target && e.target.matches('div.code')) { return; } this.setState({ active: false, }); }); }
对比React合成事件与JavaScript原生事件
事件传播与阻止事件传播
<input value={this.state.value} onChange={e => { this.setState({ value: e.target.value.toUpperCase() }) }} />
非受控组件
<input defaultValue={this.state.value} onChange={e => { this.setState({ value: e.target.value.toUpperCase() }) }} />
import React, { Component } from 'React';
import { mixin } from 'core-decorators';
const PureRender = { shouldComponentUpdate() {} }; const Theme = { setTheme() {} }; @mixin(PureRender, Theme) class MyComponent extends Component { render() {} }
mountComponent 本质上是经过递归渲染内容的,因为递归的特性,父组件的componentWillMount 在其子组件的 componentWillMount 以前调用,而父组件的 componentDidMount在其子组件的 componentDidMount 以后调用。
若是存在 componentWillUnmount,则执行并重置全部相关参数、更新队列以及更新状态,若是此时在 componentWillUnmount 中调用 setState,是不会触发 re-render 的,这是由于全部更新队列和更新状态都被重置为 null,并清除了公共类,完成了组件卸载操做。