React技术栈
轉(zhuǎn)載自阮一峰的個(gè)人博客
React 是目前最熱門的前端框架。
- Facebook 公司2013年推出
- 現(xiàn)在最好的社區(qū)支持和生態(tài)圈
- 大量的第三方工具
React 的優(yōu)點(diǎn)
- 組件模式:代碼復(fù)用和團(tuán)隊(duì)分工
- 虛擬 DOM:性能優(yōu)勢
- 移動(dòng)端支持:跨終端
- React 的缺點(diǎn)
- 學(xué)習(xí)曲線較陡峭
- 全新的一套概念,與其他所有框架截然不同
- 只有采用它的整個(gè)技術(shù)棧,才能發(fā)揮最大威力
總結(jié):React 非常先進(jìn)和強(qiáng)大,但是學(xué)習(xí)和實(shí)現(xiàn)成本都不低
JSX 語法
React 使用 JSX 語法,JavaScript 代碼中可以寫 HTML 代碼。
let myTitle = <h1>Hello, world!</h1>;
JSX 語法解釋
(1)JSX 語法的最外層,只能有一個(gè)節(jié)點(diǎn)。
// 錯(cuò)誤
let myTitle = <p>Hello</p><p>World</p>;
(2)JSX 語法中可以插入 JavaScript 代碼,使用大括號(hào)。
let myTitle = <p>{'Hello ' + 'World'}</p>
Babel 轉(zhuǎn)碼器
JavaScript 引擎(包括瀏覽器和 Node)都不認(rèn)識(shí) JSX,需要首先使用 Babel 轉(zhuǎn)碼,然后才能運(yùn)行。
<script src="react.js"></script>
<script src="react-dom.js"></script>
<script src="babel.min.js"></script>
<script type="text/babel">
// Our code goes here!
</script>
React 需要加載兩個(gè)庫:React 和 React-DOM,前者是 React 的核心庫,后者是 React 的 DOM 適配庫。
Babel 用來在瀏覽器轉(zhuǎn)換 JSX 語法,如果服務(wù)器已經(jīng)轉(zhuǎn)好了,瀏覽器就不需要加載這個(gè)庫。
課堂練習(xí):JSX 語法
瀏覽器打開demos/jsx-demo/index.html,按照《操作說明》,完成練習(xí)。
ReactDOM.render(
<span>Hello World!</span>,
document.getElementById('example')
);
示例:React 組件
React 允許用戶定義自己的組件,插入網(wǎng)頁。
瀏覽器打開demos/react-component-demo/index1.html,按照《操作說明》,仔細(xì)查看源碼。
class MyTitle extends React.Component {
render() {
return <h1>Hello World</h1>;
}
};
ReactDOM.render(
<MyTitle/>,
document.getElementById('example')
);
課堂練習(xí):組件的參數(shù)
組件可以從外部傳入?yún)?shù),內(nèi)部使用this.props獲取參數(shù)。
打開demos/react-component-demo/index2.html,按照《操作說明》,完成練習(xí)。
class MyTitle extends React.Component {
render() {
return <h1
style={{color: this.props.color}}
Hello World</h1>;
}
};
<MyTitle color="red" />,
示例:組件的狀態(tài)
組件往往會(huì)有內(nèi)部狀態(tài),使用this.state表示。
瀏覽器打開demos/react-component-demo/index3.html,按照《操作說明》,仔細(xì)查看源碼。
課堂練習(xí):React 組件實(shí)戰(zhàn)
瀏覽器打開demos/react-component-demo/index4.html,按照《操作說明》,完成練習(xí)。
組件的生命周期
React 為組件的不同生命階段,提供了近十個(gè)鉤子方法。
componentWillMount():組件加載前調(diào)用
componentDidMount():組件加載后調(diào)用
componentWillUpdate(): 組件更新前調(diào)用
componentDidUpdate(): 組件更新后調(diào)用
componentWillUnmount():組件卸載前調(diào)用
componentWillReceiveProps():組件接受新的參數(shù)時(shí)調(diào)用
我們可以利用這些鉤子,自動(dòng)完成一些操作。
課堂練習(xí):組件的生命周期
組件可以通過 Ajax 請求,從服務(wù)器獲取數(shù)據(jù)。Ajax 請求一般在componentDidMount方法里面發(fā)出。
componentDidMount() {
const url = '...';
$.getJSON(url)
.done()
.fail();
}
打開demos/react-lifecycle-demo/index.html,按照《操作說明》,完成練習(xí)。
React 組件庫
React 的一大優(yōu)勢,就是網(wǎng)上有很多已經(jīng)寫好的組件庫,可以使用。
React-Bootstrap:https://react-bootstrap.github.io/
示例:ReCharts
ReCharts 是一個(gè) React 圖表組件庫。http://recharts.org/
瀏覽器打開demos/recharts-demo/index.html,按照《操作說明》,仔細(xì)查看源碼,體會(huì) JSX 語法對表達(dá)復(fù)雜組件的優(yōu)勢。
<LineChart width={1000} height={400} data={data}>
<XAxis dataKey="name"/>
<YAxis/>
<CartesianGrid stroke="#eee" strokeDasharray="5 5"/>
<Line type="monotone" dataKey="uv" stroke="#8884d8" />
<Line type="monotone" dataKey="pv" stroke="#82ca9d" />
</LineChart>
React 的核心思想
View 是 State 的輸出。
view = f(state)
上式中,f表示函數(shù)關(guān)系。只要 State 發(fā)生變化,View 也要隨之變化。
React 的本質(zhì)是將圖形界面(GUI)函數(shù)化。
const person = {
name: "michel",
age: 31
}
const App = ({ person }) => <h1>{ person.name }</h1>
ReactDOM.render(<App person={person} />, document.body)
React 沒有解決的問題
React 本身只是一個(gè) DOM 的抽象層,使用組件構(gòu)建虛擬 DOM。
如果開發(fā)大應(yīng)用,還需要解決兩個(gè)問題。
架構(gòu):大型應(yīng)用程序應(yīng)該如何組織代碼?
通信:組件之間如何通信?
架構(gòu)問題
React 只是視圖層的解決方案,可以用于任何一種架構(gòu)。
MVC
MVVM
Observer
Reactive
...
到底哪一種架構(gòu)最合適 React ?
通信問題
組件會(huì)發(fā)生三種通信。
- 向子組件發(fā)消息
- 向父組件發(fā)消息
- 向其他組件發(fā)消息
React 只提供了一種通信手段:傳參。對于大應(yīng)用,很不方便。
狀態(tài)的同步
通信的本質(zhì)是狀態(tài)的同步。
React 同步狀態(tài)的基本方法:找到通信雙方最近的共同父組件,通過它的state,使得子組件的狀態(tài)保持同步。
Flux 架構(gòu)
Facebook 提出 Flux 架構(gòu)的概念,被認(rèn)為是 React 應(yīng)用的標(biāo)準(zhǔn)架構(gòu)。
最大特點(diǎn):數(shù)據(jù)單向流動(dòng)。與 MVVM 的數(shù)據(jù)雙向綁定,形成鮮明對比。
Flux 的核心思想
不同組件的state,存放在一個(gè)外部的、公共的 Store 上面。
組件訂閱 Store 的不同部分。
組件發(fā)送(dispatch)動(dòng)作(action),引發(fā) Store 的更新。
Flux 只是一個(gè)概念,有30多種實(shí)現(xiàn)。
目前最流行的兩個(gè) React 架構(gòu)
React 架構(gòu)的最重要作用:管理 Store 與 View 之間的關(guān)系。
MobX:響應(yīng)式(Reactive)管理,state 是可變對象,適合中小型項(xiàng)目
Redux:函數(shù)式(Functional)管理,state 是不可變對象,適合大型項(xiàng)目
MobX 架構(gòu)
MobX 的核心是觀察者模式。
Store 是被觀察者(observable)
組件是觀察者(observer)
一旦Store有變化,會(huì)立刻被組件觀察到,從而引發(fā)重新渲染。
MobX 的最簡單例子
const {observable} = mobx;
const {observer} = mobxReact;
const person = observable({name: "張三", age: 31});
const App = observer(
({ person }) => <h1>{ person.name }</h1>
);
ReactDOM.render(<App person={person} />, document.body);
person.name = "李四";
代碼:demos/mobx-demo/browser-demo目錄
示例:MobX
進(jìn)入demos/mobx-demo目錄,按照《操作說明》,理解 MobX 框架。
UI 層是觀察者,Store 是被觀察者。
Store 所有的屬性,分成兩大類:直接被觀察的屬性和自動(dòng)計(jì)算出來的屬性。
class Store {
@observable name = 'Bartek';
@computed get decorated() {
return ${this.name} is awesome!;
}
}
UI 會(huì)觀察到 Store 的變化,自動(dòng)重新渲染。
Redux 架構(gòu)
Redux 的核心概念
所有的狀態(tài)存放在Store。組件每次重新渲染,都必須由狀態(tài)變化引起。
用戶在 UI 上發(fā)出action。
reducer函數(shù)接收action,然后根據(jù)當(dāng)前的state,計(jì)算出新的state。
Redux 應(yīng)用的架構(gòu)
Redux 層保存所有狀態(tài),React 組件拿到狀態(tài)以后,渲染出 HTML 代碼。
示例:Redux
進(jìn)入demos/redux-demo目錄,按照《操作說明》,理解 Redux 框架。
Redux 將組件分成 UI 組件和容器組件兩類。
UI 組件是純組件,不包含 state 和生命周期方法,不涉及組件的行為,只涉及組件的外觀。
<div className="index">
<p>{this.props.text}</p>
<input
defaultValue={this.props.name}
onChange={this.props.onChange}
/>
</div>
容器組件正好相反。
不涉及組件的外觀,只涉及組件的行為。
負(fù)責(zé)訂閱 Store,將 Store 的數(shù)據(jù)處理以后,再通過參數(shù)傳給 UI 組件。
用戶給出配置以后,由 Redux 生成。
// MyComponent 是純的 UI 組件
const App = connect(
mapStateToProps,
mapDispatchToProps
)(MyComponent);
mapStateToProps: 定義 UI 組件參數(shù)與 State 之間的映射
mapDispatchToProps:定義 UI 組件與 Action 之間的映射
拆分 UI 組件和容器組件的好處
UI 組件與后臺(tái)數(shù)據(jù)無關(guān),可以由設(shè)計(jì)師負(fù)責(zé)
容器組件只負(fù)責(zé)數(shù)據(jù)和行為,一旦 Store 的數(shù)據(jù)結(jié)構(gòu)變化,只要調(diào)整容器組件即可
表現(xiàn)層和功能層脫鉤,有利于代碼重用,也有利于看清應(yīng)用的數(shù)據(jù)結(jié)構(gòu)和業(yè)務(wù)邏輯
Reducer 函數(shù)
reducer是一個(gè)純函數(shù),用來接收action,算出新的state。
function reducer(state = {
text: '你好,訪問者',
name: '訪問者'
}, action) {
switch (action.type) {
case 'change':
return {
name: action.payload,
text: '你好,' + action.payload
};
}
}
Store由 Redux 提供的createStore方法生成,該方法接受reducer作為參數(shù)。
為了把Store傳入組件,必須使用 Redux 提供的Provider組件在應(yīng)用的最外面,包裹一層。
const store = createStore(reducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.body.appendChild(document.createElement('div'))
);
總結(jié)
- 上一篇: Oracle统计信息不准(谓词越界)造成
- 下一篇: 索引补充