本系列將盡可能使用ES6(ES2015)語法。所以均在上節webpack的基礎上做開發。
React是Facebook開發的一款JS庫,因為基於Virtual DOM,所以響應速度快,以及支持跨平台。
(實際上,Virtual DOM在某些情況都會損耗一些性能在diff上,但相比其他MVVM框架比起來性能影響很少,同時大幅提升開發效率也是目前推薦的方式)
安裝
安裝React: npm i -S react react-dom
安裝Babel:npm i babel-loader babel-preset-react babel-plugin-import -S
HelloWorld
import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);
JSX
JavaScript 的一種擴展語法。我們推薦在 React 中使用這種語法來描述 UI 信息。
- JSX支持嵌入表達式:花括號 把任意的 JavaScript 表達式 嵌入到 JSX 中
- JSX是Javascript:比起 HTML, JSX 更接近於 JavaScript, React DOM 使用駝峰(camelCase)屬性命名約定。(html為全小寫)
- JSX防注入攻擊:在渲染之前, React DOM 會格式化(escapes) JSX中的所有值。防止 XSS(跨站腳本) 攻擊。
- JSX編譯后為: React.createElement()。
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
const element = React.createElement(
'h1',
{ className: 'greeting' },
'Hello, world!'
);
// 注意: 以下示例是簡化過的(不代表在 React 源碼中是這樣)
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world'
}
};
組件
React框架的一大特色就是它通過組件化的方式來構建和渲染前端頁面。
定義組件有很多方式,最主流的為:函數 和 類(類允許我們在其中添加本地狀態(state)和生命周期鈎子。)
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
Props
- 屬性是只讀的:無論你用函數或類的方法來聲明組件, 它都無法修改其自身 props。
- 屬性是外部控制的:屬性是由外部設置,組件內部是不確定屬性從哪設置的。
- 穩定性:對於同樣的輸入,始終可以得到相同的結果。
State
- state是內部控制的:state是私有的,並且由組件本身完全控制。
- 使用setState修改:
- 內部調用render
- 支持異步
- 支持更新合並state
生命周期事件
React組件的生命周期事件很多,常用的有:
- componentDidMount:在組件第一次初始化render方法后調用,此時組件(DOM及誒點)已創建完成。通常在此方法中ajax、使用第三方js框架。
- shouldComponentUpdate:在組件接收到新的state或props后被調用。(第一次初始化和forceUpdate時不被調用。 )默認返回true,返回false的時候則不調用render方法。
- componentWillUnmount:在組件從DOM中移除的時候被調用。通常用來移除組件相關事件。
生命周期事件又分為3條流程:
- 組件初始化(Mounting):getDefaultProps、getInitialState、componentWillMount、render、componentDidMount(getInitialState在ES6 class的構造函數中可直接對state初始化)
- 組件props更新(Updating):componentWillReceiveProps(nextProps)、shouldComponentUpdate、componentWillUpdate、render componentDidUpdate
- 組件卸載(Unmounting):componentWillUnmount
表單
受控組件
React負責渲染表單的組件仍然控制用戶后續輸入時所發生的變化。相應的,其值由React控制的輸入表單元素稱為“受控組件”。
class ShowInput extends Component {
constructor(props) {
super(props);
this.state = {
val: 'hello'
}
}
onChange(e) {
this.setState({
val: e.target.value
})
}
render() {
return (
<div>
<input type="text" onChange={e => this.onChange(e)} />
<div>{this.state.val}</div>
</div>
)
}
}
DivInput組件中的input元素就是受控組件。value 和 onChnage都會由React控制。
非受控組件
render() {
return (
<div>
<input type="text" ref={e => this.input = e} />
<button onClick={() => console.log(this.input.value)}>Click</button>
</div>
);
}
掛到組件(這里組件指的是有狀態組件)上的ref表示對組件實例的引用,而掛載到dom元素上時表示具體的dom元素節點。(stateless構造的組件是不會實例化,所以ref引用的為null)
ref屬性可以設置為一個回調函數,這也是官方強烈推薦的用法;這個函數執行的時機為:
- 組件被掛載后:回調函數被立即執行,回調函數的參數為該組件的具體實例。
- 組件被卸載或者原有的ref屬性本身發生變化時:回調也會被立即執行,此時回調函數參數為null,以確保內存泄露。
ReactDOM.findDOMNode(ref)來獲取組件掛載后真正的dom節點。
組件通信
組件之間通信的解決方案通常有2種:
- 狀態提升:將state提升到互相通信組件的最近的一個父組件上
- Redux:下節將介紹