標(biāo)簽:前端開發(fā) ReactJS
官網(wǎng)
官網(wǎng)中文鏡像(推薦)
阮一峰老師的教程
菜鳥網(wǎng)的教程
一看就懂的ReactJS入門教程(語法有點(diǎn)過期了)
關(guān)鍵庫:
react.js; react-dom.js; browser.min.js;
前言: ReactJS產(chǎn)生的原因背景
在Web開發(fā)中,我們總需要將變化的數(shù)據(jù)實(shí)時反應(yīng)到UI上玫锋,這時就需要對DOM進(jìn)行操作。而復(fù)雜或頻繁的DOM操作通常是性能瓶頸產(chǎn)生的原因(如何進(jìn)行高性能的復(fù)雜DOM操作通常是衡量一個前端開發(fā)人員技能的重要指標(biāo))庵楷。React為此引入了虛擬DOM(Virtual DOM)的機(jī)制:在瀏覽器端用Javascript實(shí)現(xiàn)了一套DOM API冯乘。基于React進(jìn)行開發(fā)時所有的DOM構(gòu)造都是通過虛擬DOM進(jìn)行内斯,每當(dāng)數(shù)據(jù)變化時栋猖,React都會重新構(gòu)建整個DOM樹净薛,然后React將當(dāng)前整個DOM樹和上一次的DOM樹進(jìn)行對比,得到DOM結(jié)構(gòu)的區(qū)別蒲拉,然后僅僅將需要變化的部分進(jìn)行實(shí)際的瀏覽器DOM更新肃拜。而且React能夠批處理虛擬DOM的刷新痴腌,在一個事件循環(huán)(Event Loop)內(nèi)的兩次數(shù)據(jù)變化會被合并,例如你連續(xù)的先將節(jié)點(diǎn)內(nèi)容從A變成B燃领,然后又從B變成A士聪,React會認(rèn)為UI不發(fā)生任何變化,而如果通過手動控制猛蔽,這種邏輯通常是極其復(fù)雜的剥悟。盡管每一次都需要構(gòu)造完整的虛擬DOM樹,但是因?yàn)樘摂MDOM是內(nèi)存數(shù)據(jù)曼库,性能是極高的区岗,而對實(shí)際DOM進(jìn)行操作的僅僅是Diff部分,因而能達(dá)到提高性能的目的毁枯。這樣慈缔,在保證性能的同時,開發(fā)者將不再需要關(guān)注某個數(shù)據(jù)的變化如何更新到一個或多個具體的DOM元素种玛,而只需要關(guān)心在任意一個數(shù)據(jù)狀態(tài)下藐鹤,整個界面是如何Render的。
如果你像在90年代那樣寫過服務(wù)器端Render的純Web頁面那么應(yīng)該知道赂韵,服務(wù)器端所要做的就是根據(jù)數(shù)據(jù)Render出HTML送到瀏覽器端娱节。如果這時因?yàn)橛脩舻囊粋€點(diǎn)擊需要改變某個狀態(tài)文字,那么也是通過刷新整個頁面來完成的祭示。服務(wù)器端并不需要知道是哪一小段HTML發(fā)生了變化肄满,而只需要根據(jù)數(shù)據(jù)刷新整個頁面。換句話說绍移,任何UI的變化都是通過整體刷新來完成的悄窃。而React將這種開發(fā)模式以高性能的方式帶到了前端讥电,每做一點(diǎn)界面的更新蹂窖,你都可以認(rèn)為刷新了整個頁面。至于如何進(jìn)行局部更新以保證性能恩敌,則是React框架要完成的事情瞬测。
1.代碼生成標(biāo)簽,插入到指定位置
jsx/babel語言 JS,HTML混寫
<body>
<div id="example"></div>
<script type="text/babel">
ReactDOM.render(
<h2>Hello,world</h2>,
document.getElementById('example')
);
</script>
</body>
div#example 作為容器存放生成的元素纠炮,
生成元素:ReactDOM.render(<tag>{codehere}</tag>, container);
注意:語句結(jié)尾可以不加分號月趟,不會出錯,有些語句加了分號之后就會出錯恢口,因此加分號要小心孝宗。
2.自定義標(biāo)簽(組件)
<script type="text/babel">
var MyTag = React.createClass({
render:function(){ return<h1>{this.props.name}</h1> }
}); //this.props.xxx 調(diào)用自定義屬性;
ReactDOM.render(<MyTag name="zhe" />, document.getElementById('example') );
</script>
自定義標(biāo)簽要一定要用在render中,直接用在html無效耕肩。
后面demo為了方便就不寫ReactDOM.render()了因妇,實(shí)際練習(xí)時要加上
注意類名一定要首字母大寫问潭,createClass參數(shù)是一個對象,
添加組件屬性婚被,有一個地方需要注意狡忙,對于要調(diào)用class屬性與for屬性,屬性名不能直接寫 class 或者for址芯,這是因?yàn)?class 和 for 是 JavaScript 的保留字灾茁。用className="" htmlFor=""
代替,這樣css一樣可以.class
找到該元素
3.可嵌套子元素的自定義標(biāo)簽
<script type="text/babel">
var MyList = React.createClass({
render:function(){
return(
<ul>{ React.Children.map(this.props.children,
function(child){return<li>{child}</li>} ) }</ul>
)} //注意大小寫谷炸,props.children 用于獲取子元素
});
// 使用
// <MyList>
// <span>item1</span>
// <span>item2</span>
//</MyList>
</script>
一種映射的方法:array.map(function(item){console.log(item)})
遍歷array每次輸出一個item北专。
另外如果數(shù)組是一系列標(biāo)簽,可以寫在容器標(biāo)簽內(nèi)自動展開,如<div>{array}</div>
旬陡。
React.Children.map
該方法遍歷children逗余,而不用理會children因size不同(0,1,1+)而返回的不同類型(undefine,object, array)
4. 組件的參數(shù)檢查與默認(rèn)值
<script type="text/babel">
var MyTag = React.createClass({
getDefaultProps: function(){ return {title:"hello"} }, //默認(rèn)值
propTypes: {title: React.PropTypes.string.isRequired }, //表示title是必須,并且是字符串
render: function(){ return<h1>{this.props.title}</h1>}
});
//<MyTag title={123} /> 控制臺報錯季惩,但一樣會顯示在頁面
</script>
5. 獲取組件內(nèi)部標(biāo)簽的DOM節(jié)點(diǎn)
內(nèi)部標(biāo)簽定義一個ref屬性录粱,組件使用this.refs.xxx內(nèi)獲取節(jié)點(diǎn)
var MyInput = React.createClass({
clickEvent:function(){ this.refs.tagInside.focus() }, //clickEvent的名字可隨意
render:function(){ return(
<div>
<input type="text" ref="tagInside"/>
<input type="button" value="focus" onClick={this.clickEvent} />
</div> )
}
});
6. 組件的狀態(tài)this.state
標(biāo)記組件的狀態(tài),用于改變顯示的文字画拾,樣式等啥繁。
var MyInput = React.createClass({
getInitialState: function(){ return { liked: false } },//定義應(yīng)有的狀態(tài)與初始化,用鍵值對形式
clickEvent:function() { this.setState({liked: !this.state.liked }) },//this.setState({}) 改變狀態(tài)值
render:function() {
var text =this.state.liked ? "liked" : "unliked";
return<input type="button" value={text} onClick={this.clickEvent} />
}
});
每次setState后都會自動調(diào)用render,因此可以改變樣式青抛。
注意this.state與this.props的區(qū)別旗闽,state可以在交互中改變,可讀可寫蜜另,props定義了了就不能改變适室,只讀。
7. 獲取表單的輸入
輸入表單屬于交互举瑰,改變this.state
var MyInput = React.createClass({
getInitialState: function() { return {value: "default"} },
changeEvent:function(e) { this.setState({value: e.target.value}) },
render:functiion(){ return(
<div>
<input type="text" value={text} onChange={this.changeEvent} />
<p> {text}</p>
</div> )
} //注意大小寫
});
因?yàn)槊看胃淖儬顟B(tài)都會調(diào)用render,因此如果input里的value設(shè)為常數(shù)捣辆,那么輸入文本就不會顯示改變
8. 組件的生命周期
分為 mounting: 已插入到真實(shí)的DOM中;
updating:被渲染中此迅;
unmounting 已經(jīng)移出真實(shí)的DOM
有兩種回調(diào)函數(shù):will 在進(jìn)入某一步前調(diào)用汽畴,did進(jìn)入某一步后調(diào)用,共5個
componentWillMount();
componentDidMount();
componentWillUpdate(oNextProps, oNextState);
componentDidUpdate(oPrevProps, oPrevState);
componentWillUnmount();
這個比較復(fù)雜耸序,還是看官網(wǎng)比較好:https://facebook.github.io/react/docs/working-with-the-browser.html#component-lifecycle
9. AJAX
componentDidMount 中可以用jQuery.get() 實(shí)現(xiàn)忍些,React 本身沒有任何依賴,完全可以不用jQuery坎怪,而使用其他庫罢坝。
<script type="text/babel">
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>
);
}
});
ReactDOM.render(
<UserGist source="https://api.github.com/users/octocat/gists" />,
document.body
);
</script>
10. 傳入promise對象
<script type="text/babel">
var RepoList = React.createClass({
getInitialState: function() {return {loading:true, data:null, error:null}},
componentDidMount: function() {
this.props.promise.then(
value => this.setState({loading:false, data:value}),
error => this.setState({loading:false, error:error})
)
},
render: function(){
if (this.state.loading) {
return <span>loading...</span>
} else if (this.state.error) {
return <span>Error: {this.state.error.message} </span>
} else {
var repos = this.state.data.items;
var list = repos.map(function(repo){
return (
<li>
<a href={repo.html_url}> {repo.name} </a>
({repo.stargazers_count} stars) <br/>
{repo.description}
</li> )
})
}
return (<div>
<h1>Most Popular JavaScript Projects in Github</h1>
<ol>{list}</ol>
</div>)
}
})
ReactDOM.render(
<RepoList promise={$.getJSON('https://api.github.com/search/repositories?q=javascript&sort=stars')} />,
document.getElementById("example")
)
</script>
總結(jié)
上面是react的簡單用法,更多更詳細(xì)的解釋請看官方文檔搅窿。
react還可以配合flux框架使用嘁酿,接下來可以學(xué)習(xí)這方面的相關(guān)知識疾棵。