轉自http://blog.csdn.net/iambinger/article/details/51803606
閱讀前請看這裏:
* 瞭解js及jQuery的使用
* 對react有一定的瞭解,知道jsx的語法
* 這裏只講述如何使用react,並不介紹react的優缺點如果不滿足這些,建議先了解下,然後再看這篇文章
下面會講述5個react的實例,雖然僅有5個,但在常用的開發中,幾乎會包含大部分的情況,只要熟練掌握這5個demo,相信一定會解決大部分問題。
demo中,所有樣例會打包後,傳遞到附件,大家可以下載閱覽,最好自己親手實踐下,不要直接copy代碼,沒有意義。
使用的react版本是0.14.7
DEMO 1 - 最簡單的react渲染
代碼:
<html>
<head>
<link href="css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<h1><span class="label label-info">DEMO 1</span></h1>
<br><br><br>
<div class="well" id="well">
</div>
<script src="js/jquery.min.js"></script>
<script src="js/react.js"></script>
<script src="js/react-dom.js"></script>
<script src="js/browser.min.js"></script>
<script type="text/babel">
var Text = React.createClass({
render: function() {
return (
<div className="a">
大家好,我是用react渲染出來的!
</div>
);
}
});
ReactDOM.render(
<Text/>,
document.getElementById('well')
);
</script>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
在瀏覽器中顯示的效果如下
講解:
- 頁面中,只有
<div id='well'>
這裏的內容是使用react渲染出來的,代碼中這裏是空的,依賴下面的js進行渲染 - 首先看下
vat Text =
這塊,這裏是聲明一個模塊,名字隨意起,我們把第一個字母大寫,用來區分html中原生的標籤
React.createClass({
render: function() {
return (
<div className="a">
大家好,我是用react渲染出來的!
</div>
);
}
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
這塊是創建一個模塊,使用React.createClass
即可創建。
* 其中參數有很多,但都可以省略,唯有render
不可以省略,因爲這是用來表述這個插件被加載後,顯示的是什麼樣子,它的返回結果,就是加載在頁面上最終的樣式。
ReactDOM.render(
<Text/>,
document.getElementById('well')
);
- 1
- 2
- 3
- 4
這段代碼是用來渲染react組件額,第一個參數是組件,第二個參數是要渲染的位置。
* 使用<Text/>
的 方式就可以實例化組件,或者寫成<Text></Text>
,要注意下,react中標籤的閉合非常嚴格,任何標籤的關閉與打開必須一一對應,否則會報錯。
* 到目前爲止,就完成了一次渲染,將Text組件render函數返回的內容,填充到了id=well的div中。
DEMO 2 - 帶有參數的react
往往在使用中,文本的內容並不是寫死的,而是需要被我們指定,這樣組件才能更通用。下面介紹下,如何向react中傳遞參數。
代碼:
<html>
<head>
<link href="css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<h1><span class="label label-info">DEMO 2</span></h1>
<br><br><br>
<div class="well" id="well">
</div>
<script src="js/jquery.min.js"></script>
<script src="js/react.js"></script>
<script src="js/react-dom.js"></script>
<script src="js/browser.min.js"></script>
<script type="text/babel">
var Text = React.createClass({
render: function() {
return (
<div className="a">
大家好,我是用{this.props.name}渲染出來的!age={this.props.age}
</div>
);
}
});
ReactDOM.render(
<Text name="react" age={181}></Text>,
document.getElementById('well')
);
</script>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
在瀏覽器中顯示的效果如下
講解
- 首先,這個大體上跟第一個demo類似,唯有實例化Text時,多了參數。
- 當我們傳遞參數時,寫了兩種方式,一種是
name="react"
另一種是age={181}
,這兩種寫法是有區別的,並不僅僅因爲一個是str
,一個是int
。如果是str
這種類型,寫成name="xxx"
或者name={"xxx"}
都是可以的,加了{}的意思就是js中的變量,更加精確了。而後者age={181}
是不可以去掉{}的,這樣會引起異常,所以這裏要注意下,並且建議任何類型都加上{}來確保統一。 - 當在Text初始化時添加了參數,在組件內部,都收集在this.props中,使用時只要{this.props.name}既可以獲取name對應的值,如果取得key並不存在,這裏不會報錯,只是取到的值是空的。當然可以在
getDefaultProps
中定義默認的props值,即使在沒有傳遞參數的情況下,也能取到默認值。 - props中的參數,在初始化傳遞後,便不能再修改。
DEMO 3 - state,react的核心
state算是react的核心了,任何頁面的變化,刷新都是state的變化引起。在react中,只要調用了setState都會引起render的重新執行。下面介紹下如何通過鍵盤事件觸發狀態變化。
代碼:
<html>
<head>
<link href="css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<h1><span class="label label-info">DEMO 3</span></h1>
<br><br><br>
<div class="well" id="well">
</div>
<script src="js/jquery.min.js"></script>
<script src="js/react.js"></script>
<script src="js/react-dom.js"></script>
<script src="js/browser.min.js"></script>
<script type="text/babel">
var Text = React.createClass({
getInitialState: function() {
return {name: "react"};
},
keyUp: function(e){
this.setState({name: e.target.value});
console.log(this.state.name);
},
render: function() {
return (
<div className="a">
大家好,我是用{this.state.name}渲染出來的!
<input onKeyUp={this.keyUp} />
</div>
);
}
});
ReactDOM.render(
<Text></Text>,
document.getElementById('well')
);
</script>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
在瀏覽器中顯示的效果如下
講解:
- 這次組件中多了兩個函數,
getInitialState
和keyUp
,其中getInitialState是react中的初始化狀態的函數,類似上一節中getDefaultProps
的作用。keyUp是我自定義的函數,用來響應鍵盤事件的。 - 我們先看render函數,文字渲染中加了{this.state.name},這個是react內部的狀態,可以理解是存儲數據的k-v結構,這裏的v支持的對象較多。{this.state.name}就是引用狀態中的name屬性,與props的區別在於,如果state中不存在這個屬性,是會報錯的,所以我們要在getInitialState中初始化這個狀態的初始值。
- render中還多了一個,onKeyUp是註冊鍵盤鍵彈起的事件,當按鍵按下後彈起,就會觸發onKeyUp事件,然後通過綁定的this.keyUp,將事件傳遞給了自己定義的keyUp函數中。
- keyUp函數中,使用了this.setState({name: e.target.value}),setState是react中內部的函數,專門用來更新狀態的,這裏是講狀態中name的值變更爲引起事件的value值。
- 在react中,每次狀態的變化,都會引起render函數的重新渲染,這是它自己的機制,我們無需人爲處理,當鍵盤輸入內容時,會觸發狀態變化,導致render重新渲染,渲染的過程會從state中取出變量,所以我們就看到了頁面的內容發生了變化。
- 我們在setState下面加了一個console,通過控制檯可以發現,每次打印的值並不是當前輸入的值,而是上一次輸入的值,這是怎麼回事呢?在setState中,這是一個異步處理的函數,並不是同步的,console在setState後立刻執行了,所以這時候狀態還沒有真正變更完,所以這裏取到的狀態仍舊是更新前的。這裏要特殊注意下。如果需要在更新狀態後,再執行操作怎麼辦呢,setState還有第二個參數,接受一個callback,我們嘗試將keyUp中代碼改成這樣
this.setState({name: e.target.value}, function(){
console.log(this.state.name);
})
- 1
- 2
- 3
- 這時候log打印出來的只就是我們期望的內容,當每次狀態更新成功後,都會調用傳進去的callback函數。
- react中渲染dom有自己的優化方式,首先它在內存中構建一套虛擬的dom,每次更新前將虛擬dom與瀏覽器中dom對比,只講有變化的部分進行更新,這樣大大的提高了性能。或者我們可以重寫函數來控制是否刷新,當然這種方式我們並不提倡。
DEMO 4 - 網絡請求觸發狀態變化
上一節講到狀態變化觸發render的重新渲染,這裏將常用的網絡請求引入,結合到狀態變化中。
代碼:
<html>
<head>
<link href="css/bootstrap.min.css" rel="stylesheet">
<style>
.div {
height: 100px;
}
</style>
</head>
<body>
<h1><span class="label label-info">DEMO 4</span></h1>
<br><br><br>
<div class="well div" id="well">
</div>
<script src="js/jquery.min.js"></script>
<script src="js/react.js"></script>
<script src="js/react-dom.js"></script>
<script src="js/browser.min.js"></script>
<script type="text/babel">
var Text = React.createClass({
getInitialState: function() {
return {cur_time: 0};
},
request: function() {
$.ajax({
type: "GET",
url: "http://xxx",
success: function(data){
this.setState({cur_time: data.timestamp});
}.bind(this),
complete: function(){
this.setState({cur_time: Date.parse(new Date()) / 1000});
}.bind(this)
});
},
componentDidMount: function(){
setInterval(this.request, 1000);
},
render: function() {
return (
<div className="col-xs-12">
當前時間{this.state.cur_time}
<div className={ this.state.cur_time % 2 == 0?"hidden": "col-xs-6 alert alert-success"}>
<span>最後一位奇數</span>
</div>
<div className={ this.state.cur_time % 2 != 0?"hidden": "col-xs-6 alert alert-danger"}>
<span>最後一位偶數</span>
</div>
</div>
);
}
});
ReactDOM.render(
<Text></Text>,
document.getElementById('well')
);
</script>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
在瀏覽器中顯示的效果如下
講解:
- 這個例子中,頁面每秒會請求一次網絡,將請求到的數據中時間戳更新到狀態中。但是這個例子中實際上並沒有使用服務返回的時間戳,因爲我在公司使用測試網的接口拿數據,但是開放給大家要換一個公網能拿到時間戳的api,簡單的找了下沒找到,也不想用公司的接口試,所以算是mock了下~,在complete中每次都取瀏覽器時間來更新。
- 仍舊是先看代碼,相比於上一個例子,這裏多了兩個函數
request
和componentDidMount
,其中request
是請求網絡的函數,componentDidMount
是react內部的函數,也是react生命週期的一部分,它會在render第一次渲染前執行,而且只會執行一次。 - 先看request,一個普通的ajax請求,在success回調中,假設服務器返回的json爲{“timestamp”: 1467425645},那data.timestamp就取得是1467425645,然後將值賦給state中的cur_time屬性。這時狀態發生了變化,render函數會重新渲染。當然例子中success不會被訪問到,因爲那個url根本不存在,所以我在complete回調中來寫了一個狀態變化,模擬success成功。
- 爲什麼success回調函數最後會加一個bind(this)?因爲這個函數已經不是react內部的函數了,它是一個外部函數,它裏面的this並不是react組件中的this,所以要將外部函數綁定到react中,並能使用react內部的方法,例如setState,就要在函數最後bind(this),這樣就完成了綁定。
- 再看下
componentDidMount
函數,這個函數在render渲染前會執行,裏面的代碼也很簡單,增加了一個定時器,1秒鐘執行一次request。 - 這裏應該在加一個回調,就是定時器在初始化時創建,卻沒有對應的銷燬,所以在組件銷燬的時候,應該在這個生命週期中銷燬定時器。
DEMO 5 - 組件的嵌套使用
在封裝react時,我們往往按照最小單位封裝,例如封裝一個通用的div,一個通用的span,或者一個通用的table等,所以各自組件對應的方法都會隨着組件封裝起來,例如div有自己的方法可以更改背景色,span可以有自己的方法更改字體大小,或者table有自己的方法來更新table的內容等~ 這裏我們用一個div相互嵌套的例子來查看父子組件如何相互嵌套及調用各自的方法。在下面的例子中,父組件與子組件都有一個方法,來改變自身的背景色,我們實現父子組件相互調用對方的方法,來改變對方的背景色。
代碼:
<html>
<head>
<link href="css/bootstrap.min.css" rel="stylesheet">
<style>
.child {
border-color: black;
border: 1px solid;
height: 200px;
}
.parent {
height: 400px;
border: 3px solid;
}
</style>
</head>
<body>
<h1><span class="label label-info">DEMO 5</span></h1>
<br><br><br>
<div id="well">
</div>
<script src="js/jquery.min.js"></script>
<script src="js/react.js"></script>
<script src="js/react-dom.js"></script>
<script src="js/browser.min.js"></script>
<script type="text/babel">
var Child = React.createClass({
getInitialState: function() {
return {color: ""};
},
changeColor: function(e) {
this.setState({color: e.target.getAttribute("data-color")});
},
render: function() {
return (
<div style={{backgroundColor: this.state.color}} className="col-xs-5 col-xs-offset-1 child">
<br/>
<ul className="list-inline">
<li><a href="#" data-color="#286090" className="btn btn-primary" onClick={this.props.parentChangeColor}> </a></li>
<li><a href="#" data-color="#31b0d5" className="btn btn-info" onClick={this.props.parentChangeColor}> </a></li>
<li><a href="#" data-color="#c9302c" className="btn btn-danger" onClick={this.props.parentChangeColor}> </a></li>
<li><a href="#" data-color="#ec971f" className="btn btn-warning" onClick={this.props.parentChangeColor}> </a></li>
<li><a href="#" data-color="#e6e6e6" className="btn btn-default" onClick={this.props.parentChangeColor}> </a></li>
</ul>
</div>
);
}
});
var Parent = React.createClass({
getInitialState: function() {
return {color: ""};
},
changeColor: function(e) {
this.setState({color: e.target.getAttribute("data-color")});
},
child1ChangeColor: function(e) {
this.refs["child1"].changeColor(e);
},
child2ChangeColor: function(e) {
this.refs["child2"].changeColor(e);
},
render: function() {
return (
<div style={{backgroundColor: this.state.color}} className="col-xs-10 col-xs-offset-1 parent">
<br/>
<ul className="list-inline">
<li>對應第一個child</li>
<li><a href="#" data-color="#286090" className="btn btn-primary" onClick={this.child1ChangeColor}> </a></li>
<li><a href="#" data-color="#31b0d5" className="btn btn-info" onClick={this.child1ChangeColor}> </a></li>
<li><a href="#" data-color="#c9302c" className="btn btn-danger" onClick={this.child1ChangeColor}> </a></li>
<li><a href="#" data-color="#ec971f" className="btn btn-warning" onClick={this.child1ChangeColor}> </a></li>
<li><a href="#" data-color="#e6e6e6" className="btn btn-default" onClick={this.child1ChangeColor}> </a></li>
</ul>
<ul className="list-inline">
<li>對應第二個child</li>
<li><a href="#" data-color="#286090" className="btn btn-primary" onClick={this.child2ChangeColor}> </a></li>
<li><a href="#" data-color="#31b0d5" className="btn btn-info" onClick={this.child2ChangeColor}> </a></li>
<li><a href="#" data-color="#c9302c" className="btn btn-danger" onClick={this.child2ChangeColor}> </a></li>
<li><a href="#" data-color="#ec971f" className="btn btn-warning" onClick={this.child2ChangeColor}> </a></li>
<li><a href="#" data-color="#e6e6e6" className="btn btn-default" onClick={this.child2ChangeColor}> </a></li>
</ul>
<hr/>
<Child ref="child1" parentChangeColor={this.changeColor} />
<Child ref="child2" parentChangeColor={this.changeColor} />
</div>
);
}
});
ReactDOM.render(
<Parent/>,
document.getElementById('well')
);
</script>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
在瀏覽器中顯示的效果如下
講解:
- 首先說下,剛打開頁面並不是這樣的,背景都是白色的。這裏的截圖是點擊各個按鈕後變色的樣子。
- 在這個例子中,藍色的div是一個父組件,它裏面包含了兩個子組件,分別是紅色和橙色,這兩個子組件實際上是一模一樣的。我們先看下父組件如何調用子組件。
- 代碼中,子組件裏面定義了changeColor函數,用來接收onClick事件,並將點擊的按鈕的data-color屬性值作爲色值,更改到state中的color屬性中,然後觸發render來更新背景色。在父組件調用子組件時,我們寫了,裏面的ref=”child1”就是react中提供的一個屬性標籤,它與普通的props不同,這裏寫上ref=”xxx”後,在父組件中,使用this.refs[“child1”]就可以引用對應的子組件,當然這裏的ref的值是可以隨意定義,只要不重複就好。這樣就可以實現組組件引用子組件,然後直接調用裏面的方法就好,例如
child1ChangeColor
中就有this.refs["child1"].changeColor(e);
的使用。連起來說下邏輯,在點擊父組件中第一列中的按鈕後,觸發onClick事件,然後onClick事件後,傳遞到child1ChangeColor後,將事件傳遞進入,然後再次傳遞給子組件的changeColor中,因爲子組件的changeColor是更改子組件自身的state,所以這時候子組件再次渲染,於是改變了顏色。這就是父組件調用子組件的邏輯。 - 再說下子組件何如調用父組件的方法,父組件自身也有一個changeColor函數,用來改變自身的背景色。當父組件調用子組件時,,通過props,也就是第二個例子中講的那樣,通過參數的方式傳遞給子組件,這樣子組件中就可以使用this.props.parentChangeColor,來把子組件的onClick事件傳遞給父組件的changeColor方法中,來改變父組件的背景色。這就是子組件調用父組件函數的方法。
- 還有一種情況,就是一個父組件下有多個子組件,但是子組件中並沒有直接的關係,這時候如果一個子組件調用另一個子組件的方法,就得通過他們共同的父組件來作爲中轉,在父組件中增加函數來作爲中轉的函數,來實現子組件間的調用。
好啦,以上就是這次分享給大家的react的5個DEMO,雖然只有5個demo,但在常用的情況下應該可以滿足大部分的需求,只要非常瞭解這5個demo就好了。更多的細節大家可以去react官網看下文檔,例如事件,生命週期等,都有較詳細的說明。英文文檔大家不用擔心看不懂,在react文檔地址後面,加一個zh-CH就會變成中文啦~ 例如這個https://facebook.github.io/react/docs/getting-started.html可改成 https://facebook.github.io/react/docs/getting-started-zh-CN.html ,這樣就可以看了。
附件地址在github上~
https://github.com/5977862/react-demo
另入門實例