每個的地方,每一種的知識,每一種事物,都是從陌生到熟悉。在這個過程裏面,或許能開闊眼界,增加見識,體驗樂趣。一切都歸於咱們的心態與行動。
學習之路不可中止,最近在玩 React。也動手嘗試寫了一個實例。藉此整理總結下初步學習 React 的一些基礎知識。由於這幾天比較忙,沒那麼多時間,因此實例和文章沒有很細緻。若是你們發現文章有錯誤的地方,請多諒解。有什麼更新的建議,歡迎在評論區指出。該文章主要是大概講下和快速上手使用,若是深刻,要靠本身探索,後期我也會補充文章。javascript
1.這裏使用 React 版本是 16.42.若是你們看的有點蒙圈,可能要去 React 上面看下 React 的基礎。css
3.代碼已經上傳到 Github 上面,須要的能夠去進行下載,歡迎 star react-demos。html
4.建議你們看該文章的時候也打開編輯器,邊寫邊看,思路會清晰不少java
學習React以前,必定要對下面兩個知識點有所瞭解。若是不瞭解下面的知識,請前往下面對應的連接,進行學習。react
學習 React 實例以前,必定要對JSX有必定的瞭解。JSX 能夠說是一個語法糖,React 使用來替代常規的 JavaScript。看起來很像 XML 的 JavaScript 語法擴展。git
JSX 不是必須的,以下兩段代碼,是徹底等價的,可是使用JSX會更加的清晰,簡潔,易懂。
JSXgithub
let el=<div className="author">守候</div> ReactDOM.render( el, document.getElementById('example') );
HTML數組
let el=React.createElement('div',{className:'suthor'},'守候') ReactDOM.render( el, document.getElementById('example') );
關於 JSX 語法的更多內容,你們請看 React JSX 。這裏不作過多的介紹。微信
組件是 React 最重要的一個概念。好比下面的代碼,就能夠說是一個組件。編輯器
class Author extends React.Component{ render(){ return ( <div className="author">守候</div> ) } }
固然也可使用函數組件的方式定義。
function Author(props) { return <div className='author'>守候</div>; }
把組件掛在到頁面的 id 爲 example 的一個 Dom 元素上面。
ReactDOM.render( <Author />, document.getElementById('example') );
上面這裏,就是一個組件,這個組件只有一個元素。組件也能夠由多個元素組成
class Author extends React.Component{ render(){ return ( <div className="author"> <span class="author-name">守候</span> <span class="author-gener">男</span> </div> ) } }
參考連接:React 組件。
這個例子的運行效果以下,是一個很是簡單的實例。下面經過這個實例,接觸下 React 的一些基礎知識和使用方式。
渲染其實上面例子就已經有了,就是利用 render 函數返回一個組件。以後利用 ReactDOM.render 進行掛載到頁面上的特定 Dom 元素裏面。
class EquipmentList extends React.Component{ render(){ return ( <div> <a href="javascript:;">殲擊機</a> <a href="javascript:;">轟炸機</a> <a href="javascript:;">運輸機</a> <ul> <li>殲20</li> <li>轟6K</li> <li>運20</li> </ul> </div> ) } } //掛載到頁面裏 id 爲 example 的元素上面 ReactDOM.render( <EquipmentList />, document.getElementById('example') );
上面是最基本的一個頁面佈局,可是頁面是靜態的,不是根據數據渲染的。下面認識下狀態和循環,以數據驅動渲染。
首先來講下狀態
引用菜鳥教程的說法:React 把組件當作是一個狀態機(State Machines)。經過與用戶的交互,實現不一樣狀態,而後渲染 UI,讓用戶界面和數據保持一致。React 裏,只需更新組件的 state,而後根據新的 state 從新渲染用戶界面(不要操做 DOM)。
咱們把上面的代碼,稍微改下,給組件加上狀態。
class EquipmentList extends React.Component{ constructor(){ super(); this.state={ post1:'殲20', post2:'轟6K', post3:'運20', } } render(){ return ( <div> <a href="javascript:;">殲擊機</a> <a href="javascript:;">轟炸機</a> <a href="javascript:;">運輸機</a> <ul> <li>{this.state.post1}</li> <li>{this.state.post2}</li> <li>{this.state.post3}</li> </ul> </div> ) } } ReactDOM.render( <EquipmentList />, document.getElementById('example') );
這裏有3個知識點須要知道1.super(); 這個必定要調用,這裏至關於調用了 React.Component 的 constructor。目的就是初始化 React 組件。
2.this.state 就是組件的狀態
3.render 方法裏面,輸入的是 state (也能夠是 props)。輸出的就是組件。
頁面效果徹底同樣,至於狀態的修改等,下面再實例再說起。
可是這樣寫代碼顯然是不優雅的,若是數據一多,工做量就很大,就應該使用循環進行渲染。下面把代碼改下。
class EquipmentList extends React.Component{ constructor(){ super(); this.state={ equipmentList:[ { id:1, title:'殲20' }, { id:2, title:'轟6K' }, { id:3, title:'運20' } ], } } render(){ return ( <div> <a href="javascript:;">殲擊機</a> <a href="javascript:;">轟炸機</a> <a href="javascript:;">運輸機</a> <ul> {this.state.equipmentList.map(item=><li key={item.id}>{item.title}</li>)} </ul> </div> ) } } ReactDOM.render( <EquipmentList />, document.getElementById('example') );
可能你們會有疑問,爲何li要帶上 key 這個屬性。是由於 React 是使用 key 屬性來標誌列表中的全部元素,當列表數據發生變化時,React 經過 key 能夠更快的知道哪些元素髮生了變化,從而只從新渲染髮生變化的元素,提升效率和性能。在列表裏面 key 須要惟一,通常是使用 id 做爲 key 值,不建議使用 index 做爲 key 值。由於若是列表發生了刪除,插入等操做,列表要重排。index 值會改變,可能會影響渲染的效率和性能。
接下來就給組件添加時間,點擊 a 元素的時候,好比點擊‘殲擊機’,就應該顯示 equipmentList 裏面 title 等於‘殲20’的數據,點擊‘轟炸機’,就應該顯示 equipmentList 裏面 title 等於‘轟6K’的數據......
實現這個需求,其實很簡單,就是新建一個狀態 equipmentListNow ,組件裏面只遍歷 equipmentListNow。點擊‘殲擊機’,就把 equipmentList 裏面 title ‘殲20’的數據賦值給postListNow,點擊‘轟炸機’,就把 equipmentList 裏面 title 等於‘轟6K’的數據賦值給postListNow......。
下面簡單實現一下
class EquipmentList extends React.Component{ constructor(){ super(); this.state={ equipmentList:[ { id:1, title:'殲20' }, { id:2, title:'轟6K' }, { id:3, title:'運20' } ], equipmentListNow:[] } } switchTab(id){ let _list=this.state.equipmentList.filter(item=>item.id===id); this.setState({ equipmentListNow:_list }) } render(){ return ( <div> <a href="javascript:;" onClick={()=>{ this.switchTab(1); }}>殲擊機</a> <a href="javascript:;" onClick={()=>{ this.switchTab(2); }}>轟炸機</a> <a href="javascript:;" onClick={()=>{ this.switchTab(3); }}>運輸機</a> <ul> {this.state.equipmentListNow.map(item=><li key={item.id}>{item.title}</li>)} </ul> </div> ) } } ReactDOM.render( <EquipmentList />, document.getElementById('example') );
若是要修改 state ,只能使用如: this.setState({equipmentListNow:_list}) 改變。切記不能出現以下寫法:this.equipmentListNow=_list;
跑起來了,沒報錯,可是頁面上一開始列表沒有被渲染出來,要點擊的時候纔有特定的數據出來(點擊第一章的a,出現第一章的數據,以此類推)。緣由想必你們也知道,由於在頁面初始化的時候,equipmentListNow 只是一個空數組,因此正確的作法是在頁面初始化的時候,就把 equipmentList 的值賦給 equipmentListNow。頁面初始化賦值,就是下面組件生命週期的內容了。
爲了讓頁面加載後,equipmentListNow 能有初始化的內容,那麼須要在生命週期函數裏面把 equipmentList 的值賦給 equipmentListNow。
至於生命週期,這裏不展開講,你們能夠看下文檔:React 組件生命週期。
你們應該知道,這個初始化賦值操做,應該在渲染前就完成。若是在渲染後再操做,那麼就至關於頁面渲染了第二次。因此咱們如今用到的生命週期函數是 componentWillMount 。
class EquipmentList extends React.Component{ constructor(){ super(); this.state={ equipmentList:[ { id:1, title:'殲擊機' }, { id:2, title:'轟炸機' }, { id:3, title:'運輸機' } ], equipmentListNow:[] } } switchTab(id){ let _list=this.state.equipmentList.filter(item=>item.id===id); this.setState({ equipmentListNow:_list }) } componentDidMount(){ let _list=this.state.equipmentList; this.setState({ equipmentListNow:_list }) } render(){ return ( <div> <a href="javascript:;" onClick={()=>{ this.switchTab(1); }}>殲擊機</a> <a href="javascript:;" onClick={()=>{ this.switchTab(2); }}>轟炸機</a> <a href="javascript:;" onClick={()=>{ this.switchTab(3); }}>運輸機</a> <ul> {this.state.equipmentListNow.map(item=><li key={item.id}>{item.title}</li>)} </ul> </div> ) } } ReactDOM.render( <EquipmentList />, document.getElementById('example') );
這樣一來,equipmentListNow 在頁面渲染前就初始化有值了,頁面也正常了。
上面的組件,一行 CSS 都沒寫,看着就特別難看。下面就添加些樣式。
方式1:最簡單的方式就是,就是給組件起 class 。在外部寫上 CSS 樣式。
CSS 代碼
body{ font-family: "微軟雅黑"; } ul{ margin: 0; padding: 0; } .post-box{ width: 600px; margin: 30px auto; } .post-box a{ display: inline-block; font-size: 14px; margin-right: 10px; width: 80px; height: 30px; line-height: 30px; text-align: center; background: #09f; color: #fff; text-decoration: none; } .post-box li{ list-style-type: none; line-height: 40px; padding-left: 10px; border-bottom: 1px solid #ccc; }
JS 代碼
在 js class 是關鍵字,因此要給元素設置 class 屬性,須要用 className
render() { return ( {/*給div增長class*/} <div className="post-box"> ... </div> ) }
方式2:因爲 React 的機制,因此不少時候會使用 css-in-js 這種方式,設置元素的樣式,簡單來講就是設置元素的內聯樣式。
render() { return ( <div className="post-box"> {/*給a設置內聯樣式*/} <a href="javascript:;" onClick={() => { this.switchTab(1); }} style={{background:'#f90'}}>殲擊機</a> <a href="javascript:;" onClick={() => { this.switchTab(2); }} style={{background:'#f00'}}>轟炸機</a> <a href="javascript:;" onClick={() => { this.switchTab(3); }} style={{background:'#0f0'}}>運輸機</a> <ul> {this.state.equipmentListNow.map(item => <li key={item.id}>{item.title}</li>)} </ul> </div> ) }
css-in-js 的另外一種寫法是:聲明樣式變量
let _style={ background:'#09f', color:'#f3f201' }
render() { return ( <div className="post-box"> {/*給a設置內聯樣式*/} <a href="javascript:;" onClick={() => { this.switchTab(1); }} style={_style}>殲擊機</a> <a href="javascript:;" onClick={() => { this.switchTab(2); }} style={_style}>轟炸機</a> <a href="javascript:;" onClick={() => { this.switchTab(3); }} style={_style}>運輸機</a> <ul> {this.state.equipmentListNow.map(item => <li key={item.id}>{item.title}</li>)} </ul> </div> ) }
你們能夠看到,上面的組件,是有一個狀態 state 的。但你們看了文章開始的例子就知道,並非全部的組件都是須要 state 的。根據有無 state 。能夠把組件區分爲有狀態組件和無狀態組件。把有狀態組件和無狀態組件合理利用,分工合做,能夠說是用好 React 的第一步,下面簡單分析下。
不難發現,上面 EquipmentList 組件複用性不強。想要複用,必須把代碼拷貝過去,而後再修改 equipmentList 這個狀態。
你們應該知道 EquipmentList 要想複用,裏面的數組不能寫死,只能由外部傳入,EquipmentList 經過 props 獲取數據。
既然說到了 props 就順便提下,props 的做用就是把父組件的值傳給子組件。props 是一個對象。以下
下面引用 2-2 的一個例子。 ReactDOM.render( <Author name='守候' gender='男'/>, document.getElementById('example') );
那麼 Author 裏面收到的 props 就是
props={ name:'守候', gender:'男' }
使用方式也很簡單
class Author extends React.Component{ render(){ return ( <div className="author"> <span class="author-name">{this.props.name}</span> <span class="author-gender">{this.props.gender}</span> </div> ) } }
引用 菜鳥教程說法:state 和 props 主要的區別在於 props 是不可變的,而 state 能夠根據與用戶交互來改變。這就是爲何有些容器組件須要定義 state 來更新和修改數據。 而子組件只能經過 props 來傳遞數據。
說了這麼多,下面修改下,把 EquipmentList 封裝成一個能複用的組件。
class EquipmentList extends React.Component { constructor(props) { super(props); this.state = { //根據props獲取數據 equipmentList: this.props.list, equipmentListNow: [] } } switchTab(id) { let _list = this.state.equipmentList.filter(item => item.id === id); this.setState({ equipmentListNow: _list }) } componentDidMount() { let _list = this.state.equipmentList; this.setState({ equipmentListNow: _list }) } render() { return ( <div className='post-box'> <a href="javascript:;" onClick={() => { this.switchTab(1); }}>殲擊機</a> <a href="javascript:;" onClick={() => { this.switchTab(2); }}>轟炸機</a> <a href="javascript:;" onClick={() => { this.switchTab(3); }}>運輸機</a> <ul> {this.state.equipmentListNow.map(item => <li key={item.id}>{item.title}</li>)} </ul> </div> ) } }
這裏有一個要注意的點 在 constructor 裏面,我寫的是 super(props) 不是以前那樣的 super() 。這樣的寫的緣由就是爲了在 constructor 裏面可使用 this.props。以下代碼
constructor(props) { super(props); this.state = { //根據props獲取數據 equipmentList: this.props.list, equipmentListNow: [] } }
如不須要用 this.props 。能夠直接寫 super(),固然寫 super(props) 也沒錯。
constructor(props) { super(); this.state = { //根據props獲取數據 equipmentList: props.list, equipmentListNow: [] } }
說了這麼多,下面看下怎麼使用。
使用方式1,這裏只作一個說明,這樣子寫實際是沒什麼意思的。
let equipmentList = [ { id: 1, title: '殲20' }, { id: 2, title: '轟6K' }, { id: 3, title: '運20' } ] ReactDOM.render( <EquipmentList list={equipmentList}/>, document.getElementById('example') );
使用方式2
class Example2 extends React.Component { constructor(props) { super(props); this.state = { equipmentList: [ { id: 1, title: '殲20-量產型號' }, { id: 2, title: '轟6K-量產型號' }, { id: 3, title: '運20-量產型號' } ], } } componentDidMount() { let _list = this.state.equipmentList; //兩秒後更新數據 setTimeout(() => { _list.forEach((item,index)=>{ item.title='其實這是一艘航空母艦'+index; }); this.setState({ equipmentList: _list }) }, 2000) } render(){ return ( <EquipmentList list={this.state.equipmentList}></EquipmentList> ) } } ReactDOM.render(<Example2/>, document.getElementById('example2') );
這樣一來,EquipmentList 變成了無狀態組件,Example2 變成了有狀態組件。分工方面,EquipmentList 不操做數據的變化,只管數據的渲染;Example2 不關注如何渲染,只控制數據變化,每次變化,使用 setState 更新數據,EquipmentList 的渲染結果就會改變。
看到這可能你們也有感悟了,通常而言,一個頁面上絕大部分應該是無狀態組件,少部分是有狀態組件。
最後提一點,可能你們也有會疑問,若是 props 不少都是重複的值,可不能夠設置一個默認值,就能夠少傳些參數。答案是能夠的,好比下面代碼,掛載的時候 EquipmentList 沒有傳值,可是能渲染出來,由於使用了 defaultProps 設置 props 的默認值。
class EquipmentList extends React.Component { constructor(props) { super(props); this.state = { //根據props獲取數據 equipmentList: this.props.list, equipmentListNow: [] } } switchTab(id) { let _list = this.state.equipmentList.filter(item => item.id === id); this.setState({ equipmentListNow: _list }) } componentDidMount() { let _list = this.state.equipmentList; this.setState({ equipmentListNow: _list }) } render() { return ( <div> <a href="javascript:;" onClick={() => { this.switchTab(1); }}>殲擊機</a> <a href="javascript:;" onClick={() => { this.switchTab(2); }}>轟炸機</a> <a href="javascript:;" onClick={() => { this.switchTab(3); }}>運輸機</a> <ul> {this.state.equipmentListNow.map(item => <li key={item.id}>{item.title}</li>)} </ul> </div> ) } } //設置 props 默認值 EquipmentList.defaultProps={ list:[ { id: 1, title: '殲20' }, { id: 2, title: '轟6K' }, { id: 3, title: '運20' } ] } ReactDOM.render(<EquipmentList/>, document.getElementById('example') );
好了,這幾天對 React 學習的一些總結,就暫時告一段落了。該文章只是針對 React 實現一個很是簡單的實例,也很基礎。若是要深刻,就要你們各自去努力了,在日後深刻學習裏面,我也會繼續寫文章,分享。但願和你們有更多的交流,若是你們對文章有什麼見解和建議,歡迎指點。
-------------------------華麗的分割線--------------------
想了解更多,和我交流,內推職位,請添加我微信。或者關注個人微信公衆號:守候書閣