我們對于React,描述得比較多的就是它擁有優(yōu)越的渲染性能和高質(zhì)量的模塊化。那它長什么樣子,如何來學(xué)習(xí)React 呢?以下是我從以前的自己的文章匯總起來的,跨越了React的幾個版本,因此,很有必要說明當(dāng)前版本號,也順便追蹤一下其變化過程。我先以最早之前看的版本v0.13.0來開始吧。
快速開始
先看一個最簡單的 react 項(xiàng)目目錄
1 2 3 4 5 |
react-study ├── build | ├── JSXTransformer.js | └── react.min.js └── helloworld.html |
以打印經(jīng)典的 hello world 為例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<!-- helloworld.html --> <!DOCTYPE html> <html> <head> <script src="build/react.js"></script> <script src="build/JSXTransformer.js"></script> </head> <body> <div id="example"></div> <script type="text/jsx"> React.render( <h1>Hello, world!</h1>, document.getElementById('example') ); </script> </body> </html> |
上面的 text/jsx 中的代碼是JSX語法的代碼,跟瀏覽器并不兼容,可以通過 JSXTransformer.js
將JSX代碼轉(zhuǎn)化為標(biāo)準(zhǔn)的JS代碼。
創(chuàng)建 src/helloworld.js,html中的把jsx轉(zhuǎn)移到里面
1 2 3 4 5 6 7 |
react-study ├── build | ├── JSXTransformer.js | └── react.min.js ├── src | ├── helloworld.js └── hellowworld.html |
1 2 3 4 5 6 7 8 9 10 11 12 |
<!-- helloworld.html --> <!DOCTYPE html> <html> <head> <script src="build/react.js"></script> <script src="build/JSXTransformer.js"></script> </head> <body> <div id="example"></div> <script type="text/jsx" src="src/helloworld.js"></script> </body> </html> |
1 2 3 4 5 |
// src/helloworld.js React.render( <h1>Hello, world!</h1>, document.getElementById('example') ); |
1 2 3 4 5 |
// src/helloworld.js React.render( <h1>Hello, world!</h1>, document.getElementById('example') ); |
當(dāng)遇到js無法加載的時候,試一下本地配一下http環(huán)境。
安裝命令行工具(依賴 npm)
1 |
sudo npm install -g react-tools |
將 src/helloworld.js 文件轉(zhuǎn)成標(biāo)準(zhǔn)的 javascript,并檢測文件目錄里的修改變動,自動更新
1 |
jsx --watch src/ build/ |
1 2 3 4 5 6 7 8 |
react-study ├── build | ├── helloworld.js | ├── JSXTransformer.js | └── react.min.js ├── src | ├── helloworld.js └── hellowworld.html |
1 2 3 4 5 |
// build/helloworld.js React.render( React.createElement('h1', null, 'Hello, world!'), document.getElementById('example') ); |
更正 html,完成
1 2 3 4 5 6 7 8 9 10 11 |
<!DOCTYPE html> <html> <head> <title>Hello React!</title> <script src="build/react.js"></script> </head> <body> <div id="example"></div> <script src="build/helloworld.js"></script> </body> </html> |
最簡單的 React 栗子描述完了,給我的第一印象是和less/sass的引進(jìn)使用方式有點(diǎn)相近。
核心基本函數(shù)方法之一,React.render(),結(jié)構(gòu)渲染
React.render 是 React 的最基本方法,用于將模板轉(zhuǎn)為 HTML 語言,并插入指定的 DOM 節(jié)點(diǎn)。
1 2 3 4 |
React.render( <h1>Hello, world!</h1>, document.getElementById('example') ); |
該代碼實(shí)現(xiàn) h1 標(biāo)簽插入到 example 標(biāo)簽中
1 2 3 4 5 6 7 8 9 10 11 |
var names = ['Alice', 'Emily', 'Kate']; ReactDOM.render( <div> { names.map(function (name) { return <div>Hello, {name}!</div> }) } </div>, document.getElementById('example') ); |
上面代碼體現(xiàn)了 JSX 的基本語法規(guī)則:遇到 HTML 標(biāo)簽(以 < 開頭),就用 HTML 規(guī)則解析;遇到代碼塊(以 { 開頭),就用 JavaScript 規(guī)則解析
1 2 3 4 5 6 7 8 |
var arr = [ <h1>Hello world!</h1>, <h2>React is awesome</h2> ]; ReactDOM.render( <div>{arr}</div>, document.getElementById('example') ); |
核心基本函數(shù)方法之二,React.createClass(),創(chuàng)建組件
1 2 3 4 5 6 7 8 9 10 |
var HelloMessage = React.createClass({ render: function() { return <h1>Hello {this.props.name}</h1>; } });
React.render( <HelloMessage name="John" />, document.getElementById('example') ); |
1)上面代碼中,變量 HelloMessage 就是一個組件類。模板插入 <HelloMessage /> 時,會自動生成 HelloMessage 的一個實(shí)例。所有組件類都必須有自己的 render 方法,用于輸出組件。
2)組件類的第一個字母必須大寫,否則會報(bào)錯,比如HelloMessage不能寫成helloMessage。
3)另外,組件類只能包含一個頂層標(biāo)簽,否則也會報(bào)錯。
引入模塊的變化
然后到了React v0.14.7,相比Reat v0.13.0有一些明顯的變動。如原本的 react package 被拆分為react及react-dom兩個package。其中react package 中包含React.createElement、React.createClass、React.Component,React.PropTypes,React.Children這些API,而react-dom package中包含ReactDOM.render、React.unmountComponentAtNode、React.findDOMNode。React的html結(jié)構(gòu)大致如此:
1 2 3 4 5 6 7 8 9 10 11 12 |
<!DOCTYPE html> <html> <head> <script src="../build/react.js"></script> <script src="../build/react-dom.js"></script> <script src="../build/browser.min.js"></script> </head> <body> <div id="example"></div> <script type="text/babel" src="../src/helloworld.js"></script> </body> </html> |
其中,react.js 是 React 的核心庫,react-dom.js 是提供與 DOM 相關(guān)的功能,Browser.js 跟JSXTransformer.js的作用類似,是將 JSX 語法轉(zhuǎn)為JavaScript 語法,同樣,這一步很消耗時間,實(shí)際上線的時候,應(yīng)該將它放到服務(wù)器完成。
離線轉(zhuǎn)換工具的變化
Babel代替JSX,首先你得確保安裝 Babel命令行工具:
安裝babel命令行工具
1 |
npm install -g babel-cli |
編譯腳本
1 |
babel src --out-dir build |
這樣一來,html變成:
1 2 3 4 5 6 7 8 9 10 11 |
<!DOCTYPE html> <html> <head> <script src="../build/react.js"></script> <script src="../build/react-dom.js"></script> </head> <body> <div id="example"></div> <script src="../build/helloworld.js"></script> </body> </html> |
ReactDOM.render 代替 React.render
1 2 3 4 |
ReactDOM.render( <h1>Hello, world!</h1>, document.getElementById('example') ); |
之前,我們只認(rèn)識了 React.createClass() 、和 ReactDOM.render() 這兩個基本函數(shù),這次,我們再來認(rèn)識一下幾個常用概念,版本v0.14.7。
this.props
React 允許將代碼封裝成組件(component),然后像插入普通 HTML 標(biāo)簽一樣,在網(wǎng)頁中插入這個組件。React.createClass 方法就用于生成一個組件類。
1 2 3 4 5 6 7 8 9 10 |
var HelloMessage = React.createClass({ render: function() { return <h1>Hello {this.props.name}</h1>; } });
ReactDOM.render( <HelloMessage name="John" />, document.getElementById('example') ); |
上面代碼中,變量 HelloMessage 就是一個組件類。模板插入 <HelloMessage /> 時,會自動生成 HelloMessage 的一個實(shí)例。所有組件類都必須有自己的 render 方法,用于輸出組件。
組件的用法與原生的 HTML 標(biāo)簽完全一致,可以任意加入屬性,比如 <HelloMessage name=”John”> ,就是 HelloMessage 組件加入一個 name 屬性,值為 John。組件的屬性可以在組件類的 this.props 對象上獲取,比如 name 屬性就可以通過 this.props.name 讀取。
添加組件屬性,有一個地方需要注意,就是 class 屬性需要寫成 className ,for 屬性需要寫成 htmlFor ,這是因?yàn)?nbsp;class 和 for 是 JavaScript 的保留字。
this.props.children
this.props 對象的屬性與組件的屬性一一對應(yīng),但是有一個例外,就是 this.props.children 屬性。它表示組件的所有子節(jié)點(diǎn)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
var NotesList = React.createClass({ render: function() { return ( <ol> { React.Children.map(this.props.children, function (child) { return <li>{child}</li>; }) } </ol> ); } });
ReactDOM.render( <NotesList> <span>hello</span> <span>world</span> </NotesList>, document.body ); |
上面代碼的 NoteList 組件有兩個 span 子節(jié)點(diǎn),它們都可以通過 this.props.children 讀取。
這里需要注意, this.props.children 的值有三種可能:如果當(dāng)前組件沒有子節(jié)點(diǎn),它就是 undefined ;如果有一個子節(jié)點(diǎn),數(shù)據(jù)類型是 object ;如果有多個子節(jié)點(diǎn),數(shù)據(jù)類型就是 array 。所以,處理 this.props.children 的時候要小心。
React 提供一個工具方法 React.Children 來處理 this.props.children 。我們可以用 React.Children.map 來遍歷子節(jié)點(diǎn),而不用擔(dān)心this.props.children 的數(shù)據(jù)類型是 undefined 還是 object。
React.Children
React.Children 為處理 this.props.children 這個封閉的數(shù)據(jù)結(jié)構(gòu)提供了有用的工具。
React.Children.map
1 |
object React.Children.map(object children, function fn [, object context]) |
在每一個直接子級(包含在 children 參數(shù)中的)上調(diào)用 fn 函數(shù),此函數(shù)中的 this 指向 上下文。如果 children 是一個內(nèi)嵌的對象或者數(shù)組,它將被遍歷:不會傳入容器對象到 fn 中。如果 children 參數(shù)是 null 或者 undefined,那么返回 null 或者 undefined 而不是一個空對象。
React.Children.forEach
1 |
React.Children.forEach(object children, function fn [, object context]) |
類似于 React.Children.map(),但是不返回對象。
React.PropTypes
組件類的ProTypes屬性,用來驗(yàn)證使用組件時提供的屬性值是否符合要求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
var MyTitle = React.createClass({ propTypes: { title: React.PropTypes.string.isRequired, },
render: function() { return <h1> {this.props.title} </h1>; } });
ReactDOM.render( <MyTitle title="123" />, document.body ); |
上面的Mytitle組件有一個title屬性。PropTypes 告訴 React,這個 title 屬性是必須的,而且它的值必須是字符串。像上面這樣輸入數(shù)字,控制臺就會報(bào)錯。
此外,getDefaultProps 方法可以用來設(shè)置組件屬性的默認(rèn)值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
var MyTitle = React.createClass({ getDefaultProps : function () { return { title : 'Hello World' }; },
render: function() { return <h1> {this.props.title} </h1>; } });
ReactDOM.render( <MyTitle />, document.body ); |
上面代碼會輸出”Hello World”。
目前React的版本到了15.1.0,這個其實(shí)是官方宣布將版本的小數(shù)點(diǎn)向左移了一位,此前0.14.x稱為React 14,說是為避免開頭的0的誤解以及提升這個迅猛發(fā)展的項(xiàng)目的認(rèn)可度。
React的基礎(chǔ)核心內(nèi)容其實(shí)就是上面這些,更多內(nèi)容請查看官方網(wǎng)站。
原文來自:京東設(shè)計(jì)中心