最近在學(xué)習(xí)react,希望有系統(tǒng)的資料呜象,這篇文章適合入門:
React可以在瀏覽器運(yùn)行孽惰,也可以在服務(wù)器運(yùn)行晚岭,但是在這為了盡量保持簡單,且React語法是一致的勋功,服務(wù)器的用法和瀏覽器差別不大坦报,在這只涉及瀏覽器。
一. HTML模板
使用React的網(wǎng)頁源碼狂鞋,結(jié)構(gòu)大致如下:
<!DOCTYPE html>
<html >
<head>
<script type="text/javascript" src="react.min.js"></script>
<script type="text/javascript" src="JSXTransformer.js"></script>
</head>
<body>
<div id="example" ></div>
<script type="text/jsx">
//Our code goes here!
</script>
</body>
</html>
注意:
1.最后一個script標(biāo)簽的type屬性為text/jsx片择。這是因?yàn)镽eact獨(dú)有的JSX語法,跟JavaScript不兼容骚揍。凡是使用JSX的地方字管,都要加上type=”text/jsx”。
2.React提供兩個庫:react.js和JSXTransformer.js疏咐,它們必須首先加載纤掸,其中JSXTransformer.js的作用是將JSX語法轉(zhuǎn)為JavaScript語法。這一步很消耗時間浑塞,實(shí)際上線的時候借跪,應(yīng)該將它放到服務(wù)器完成。
$ jsx src/ build/:這個命令可以將src子目錄的js文件進(jìn)行語法轉(zhuǎn)換酌壕,轉(zhuǎn)碼后的文件全部放在build子目錄掏愁。
二. React.render()
React.render是React的最基本方法,用于將模板轉(zhuǎn)為HTML語言卵牍,并插入指定的DOM節(jié)點(diǎn)果港。
實(shí)例一:
<!DOCTYPE html>
<html >
<head>
<script src="es5-shim.min.js"></script>
<script src="es5-sham.min.js"></script>
<script src="console-polyfill.js"></script>
<script type="text/javascript" src="react.min.js"></script>
<script type="text/javascript" src="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>
運(yùn)行效果:
三. JSX語法
HTML語言直接寫在JavaScript語言之中,不加任何引號糊昙,這就是JSX的語法辛掠,它允許HTML與JavaScript的混寫。
實(shí)例二:
<!DOCTYPE html>
<html >
<head>
<script src="es5-shim.min.js"></script>
<script src="es5-sham.min.js"></script>
<script src="console-polyfill.js"></script>
<script type="text/javascript" src="react.min.js"></script>
<script type="text/javascript" src="JSXTransformer.js"></script>
</head>
<body>
<div id="example" ></div>
<script type="text/jsx">
var names = ['Alice','Emily','Kate'];
React.render(
<div>
{
names.map(function(name) {
return <div>Hello,{name}!</div>
})
}
</div>,
document.getElementById("example")
);
</script>
</body>
</html>
運(yùn)行效果:
上面代碼體現(xiàn)了JSX的基本語法規(guī)則:遇到HTML標(biāo)簽(以<開頭)释牺,就用HTML規(guī)則解析萝衩;遇到代碼塊(以{開頭},就用JavaScript規(guī)則解析没咙。
JSX允許直接在模板插入JavaScript變量猩谊。如果這個變量是一個數(shù)組,則會展開這個數(shù)組的所有成員
實(shí)例三:
<html >
<head>
<script src="es5-shim.min.js"></script>
<script src="es5-sham.min.js"></script>
<script src="console-polyfill.js"></script>
<script type="text/javascript" src="react.min.js"></script>
<script type="text/javascript" src="JSXTransformer.js"></script>
</head>
<body>
<div id="example" ></div>
<script type="text/jsx">
var arr = [
<h1>Hello world!</h1>,
<h2>React is awesome</h2>
];
React.render(
<div>{arr}</div>,
document.getElementById("example")
);
</script>
</body>
</html>
上面代碼的arr變量是一個數(shù)組祭刚,結(jié)果JSX會把它的所有成員牌捷,添加到模板墙牌,運(yùn)行結(jié)果如下:
四. 組件
React允許將代碼封裝成組件(component),然后像插入普通HTML標(biāo)簽一樣暗甥,在網(wǎng)頁中插入這個組件喜滨。React.createClass方法就用于生成一個組件類。
實(shí)例四:
<!DOCTYPE html>
<html >
<head>
<script src="es5-shim.min.js"></script>
<script src="es5-sham.min.js"></script>
<script src="console-polyfill.js"></script>
<script type="text/javascript" src="react.min.js"></script>
<script type="text/javascript" src="JSXTransformer.js"></script>
</head>
<body>
<div id="example" ></div>
<script type="text/jsx">
var HelloMessage = React.createClass({
render: function() {
return <h1>Hello {this.props.name}</h1>;
}
});
React.render(
<HelloMessage name="John"/>,
document.getElementById("example")
);
</script>
</body>
</html>
運(yùn)行效果:
上面代碼中淋袖,變量HelloMessage就是一個組件類鸿市。模板插入<HelloMessage/>時,會自動生成HelloMessage的一個實(shí)例(下文的“組件”都指組件類的實(shí)例)即碗。所有組件類都必須有自已的render方法焰情,用于輸出組件。
組件的用法與原生的HTML標(biāo)簽完全一致剥懒,可以任意加入屬性内舟,比如<HelloMessage name=”John”/>,就是HelloMessage組件加入一個name屬性初橘,值為John验游。組件的屬性可以在組件類的this.props對象上獲取,比如name屬性就可以通過this.props.name讀取保檐。
添加組件屬性耕蝉,有一個地方需要注意,就是class屬性需要寫成className夜只,for屬性需要寫成htmlFor垒在,這是因?yàn)閏lass和for是JavaScript的保留字。
五. this.props.children
this.props對象的屬性與組件的屬性一一對應(yīng)扔亥,但是有一個例外场躯,就是this.props.children屬性。它表示組件的所有子節(jié)點(diǎn)旅挤。
實(shí)例五:
<!DOCTYPE html>
<html >
<head>
<script src="es5-shim.min.js"></script>
<script src="es5-sham.min.js"></script>
<script src="console-polyfill.js"></script>
<script type="text/javascript" src="react.min.js"></script>
<script type="text/javascript" src="JSXTransformer.js"></script>
</head>
<body>
<script type="text/jsx">
var NotesList = React.createClass({
render:function() {
return (
<ol>
{
this.props.children.map(function(child) {
return <li>{child}</li>
})
}
</ol>
);
}
});
React.render(
<NotesList>
<span>hello</span>
<span>world</span>
</NotesList>,
document.body
);
</script>
</body>
</html>
上面代碼的NoteList組件有兩個span子節(jié)點(diǎn)踢关,它們都可以通過this.props.children讀取,運(yùn)行結(jié)果如下:
這里需要注意粘茄,只有當(dāng)子節(jié)點(diǎn)多于1個時签舞,this.props.children才是一個數(shù)組,否則是不能用map方法的柒瓣,會報錯瘪菌。
六. React.findDOMNode()
組件并不是真實(shí)的DOM節(jié)點(diǎn),而是存在于內(nèi)存之中的一種數(shù)據(jù)結(jié)構(gòu)嘹朗,叫做虛擬DOM(virtual DOM)。只有當(dāng)它插入文檔之后诵肛,才會變成真實(shí)的DOM屹培。根據(jù)React的設(shè)計(jì)默穴,所有的DOM變動,都先在虛擬DOM上發(fā)生褪秀,然后再將實(shí)際發(fā)生變動的部分蓄诽,反映在真實(shí)DOM上,這種算法叫做DOM diff媒吗,它可以極大提高網(wǎng)頁的性能仑氛。
但是,有時需要從組件獲取真實(shí)DOM的節(jié)點(diǎn)闸英,這時就要用到React.findDOMNode方法锯岖。
實(shí)例六:
<html >
<head>
<script src="es5-shim.min.js"></script>
<script src="es5-sham.min.js"></script>
<script src="console-polyfill.js"></script>
<script type="text/javascript" src="react.min.js"></script>
<script type="text/javascript" src="JSXTransformer.js"></script>
</head>
<body>
<div id="example" ></div>
<script type="text/jsx">
var MyComponent = React.createClass({
handleClick: function() {
React.findDOMNode(this.refs.myTextInput).focus();
},
render: function() {
return (
<div>
<input type="text" ref="myTextInput"/>
<input type="button" value="Focus the text input" onClick={this.handleClick}/>
</div>
);
}
});
React.render(
<MyComponent/>,
document.getElementById('example')
);
</script>
</body>
</html>
運(yùn)行效果:
上面代碼中,組件MyComponent的子節(jié)點(diǎn)有一個文本輸入框甫何,用于獲取用戶的輸入出吹。這時就必須獲取真實(shí)的DOM節(jié)點(diǎn),虛擬DOM是拿不到用戶輸入的辙喂。為了做到這一點(diǎn)捶牢,文本輸入框必須有一個ref屬性,然后this.refs.[refName]就指向這個虛擬DOM的子節(jié)點(diǎn)巍耗,最后通過React.findDOMNode方法獲取真實(shí)DOM的節(jié)點(diǎn)秋麸。
需要注意的是,由于React.findDOMNode方法獲取的是真實(shí)DOM炬太,所以必須等到虛擬DOM插入文檔以后灸蟆,才能使用這個方法,否則會返回null娄琉。上面代碼中次乓,通過為組件指定Click事件的回調(diào)函數(shù),確保了只有等到真實(shí)DOM發(fā)生Click事件之后孽水,才會調(diào)用React.findDOMNode方法票腰。
React組件支持很多事件,除了Click事件以外女气,還有KeyDown杏慰、Copy、Scroll等炼鞠,完整的事件清單請查看官方文檔缘滥。
七. this.state
組件免不子要與用戶互動,React的一大創(chuàng)新谒主,就是將組件看成是一個狀態(tài)機(jī)朝扼,一開始有一個初始狀態(tài),然后用戶互動霎肯,導(dǎo)致狀態(tài)變化擎颖,從而觸發(fā)重新渲染UI榛斯,如下實(shí)例所示。
實(shí)例七:
<html >
<head>
<script src="es5-shim.min.js"></script>
<script src="es5-sham.min.js"></script>
<script src="console-polyfill.js"></script>
<script type="text/javascript" src="react.min.js"></script>
<script type="text/javascript" src="JSXTransformer.js"></script>
</head>
<body>
<div id="example" ></div>
<script type="text/jsx">
var LikeButton = React.createClass({
getInitialState: function() {
return {liked:false};
},
handleClick: function(event) {
this.setState({liked:!this.state.liked});
},
render: function() {
var text = this.state.liked?'like':'haven\'t liked';
return (
<p onClick={this.handleClick}>
You {text} this.click to toggle.
</p>
);
}
});
React.render(
<LikeButton/>,
document.getElementById('example')
);
</script>
</body>
</html>
運(yùn)行效果:
點(diǎn)擊上面這行搂捧,將會變成如下內(nèi)容
再次點(diǎn)擊驮俗,會變回初始內(nèi)容,即點(diǎn)擊內(nèi)容會交替變換允跑。
上面代碼是一個LikeButton組件王凑,它的getInitialState方法用于定義初始狀態(tài),也就是一個對象聋丝,這個對象可以通過this.state屬性讀取索烹。當(dāng)用戶點(diǎn)擊組件,導(dǎo)致狀態(tài)變化潮针,this.setState方法就修改狀態(tài)值术荤,每次修改以后,自動調(diào)用this.render方法每篷,再次渲染組件瓣戚。
由于this.props和this.state都用于描述組件的特性,可能會產(chǎn)生混淆焦读。一個簡單的區(qū)分方法是子库,this.props表示那些一旦定義,就不再改變的特性矗晃,而this.state是會隨著用戶互動而產(chǎn)生變化的特性仑嗅。
八. 表單
用戶在表單填入的內(nèi)容,屬于用戶跟組件的互動张症,所以不能用this.props讀取仓技。如下實(shí)例所示。
實(shí)例八:
<html >
<head>
<script src="es5-shim.min.js"></script>
<script src="es5-sham.min.js"></script>
<script src="console-polyfill.js"></script>
<script type="text/javascript" src="react.min.js"></script>
<script type="text/javascript" src="JSXTransformer.js"></script>
</head>
<body>
<script type="text/jsx">
var Input = React.createClass({
getInitialState: function() {
return {value:'Hello!'};
},
handleChange: function(event) {
this.setState({value:event.target.value});
},
render: function() {
var value=this.state.value;
return (
<div>
<input type="text" value={value} onChange={this.handleChange}/>
<p>{value}</p>
</div>
);
}
});
React.render(
<Input/>,
document.body
);
</script>
</body>
</html>
運(yùn)行效果:
上面代碼中俗他,文本輸入框的值脖捻,不能用this.props.value讀取,而要定義一個onChange事件的回調(diào)函數(shù)兆衅,通過event.target.value讀取用戶輸入的值地沮。textarea元素、select元素羡亩、radio元素都屬于這種情況摩疑,更多介紹請參考官方文檔。
九. 組件的生命周期
組件的生命周期分成三個狀態(tài):
Mounting:已插入真實(shí)DOM
Updating:正在被重新渲染
Unmounting:已移出真實(shí)DOM
React為每個狀態(tài)都提供了兩種處理函數(shù)畏铆,will函數(shù)在進(jìn)入狀態(tài)之前調(diào)用雷袋,did函數(shù)在進(jìn)入狀態(tài)之后調(diào)用,三種狀態(tài)共計(jì)五種處理函數(shù)辞居。
componentWillMount()
componentDidMount()
componentWillUpdate(object nextProps, object nextState)
componentDidUpdate(object prevProps, object prevState)
componentWillUnmount()
此外片排,React還提供兩種特殊狀態(tài)的處理函數(shù)寨腔。
componentWillReceiveProps(object nextProps):已加載組件收到新的參數(shù)時調(diào)用
shouldComponentUpdate(object nextProps, object nextState):組件判斷是否重新渲染時調(diào)用
這些方法的詳細(xì)說明,可以參考官方文檔率寡。
實(shí)例九:
<html >
<head>
<script src="es5-shim.min.js"></script>
<script src="es5-sham.min.js"></script>
<script src="console-polyfill.js"></script>
<script type="text/javascript" src="react.min.js"></script>
<script type="text/javascript" src="JSXTransformer.js"></script>
</head>
<body>
<script type="text/jsx">
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>
);
}
});
React.render(
<Hello name="world"/>,
document.body
);
</script>
</body>
</html>
運(yùn)行效果:
上面代碼在hello組件加載以后,通過componentDidMount方法設(shè)置一個定時器倚搬,每隔100毫秒冶共,就重新設(shè)置組件的透明度,從而引發(fā)重新渲染每界。
另外捅僵,組件的style屬性的設(shè)置方式也值得注意,不能寫成
style="opacity:{this.state.opacity};"
而要寫成
style={{opacity:this.state.opacity}}
這是因?yàn)镽eact組件樣式是一個對象眨层,所以第一重大括號表示這是JavaScript語法庙楚,第二重大括號表示樣式對象。
十. Ajax
組件的數(shù)據(jù)來源趴樱,通常是通過Ajax請求從服務(wù)器獲取馒闷,可以使用componentDidMount方法重新渲染UI。
實(shí)例十:
<html >
<head>
<script src="es5-shim.min.js"></script>
<script src="es5-sham.min.js"></script>
<script src="console-polyfill.js"></script>
<script type="text/javascript" src="react.min.js"></script>
<script type="text/javascript" src="JSXTransformer.js"></script>
<script type="text/javascript" src="jquery-1.8.3.js"></script>
</head>
<body>
<script type="text/jsx">
var UserGist = React.createClass({
getInitialState: function() {
return {
username:'',
lastGistUrl:''
};
},
componentDidMount: function() {
$.get(this.props.source, function(result) {
var lastGist = result[0];
if(this.isMounted()) {
this.setState({
username:lastGist.owner.login,
lastGistUrl:lastGist.html_url
});
}
}.bind(this));
},
render: function() {
return (
<div>
{this.state.username}'s last gist is
<a href={this.state.lastGistUrl}>here</a>.
</div>
);
}
});
React.render(
<UserGist source="https://api.github.com/users/octocat/gists"/>,
document.body
);
</script>
</body>
</html>
上面代碼使用jQuery完成Ajax請求叁征,這是為了便于說明纳账。React沒有任何依賴,完全可以使用其他庫捺疼。