一、React 相關(guān)概念:
1.1. 含義:
- React 是一個用于構(gòu)建用戶界面的JavaScript庫。
- React主要用于構(gòu)建UI,很人多認為 React 是 MVC 中的 V(視圖)。
- React 起源于 Facebook 的內(nèi)部項目,用來架設(shè) Instagram 的網(wǎng)站,并于 2013 年 5 月開源。
- React 擁有較高的性能,代碼邏輯非常簡單,越來越多的人已開始關(guān)注和使用它。
1.2. 作用:
- 用做UI: 許多人把React當(dāng)做MVC設(shè)計模式中的視圖(view),當(dāng)把React成為你的技術(shù)掌握之后, 它可以很輕松應(yīng)用于一個小功能的項目。
- 虛擬DOM:React用一個”虛擬DOM”實現(xiàn)了超高的性能,配合nodeJS也可以實現(xiàn)在服務(wù)端的渲染,不存在耗時的瀏覽器dom渲染。
- 數(shù)據(jù)流: React是一種減少引用數(shù)據(jù)流的實現(xiàn)方式,并且比傳統(tǒng)的方式更容易實現(xiàn)數(shù)據(jù)綁定。
- React Native 項目就是使用 React 和 JavaScript 創(chuàng)建本機 APP。
1.3. 特點:
- 聲明式設(shè)計 ?React采用聲明范式,可以輕松描述應(yīng)用。
- 高效 ?React通過對DOM的模擬,最大限度地減少與DOM的交互。
- 靈活 ?React可以與已知的庫或框架很好地配合。
- JSX ? JSX 是 JavaScript 語法的擴展。React 開發(fā)不一定使用 JSX ,但我們建議使用它。
- 組件 ? 通過 React 構(gòu)建組件,使得代碼更加容易得到復(fù)用,能夠很好的應(yīng)用在大項目的開發(fā)中。
- 單向響應(yīng)的數(shù)據(jù)流 ? React 實現(xiàn)了單向響應(yīng)的數(shù)據(jù)流,從而減少了重復(fù)代碼,這也是它為什么比傳統(tǒng)數(shù)據(jù)綁定更簡單。
二、安裝
- 關(guān)于安裝這里不再贅述,你可以在官網(wǎng) http://facebook.github.io/react/ 下載最新版;
- 也可以直接使用 cdn 上的React CDN 庫,地址如下:
<script src="https://cdn.bootcss.com/react/15.4.2/react.min.js"></script>
<script src="https://cdn.bootcss.com/react/15.4.2/react-dom.min.js"></script>
<script src="https://cdn.bootcss.com/babel-standalone/6.22.1/babel.min.js"></script>
說明:
1.react.min.js - React 的核心庫;
2.react-dom.min.js - 提供與 DOM 相關(guān)的功能;
3.browser.min.js - 用于將 JSX 語法轉(zhuǎn)為 JavaScript 語法,關(guān)于 JSX 語法在下面說明。
三、 React JSX 語法說明
- JSX 的語法如下:
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
以上代碼將一個 h1 標(biāo)題,插入 id="example" 節(jié)點中。
如果我們需要使用 JSX,則 <script> 標(biāo)簽的 type 屬性需要設(shè)置為 text/babel。
我們可以在 JSX 中使用 JavaScript 表達式。表達式寫在花括號 {} 中
- 完整示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcss.com/react/15.4.2/react.min.js"></script>
<script src="https://cdn.bootcss.com/react/15.4.2/react-dom.min.js"></script>
<script src="https://cdn.bootcss.com/babel-standalone/6.22.1/babel.min.js"></script>
</head>
<body>
<div id="em1"></div>
<script type="text/babel">
ReactDOM.render(
<h1>Hello, YijiangWang! {1+2}</h1>,
document.getElementById('em1')
)
</script>
</body>
</html>
四、 組件
- 通過方法
React.createClass方法用于生成一個組件類; - 如果我們需要向組件傳遞參數(shù),可以使用 this.props 對象,實例如下:
var Yjw_component = React.createClass({
render: function() {
return <h1>Hello {this.props.name}</h1>;
}
});
ReactDOM.render(
<Yjw_component name="Yjw" />,
document.getElementById('example')
);
注意:
1.原生 HTML 元素名以小寫字母開頭,而自定義的 React 類名以大寫字母開頭;
2.組件類只能包含一個頂層標(biāo)簽,否則也會報錯。
- 復(fù)合組件:
//自定義符合組件
/**
* 注意點:
* 1、組件首字母要大寫
* 2、不能 return 多個控件,如果需要返回多個控件,可以在最外層用一個控件進行包裝
* 3、return 控件時,要用 () 進行包裝
* */
var Contenttxt = React.createClass({
render:function () {
return (
<h1>{this.props.contentt}</h1>
)
}
});
var Titletxt = React.createClass({
render:function () {
return (
<h2>{this.props.titlet}</h2>
)
}
});
var Article = React.createClass({
render:function () {
return (
<div>
<Titletxt titlet={this.props.titlet} />
<Contenttxt contentt={this.props.contentt} />
</div>
)
}
});
ReactDOM.render(
<Article titlet="I'm the title" contentt="I'm the content"></Article>,
document.getElementById("example")
)
五、React State(狀態(tài))
//自定義一個組件
var Yjw = React.createClass({
//定義初始狀態(tài)
getInitialState:function () {
return {like:true};
},
//定義一個點擊事件
handle:function () {
this.setState({like:!this.state.like})
},
render:function () {
var text = this.state.like?"喜歡":"不喜歡";
return (
<h1 onClick={this.handle}>{this.props.titlet}如果你 <ins>{text}</ins> 我,就點我</h1>
)
},
});
//渲染一個組件
ReactDOM.render(
<Yjw/>,
document.getElementById("example")
)
六、React Props
- 設(shè)置默認 props
var Dprop = React.createClass({
getDefaultProps:function () {
return {
name:"yijiang"
}
},
render:function () {
return (
<h1>這里是默認的:{this.props.name}</h1>
)
}
});
ReactDOM.render(
<Dprop name="mage"/>,
document.getElementById("prop1")
);
- props 和 state 結(jié)合使用
var Name = React.createClass({
render:function () {
return <h1>I'm {this.props.name}</h1>
}
});
var Site = React.createClass({
render:function () {
return <a href={this.props.site}>{this.props.site}</a>
}
});
var Website = React.createClass({
getInitialState:function () {
return {
name:"yijiang",
site:"www.baidu.com"
}
},
clickName:function () {
this.setState({name:"magege"});
},
render:function () {
return (
<div onClick={this.clickName}>
<Name name={this.state.name}/>
<Site site={this.state.site}/>
</div>
)
}
});
ReactDOM.render(
<Website/>,
document.getElementById("prop2")
);
- prop 驗證:這里驗證 title 必須為 string 類型,并且是必須字段:
var Vprop = React.createClass({
propTypes:{
title:React.PropTypes.string.isRequired
},
render:function () {
return (<h1>{this.props.title}</h1>)
}
});
ReactDOM.render(
<Vprop title="123"/>,
document.getElementById("prop3")
)
更多的驗證器說明如下
React.createClass({
propTypes: {
// 可以聲明 prop 為指定的 JS 基本數(shù)據(jù)類型,默認情況,這些數(shù)據(jù)是可選的
optionalArray: React.PropTypes.array,
optionalBool: React.PropTypes.bool,
optionalFunc: React.PropTypes.func,
optionalNumber: React.PropTypes.number,
optionalObject: React.PropTypes.object,
optionalString: React.PropTypes.string,
// 可以被渲染的對象 numbers, strings, elements 或 array
optionalNode: React.PropTypes.node,
// React 元素
optionalElement: React.PropTypes.element,
// 用 JS 的 instanceof 操作符聲明 prop 為類的實例。
optionalMessage: React.PropTypes.instanceOf(Message),
// 用 enum 來限制 prop 只接受指定的值。
optionalEnum: React.PropTypes.oneOf(['News', 'Photos']),
// 可以是多個對象類型中的一個
optionalUnion: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number,
React.PropTypes.instanceOf(Message)
]),
// 指定類型組成的數(shù)組
optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
// 指定類型的屬性構(gòu)成的對象
optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
// 特定 shape 參數(shù)的對象
optionalObjectWithShape: React.PropTypes.shape({
color: React.PropTypes.string,
fontSize: React.PropTypes.number
}),
// 任意類型加上 `isRequired` 來使 prop 不可空。
requiredFunc: React.PropTypes.func.isRequired,
// 不可空的任意類型
requiredAny: React.PropTypes.any.isRequired,
// 自定義驗證器。如果驗證失敗需要返回一個 Error 對象。不要直接使用 `console.warn` 或拋異常,因為這樣 `oneOfType` 會失效。
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error('Validation failed!');
}
}
},
/* ... */
});
六、React 組件 API
設(shè)置狀態(tài):setState
替換狀態(tài):replaceState
設(shè)置屬性setProps
替換屬性replaceProps
強制更新:forceUpdate
獲取DOM節(jié)點:findDOMNode
-
判斷組件掛載狀態(tài):isMounted
這里列舉兩例:setState 和 setProps,其它 API 使用大同小異,這里不一一例舉:
//setState
var Sta = React.createClass({
getInitialState:function () {
return {
clickCount:0
}
},
// clickEvent:function () {
// this.setState({clickCount:this.state.clickCount+1})
// },
//這里兩個 clickEvent 方法作用相同
clickEvent:function () {
this.setState(function (state) {
return {clickCount:state.clickCount+1}
})
},
render:function () {
return <h1 onClick={this.clickEvent}>點擊的次數(shù)為:{this.state.clickCount}</h1>
}
});
ReactDOM.render(
<Sta/>,
document.getElementById("example1")
);
//setProps
var Sprop = React.createClass({
getInitialProps:function () {
return {
clickCount:0
}
},
clickEvent:function () {
this.setProps({clickCount:this.props.clickCount+1})
},
//這里兩個 clickEvent 方法作用相同
// clickEvent:function () {
// this.setProps(function (state) {
// return {clickCount:state.clickCount+1}
// })
// },
render:function () {
return <h1 onClick={this.clickEvent}>點擊的次數(shù)為:{this.props.clickCount}</h1>
}
});
ReactDOM.render(
<Sta/>,
document.getElementById("example2")
)
七、生命周期函數(shù)
- 生命周期的方法有:
- componentWillMount 在渲染前調(diào)用,在客戶端也在服務(wù)端。
- componentDidMount : 在第一次渲染后調(diào)用,只在客戶端。之后組件已經(jīng)生成了對應(yīng)的DOM結(jié)構(gòu),可以通過this.getDOMNode()來進行訪問。 如果你想和其他JavaScript框架一起使用,可以在這個方法中調(diào)用setTimeout, setInterval或者發(fā)送AJAX請求等操作(防止異部操作阻塞UI)。
- componentWillReceiveProps 在組件接收到一個新的prop時被調(diào)用。這個方法在初始化render時不會被調(diào)用。
- shouldComponentUpdate 返回一個布爾值。在組件接收到新的props或者state時被調(diào)用。在初始化時或者使用forceUpdate時不被調(diào)用。 可以在你確認不需要更新組件時使用。
- componentWillUpdate在組件接收到新的props或者state但還沒有render時被調(diào)用。在初始化時不會被調(diào)用。
- componentDidUpdate 在組件完成更新后立即調(diào)用。在初始化時不會被調(diào)用。
- componentWillUnmount在組件從 DOM 中移除的時候立刻被調(diào)用。
<body>
<div id="em1"></div>
<div id="em2"></div>
<script type="text/babel">
//定義一個 Hello 組件,并且每秒鐘重新渲染一次
var Hello = React.createClass({
//初始化 state
getInitialState:function () {
return {opacity:1.0}
},
componentDidMount:function () {
this.timer = setInterval(function () {
var opacity = this.state.opacity;
opacity -= 0.2;
if (opacity < 0.1){
opacity = 1.0;
}
this.setState({opacity:opacity})
}.bind(this),1000);
},
render:function () {
return (
<div style={{opacity:this.state.opacity}}>
Hello {this.props.name}
</div>
)
}
});
ReactDOM.render(
<Hello name="Yijiang"/>,
document.getElementById("em1")
);
//定義一個 Button 組件
var Button = React.createClass({
getInitialState:function () {
return {data:0}
},
setNewNumber:function () {
this.setState({data:this.state.data+1})
},
render:function () {
return (
<div>
<button onClick={this.setNewNumber}>Increment</button>
<Content myNumber={this.state.data}></Content>
</div>
)
}
});
//定義一個 Content 組件
var Content = React.createClass({
componentWillMount:function () {
console.log("component Will Mount");
},
componentDidMount:function () {
console.log("component Did Mount");
},
componentWillReceiveProps:function(newProps) {
console.log('Component WILL RECIEVE PROPS!')
},
shouldComponentUpdate:function(newProps, newState) {
return true;
},
componentWillUpdate:function(nextProps, nextState) {
console.log('Component WILL UPDATE!');
},
componentDidUpdate:function(prevProps, prevState) {
console.log('Component DID UPDATE!')
},
componentWillUnmount:function() {
console.log('Component WILL UNMOUNT!')
},
render: function () {
return (
<div>
<h3>{this.props.myNumber}</h3>
</div>
);
}
});
ReactDOM.render(
<div>
<Button />
</div>,
document.getElementById('em2')
);
/**
* 首先會展示前兩條:
* component Will Mount
* component Did Mount
* 當(dāng)點擊之后會顯示以下三條
* Component WILL RECIEVE PROPS!
* Component WILL UPDATE!
* Component DID UPDATE!
*/
</script>
</body>
八、React AJAX:
- React 組件的數(shù)據(jù)可以通過 componentDidMount 方法中的 Ajax 來獲取,當(dāng)從服務(wù)端獲取數(shù)據(jù)庫可以將數(shù)據(jù)存儲在 state 中,再用 this.setState 方法重新渲染 UI。
- 當(dāng)使用異步加載數(shù)據(jù)時,在組件卸載前,在 componentWillUnmount 里面取消未完成的請求。
var UserGist = React.createClass({
getInitialState: function() {
return {
username: '',
lastGistUrl: ''
};
},
componentDidMount: function() {
this.serverRequest = $.get(this.props.source, function (result) {
var lastGist = result[0];
this.setState({
username: lastGist.owner.login,
lastGistUrl: lastGist.html_url
});
}.bind(this));
},
componentWillUnmount: function() {
this.serverRequest.abort();
},
render: function() {
return (
<div>
{this.state.username} 用戶最新的 Gist 共享地址:
<a href={this.state.lastGistUrl}>{this.state.lastGistUrl}</a>
</div>
);
}
});
ReactDOM.render(
<UserGist source="https://api.github.com/users/octocat/gists" />,
document.getElementById("em1")
);
九、React 表單與事件:
<body>
<div id="em1"></div>
<div id="em2"></div>
<div id="em3"></div>
<div id="em4"></div>
<script type="text/babel">
//一、React 表單與事件
//設(shè)置輸入框 input 值value = {this.state.data}。在輸入框值發(fā)生變化時我們可以更新 state。
var Yjw_input = React.createClass({
getInitialState:function () {
return {value:"Yijiangwang"}
},
changeValue:function (event) {
this.setState({value:event.target.value})
},
render:function () {
var txt = this.state.value;
return (
<div>
<h3>這里是value的值:{this.state.value}</h3>
<input value={this.state.value} onChange={this.changeValue}/>
</div>
)
}
});
ReactDOM.render(
<Yjw_input></Yjw_input>,
document.getElementById("em1")
);
//在子組件上使用表單。 onChange 方法將觸發(fā) state 的更新并將更新的值傳遞到子組件的輸入框的 value 上來重新渲染界面。
//在父組件通過創(chuàng)建事件句柄 (handleChange) ,并作為 prop (updateStateProp,這里名字可以隨意取) 傳遞到你的子組件上。
//創(chuàng)建一個子組件
var Content = React.createClass({
render:function () {
return <div>
<h4>{this.props.myDataProp}</h4>
<input type="text" value={this.props.myDataProp} onChange={this.props.updateStateProp} />
</div>;
}
});
//創(chuàng)建一個父組件
var HelloMessage = React.createClass({
getInitialState: function() {
return {value: 'Hello Yijiang!'};
},
handleChange: function(event) {
this.setState({value: event.target.value});
},
render: function() {
var value = this.state.value;
return <div>
<Content myDataProp = {value}
updateStateProp = {this.handleChange}></Content>
</div>;
}
});
ReactDOM.render(
<HelloMessage />,
document.getElementById('em2')
);
//二、React 事件
//通過 onClick 事件來修改數(shù)據(jù)
var Yjw_click = React.createClass({
getInitialState: function() {
return {value: 'Hello Yijiang!'};
},
handleChange: function(event) {
this.setState({value: 'Hello YijiangWang!'})
},
render: function() {
var value = this.state.value;
return <div>
<button onClick={this.handleChange}>點我</button>
<h4>{value}</h4>
</div>;
}
});
ReactDOM.render(
<Yjw_click />,
document.getElementById('em3')
);
//當(dāng)需要從子組件中更新父組件的 state 時,需要在父組件通過創(chuàng)建事件句柄 (handleChange) ,并作為 prop (updateStateProp) 傳遞到子組件上。
//子組件
var Child_event = React.createClass({
render: function() {
return <div>
<button onClick = {this.props.updateStateProp}>點我</button>
<h4>{this.props.myDataProp}</h4>
</div>
}
});
//父組件
var Father_event = React.createClass({
getInitialState: function() {
return {value: 'Hello Yijiang!'};
},
handleChange: function(event) {
this.setState({value: 'Hello YijiangWang!'})
},
render: function() {
var value = this.state.value;
return <div>
<Child_event myDataProp = {value}
updateStateProp = {this.handleChange}></Child_event>
</div>;
}
});
ReactDOM.render(
<Father_event />,
document.getElementById('em4')
);
</script>
</body>
十、React Refs
- React 支持一種非常特殊的屬性 Ref ,你可以用來綁定到 render() 輸出的任何組件上。
- 這個特殊的屬性允許你引用 render() 返回的相應(yīng)的支撐實例( backing instance )。這樣就可以確保在任何時間總是拿到正確的實例。
- 使用方法:
//綁定一個 ref 屬性到 render 的返回值上:
<input ref="myInput" />
//在其它代碼中,通過 this.refs 獲取支撐實例:
var input = this.refs.myInput;
var inputValue = input.value;
var inputRect = input.getBoundingClientRect();
- 具體實例:
<div id="em1"></div>
<script type="text/babel">
//可以通過使用 this 來獲取當(dāng)前 React 組件,或使用 ref 來獲取組件的引用
var Yjw_component = React.createClass({
handleClick: function() {
// 使用原生的 DOM API 獲取焦點
this.refs.myInput.focus();
},
render: function() {
// 當(dāng)組件插入到 DOM 后,ref 屬性添加一個組件的引用于到 this.refs
return (
<div>
<input type="text" ref="myInput" />
<input
type="button"
value="點我輸入框獲取焦點"
onClick={this.handleClick}
/>
</div>
);
}
});
ReactDOM.render(
<Yjw_component />,
document.getElementById('em1')
);
</script>