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,並清除了公共類,完成了組件卸載操做。