React是一個Facebook和Instagram用來創(chuàng)建用戶界面的JavaScript庫讥电,用于構建“可預期的”和“聲明式的”Web用戶界面花鹅。 該框架的推出主要為了開發(fā)隨著時間數(shù)據(jù)不斷變化的大規(guī)模應用程序钮科。 具體文檔可以參考官網(wǎng)
React具有以下特點:
- 1.聲明式設計 ?React采用聲明范式,可以輕松描述應用刁笙。
- 2.高效 ?React通過對DOM的模擬改橘,最大限度地減少與DOM的交互滋尉。
- 3.靈活 ?React可以與已知的庫或框架很好地配合。
- 4.JSX ? JSX 是 JavaScript 語法的擴展飞主。React 開發(fā)不一定使用 JSX 狮惜,但我們建議使用它。
- 5.組件 ? 通過 React 構建組件碌识,使得代碼更加容易得到復用碾篡,能夠很好的應用在大項目的開發(fā)中。
- 6.單向響應的數(shù)據(jù)流 ? React 實現(xiàn)了單向響應的數(shù)據(jù)流筏餐,從而減少了重復代碼开泽,這也是它為什么比傳統(tǒng)數(shù)據(jù)綁定更簡單。
目錄
1魁瞪、構建與初始化
2穆律、React元素
3、React組件
4导俘、React組件生命周期
5峦耘、受控與非受控組件
1、構建與初始化
- 方式一:如果你只是想簡單嘗試下 React趟畏,可以使用stackblitz贡歧。在這里滩租,我必須推薦一下這個在線編輯器赋秀,你不需要安裝任何東西,目前支持angular律想、react猎莲、ionic,遲點應該也會支持vue技即。支持github帳號登錄著洼,可以fork和share,一個專門為Web構建的更聰明而叼、更快的包管理器身笤。
- 方式二:可以使用官網(wǎng)推薦用create-react-app的方式,是開始構建新的React單頁面應用的最佳途徑葵陵。它可以幫你配置開發(fā)環(huán)境液荸,以便你可以使用最新的 JavaScript 特性,還能提供很棒的開發(fā)體驗脱篙,并為生產(chǎn)環(huán)境優(yōu)化你的應用娇钱。
// 在終端下全局安裝官網(wǎng)推薦的create-react-app
npm install -g create-react-app
create-react-app my-app
cd my-app
npm start
- 方式三: 可以使用像webpack或Browserify這樣的構建工具伤柄,以便于編寫模塊代碼并將其壓縮,優(yōu)化加載時間文搂,這里推薦使用webpack方式适刀。
2、React元素
react 是React庫的入口點煤蹭。如果你通過script標簽加載React笔喉,這些高階API可用于 React 全局。如果你使用ES6硝皂,你可以使用 import React from 'react' 然遏。如果你使用ES5,你可以使用 var React = require('react')
創(chuàng)建React元素有3種方式吧彪,注意:官網(wǎng)認為createFactor方法過時了待侵,推薦你使用JSX或直接使用 React.createElement() 來替代它。JSX可以看做JavaScript的語法拓展(eXtension)姨裸,看起來有點像XML秧倾,讓我們可以在JavaScript中編寫類似HTML的代碼。 使用React傀缩,可以進行JSX語法到JavaScript的轉換那先。判斷一個元素是HTML元素還是React組件的原則是第一個字母是否大寫,如果為大寫赡艰,則認為是React組件售淡,否則認為是HTML元素。如果我們自定義的組件首字母寫成小寫慷垮,那會得不到我們想要的結果揖闸。在JSX中可以通過onClick這樣的方式來給一個元素添加事件處理函數(shù),在HTML我們還可以用onclick(onclick和onClick是不同的)來添加事件
第一種是React.createElement(type,[props],[...children])
var listItemElement1 = React.createElement('li', {className: 'item-1', key: 'item-1'}, 'Item-1')
var listItemElement2 = React.createElement('li', {className: 'item-2', key: 'item-2'}, 'Item-2')
var listItemElement3 = React.createElement('li', {className: 'item-3', key: 'item-3'}, 'Item-3')
var reactFragment = [listItemElement1, listItemElement2, listItemElement3];
var listOfItems = React.createElement('ul', {className: 'list-of-items'}, reactFragment);
- 第二種是通過創(chuàng)建工廠函數(shù)React.createFactory(type)料身,React.DOM.li(...) 是 React.createELement('li', ...) 的一個包裝寫法汤纸,但被官網(wǎng)認為是過時的,有可能最終會被遺棄芹血。
var createListItemElement = React.createFactory('li');
var listItemElement1 = React.DOM.li({className: 'item-1', key: 'item-1'}, 'Item-1')
var listItemElement2 = React.DOM.li({className: 'item-2', key: 'item-2'}, 'Item-2')
var listItemElement3 = React.DOM.li({className: 'item-3', key: 'item-3'}, 'Item-3')
var reactFragment = [listItemElement1, listItemElement2, listItemElement3];
var listOfItems = React.createElement('ul', {className: 'list-of-items'}, reactFragment);
- 第三種是使用JSX創(chuàng)建React元素贮泞,編寫React的時候,JSX并不是必須的幔烛。每一個JSX元素都只是 React.createElement(component, props, ...children) 的語法糖啃擦。因此,任何時候你用JSX語法寫的代碼也可以用普通的 JavaScript 語法寫出來饿悬。
var listOfItems = <ul className="list-of-items">
<li className="item-1">Item 1</li>
<li className="item-2">Item 2</li>
<li className="item-3">Item 3</li>
</ul>;
//官網(wǎng)例子jsx寫法
class Hello extends React.Component {
render() {
return <div>Hello {this.props.toWhat}</div>;
}
}
//編譯轉成不使用JSX的代碼
class Hello extends React.Component {
render() {
return React.createElement('div', null, `Hello ${this.props.toWhat}`);
}
}
ReactDOM.render(
React.createElement(Hello, {toWhat: 'World'}, null),
document.getElementById('root')
);
- 渲染React元素
//格式:ReactDOM.render(ReactElement, DOMElement, callback);
ReactDOM.render(
listOfItems,
document.getElementById('example')
)
3令蛉、React組件
- 可以通過三種方式創(chuàng)建React組件,注意乡恕,組件類的第一個字母必須大寫言询,否則會報錯俯萎,比如HelloMessage不能寫成helloMessage。另外运杭,組件類只能包含一個頂層標簽夫啊,否則也會報錯。
- 第一種無狀態(tài)函數(shù)式組件辆憔,無狀態(tài)函數(shù)式組件形式上表現(xiàn)為只帶有一個render方法的組件類撇眯,通過函數(shù)形式或者ES6 arrow function的形式創(chuàng)建,并且該組件是無state狀態(tài)的虱咧。只要有可能熊榛,盡量使用無狀態(tài)組件。能用React.Component創(chuàng)建的組件的就盡量不用React.createClass形式創(chuàng)建組件腕巡。
function HelloComponent(props) {
return <div> Hello {props.name} </div>;
}
ReactDOM.render(
<HelloComponent name="world" />,
document.getElementById('example')
)
- 第二種React.createClass玄坦,它是react剛開始推薦的創(chuàng)建組件的方式,是用ES5的寫法實現(xiàn)
var InputControlES5 = React.createClass({
propTypes: {//定義傳入props中的屬性各種類型要求绘沉,可以接受任意值煎楣,字符串、對象车伞、函數(shù)等等择懂。
initialValue: React.PropTypes.string.isRequired
},
defaultProps: { //用來設置組件屬性的默認值
initialValue: 'Hello World'
},
getInitialState: function() {//用于定義初始狀態(tài),也就是一個對象另玖,這個對象可以通過 this.state 屬性讀取困曙。
return {
text: this.props.initialValue || 'placeholder'
};
},
handleChange: function(event) {
this.setState({ //事件的回調(diào)函數(shù),當用戶交互導致狀態(tài)變化谦去,this.setState 方法就修改狀態(tài)值慷丽,每次修改以后,自動調(diào)用this.render方法哪轿,再次渲染組件盈魁。
text: event.target.value
});
},
render: function() {
return (
<div>
Type something:
<input onChange={this.handleChange} value={this.state.text} />
</div>
);
}
});
ReactDOM.render(
<InputControlES5 />,
document.getElementById('example')
)
- 第三種是React.Component,它是以ES6的形式來創(chuàng)建react的組件的窃诉,是React目前極為推薦的創(chuàng)建有狀態(tài)組件的方式,最終會取代React.createClass形式赤套;相對于 React.createClass可以更好實現(xiàn)代碼復用飘痛。將上面React.createClass的形式改為React.Component形式如下:
class InputControlES6 extends React.Component {
constructor(props) {
super(props); //調(diào)用super,是為了正確獲取到this
this.state = {
text: props.initialValue || 'placeholder'
};
this.handleChange = this.handleChange.bind(this); // ES6 類中函數(shù)必須手動綁定
}
handleChange(event) {
this.setState({
text: event.target.value
});
}
render() {
return (
<div>
Type something:
<input onChange={this.handleChange} value={this.state.text} />
</div>
);
}
}
InputControlES6.propTypes = {
initialValue: React.PropTypes.string.isRequired
};
InputControlES6.defaultProps = {
initialValue: 'Hello Wrold'
};
ReactDOM.render(
<InputControlES6 />,
document.getElementById('example')
)
React.createClass與React.Component區(qū)別
- React.createClass 創(chuàng)建的組件容握,其每一個成員函數(shù)的this都有React自動綁定宣脉,任何時候,直接使用this.method即可剔氏,函數(shù)中的this會被正確設置
- React.Component創(chuàng)建的組件塑猖,其成員函數(shù)不會自動綁定this竹祷,需要開發(fā)者手動綁定,否則將它作為事件處理函數(shù)被調(diào)用時不能通過this獲取當前組件實例對象羊苟。
- React.Component 有三種手動綁定方法:
1塑陵、在構造函數(shù)中完成綁定
2、調(diào)用時使用method.bind(this)來完成綁定
3蜡励、使用arrow function 來綁定 - 組件屬性類型 propTypes 及其默認 props 屬性 defaultProps 配置不同令花。
- 組件初始狀態(tài)state配置不同。React.createClass創(chuàng)建的組件凉倚,其狀態(tài)state是通過getInitState方法方法來配置組件的相關狀態(tài)兼都。React.Component創(chuàng)建的組件,其狀態(tài)state是在construct中像初始化組件屬性一樣聲明稽寒。
- Mixins的支持不同扮碧。React.createClass在創(chuàng)建組件時可以使用mixins屬性,以數(shù)組的形式來混合類的集合杏糙。React.Component不支持Mixins,React開發(fā)者社區(qū)提供了一個全新的方式來取代Mixins芬萍,那就是Higher-Order Components(高階組件)
//React.createClass
const Contacts = React.createClass({
handleClick() {
console.log(this); // React組件實例
},
render() {
return (
<div onClick={this.handleClick}></div>
);
}
});
//React.Component
class Contacts extends React.Component {
constructor(props) {
super(props);
}
handleClick() {
console.log(this); // null
}
render() {
return (
<div onClick={this.handleClick}></div>
);
}
}
//React.Component綁定this方法
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this); //構造函數(shù)中綁定
}
<div onClick={this.handleClick.bind(this)}></div> //使用bind來綁定
<div onClick={()=>this.handleClick()}></div> //使用arrow function來綁定
4、React組件生命周期
組件的生命周期分成三個狀態(tài):
- 掛在(Mounting): 這個階段發(fā)生在組件被創(chuàng)建并被插入到DOM時
- 更新(Updating): 這個階段發(fā)生在組件被重新渲染成虛擬DOM并決定實際DOM是否需要更新時
- 卸載(Unmounting): 這個階段發(fā)生在組件從DOM中被刪除時
組件掛載階段
ES5(React.createClass)
- getInitialState()
- componentWillMount()
- render()
- componentDidMount()
ES6(React.Component)
- constructor()
- componentWillMount()
- render()
- componentDidMount()
組件更新階段
- componentWillReceiveProps()
- shouldComponentUpdate()
- componentWillUpdate()
- render()
- componentDidUpdate()
組件卸載階段
- componentWillUnmount()
var Hello = React.createClass({
getInitialState: function () {
return {
opacity: 1.0
};
},
componentDidMount: function () {
this.timer = setInterval(function () {
var opacity = this.state.opacity;
opacity -= .05;
if (opacity < 0.1) {
opacity = 1.0;
}
this.setState({
opacity: opacity
});
}.bind(this), 100);
},
render: function () {
return (
<div style={{opacity: this.state.opacity}}>
Hello {this.props.name}
</div>
);
}
});
ReactDOM.render(
<Hello name="world"/>,
document.body
);
5搔啊、受控與非受控組件
React 通過props和state來區(qū)分組件的屬性和狀態(tài)柬祠。其中,props(屬性)用來表示組件外部傳入的屬性负芋,組件內(nèi)部不能改變漫蛔。而state(狀態(tài))通常表示組件內(nèi)部的狀態(tài),狀態(tài)是可以并且應該改變的旧蛾。React通過 props和state的值來渲染組件莽龟,組件渲染完畢之后,通過響應用戶操作或者異步網(wǎng)絡請求等操作更新組件的狀態(tài)來重新渲染組件锨天。
- 受控組件將表單數(shù)據(jù)統(tǒng)一存放在 state 中毯盈,交由 React 管理,我們就可以根據(jù)用戶的輸入及時作出響應:1病袄、驗證輸入正確性(輸入格式搂赋、類型等),并作出反饋 2益缠、根據(jù)輸入設置其它組件的狀態(tài)脑奠,譬如輸入不規(guī)范時,提交按鈕處于不可用狀態(tài)
class ControlledForm extends React.Component {
constructor(props) {
super(props);
this.state = {
username: ''
}
this.handleSubmit = this.handleSubmit.bind(this);
this.updateUsername = this.updateUsername.bind(this);
}
updateUsername(e) {
this.setState({
username: e.target.value,
})
}
handleSubmit() {}
render () {
return (
<form onSubmit={this.handleSubmit}>
<input
type='text'
value={this.state.username}
onChange={this.updateUsername} />
<button type='submit'>Submit</button>
</form>
)
}
}
ReactDOM.render(<ControlledForm />, document.getElementById('react-root'))
- 非受控組件和傳統(tǒng)的表單數(shù)據(jù)管理一樣幅慌,由DOM存放表單數(shù)據(jù)宋欺,可以使用React提供的refs來獲得DOM元素的引用。在需要的時候(譬如表單提交的時候)一次性獲取表單的值。
class UnControlledForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(e) {
e.preventDefault();
console.log("Value: ", this.input.value)
}
render () {
return (
<form onSubmit={this.handleSubmit}>
<input
type='text'
ref={(input) => this.input = input} />
<button type='submit'>Submit</button>
</form>
)
}
}
ReactDOM.render(<UnControlledForm />, document.getElementById('react-root'));
- 參考文獻
1齿诞、阮一峰React 入門實例教程
2酸休、React從入門到放棄 -- 筆記、教程祷杈、Demo