組件容許您將UI拆分爲獨立的可重用的部分,並單獨地考慮每一個部分。
從概念上講,組件就像JavaScript函數。 它們接受任意輸入(稱爲「props」),並返回應該出如今屏幕上的React元素。javascript
定義組件的最簡單的方法是編寫JavaScript函數:java
function Welcome(props) { return <h1>hello, {props.name}</h1> }
此函數是個有效的React組件,由於它接收一個帶有數據的「props」對象做爲參數,並返回一個React元素。 咱們把這樣的組件稱爲「功能性組件(functional)」,由於它們是個JavaScript函數。react
您還可使用ES6類來定義組件:網絡
class Welcome extends React.Component { render() { return <h1>hello, {this.props.name}</h1>; } }
上述兩個組件從React的角度來看是等效的。dom
類組件有一些額外的功能,咱們將在下面的章節中討論。 在那以前,咱們將簡單地使用功能組件。函數
之前,咱們只遇到使用DOM標籤的React元素:組件化
const element = <div />;
可是,元素也能夠表示用戶自定義的組件:網站
const element = <Welcome name="zhangyatao" />;
當React看到表示用戶定義組件的元素時,它將該JSX標籤的因此屬性放到一個對象中傳遞給組件。 咱們稱這個對象爲「props」。this
例如,此代碼在頁面上呈現「Hello,zhangyatao」:code
function Welcome(props) { return <h1>Hello, {props.name}</h1>; } const element = <Welcome name="zhangyatao" />; ReactDOM.render( element, document.getElementById('root') );
讓咱們回顧一下在這個例子中發生了什麼:
首先調用ReactDOM.render()
方法,並處理<Welcome name =「zhangyatao」/>
組件。
React使用{name:'zhangyatao'}
做爲props調用Welcome
組件。
咱們的Welcome
組件返回一個<h1> Hello,zhangyatao </ h1>
元素做爲結果。
React DOM有效地根據<h1> Hello,zhangyatao </ h1>
來更新DOM。
警告
組件名稱始終使用·首字母大寫·。
例如,<div />
表示一個DOM標籤,但<Welcome />
表示一個組件,並要求Welcome
必須和ReactDOM在一個做用域內。
組件能夠在其返回值中引用去其餘組件。 這容許咱們對任何級別的細節使用相同的組件抽象。 一個按鈕,一個表單,一個對話框,一個屏幕:在React應用程序中,全部這些一般表示爲組件。
例如,咱們能夠建立一個App組件,讓它渲染多個Welcome
組件:
function Welcome(props) { return <h1>Hello, {props.name}</h1>; } function App() { return ( <div> <Welcome name="zhangyatao" /> <Welcome name="jiangyanyun" /> <Welcome name="pangyun" /> </div> ); } ReactDOM.render( <App />, document.getElementById('root') );
這個新的React應用程序在頂部有一個單獨的App
組件。
可是,若是您將React集成到現有應用程序中,則可使用Button這樣的小組件自下而上開始逐步向上到達視圖層次結構的頂部。
警告
引用多個組件時必須包裹在一個根元素中返回。 這就是爲何咱們添加了一個<div>
來包含全部<Welcome />
元素。
永遠不要懼怕將組件拆分紅更小的組件。
例如,考慮這個Comment
組件:
import React from 'react'; import ReactDOM from 'react-dom'; function formatDate(date) { return date.toISOString(); } function Comment(props) { return ( <div className="Comment"> <div className="UserInfo"> <img className="avatar" src={props.author.avatarUrl} alt={props.author.name} /> <div className="UserInfo-name"> {props.author.name} </div> </div> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); } ReactDOM.render( <Comment author={{ avatarUrl: 'https://ss0.bdstatic.com/7Ls0a8Sm1A5BphGlnYG/sys/portrait/item/3ae1dc06.jpg', name: 'zhangyatao' }} text={'個人名字叫張亞濤'} date={new Date()}/>, document.getElementById('root') );
它接受author
(做者),text
(內容)和date
(日期)做爲props,用來描述社交媒體網站上的評論。
這個組件可能很難改變,由於全部的嵌套,它也很難重用其中的單個部分。 讓咱們從中提取幾個組件。
首先,咱們將提取avatar
:
function Avatar(props) { return ( <img className="Avatar" src={props.user.avatarUrl} alt={props.user.name} /> ); }
avatar
不須要知道它正在Comment
中呈現。 這就是爲何咱們給它的prop一個更通用的名稱:user
而不是author
。
咱們建議從組件本身的角度來命名props,而不是使用它的上下文。
咱們如今能夠對Comment
組件作一點點簡化:
function Comment(props) { return ( <div className="Comment"> <div className="UserInfo"> <Avatar user={props.author} /> <div className="UserInfo-name"> {props.author.name} </div> </div> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); }
接下來,咱們將提取一個UserInfo
組件,該組件在用戶名稱旁邊呈現一個avatar
:
function UserInfo(props) { return ( <div className="UserInfo"> <avatar uer={props.user} /> <div className="UserInfo-name"> {props.user.name} </div> </div> ); }
這使咱們能夠進一步簡化Comment
組件:
function Comment(props) { return ( <div className="Comment"> <UserInfo user={props.author} /> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); }
最終的代碼以下:
import React from 'react'; import ReactDOM from 'react-dom'; function formatDate(date) { return date.toISOString(); } function Avatar(props) { return ( <img className="Avatar" src={props.user.avatarUrl} alt={props.user.name} /> ); } function UserInfo(props) { return ( <div className="UserInfo"> <Avatar user={props.user}/> <div className="UserInfo-name"> {props.user.name} </div> </div> ); } function Comment(props) { return ( <div className="Comment"> <UserInfo user={props.author}/> <div className="Comment-text"> {props.text} </div> <div className="Comment-date"> {formatDate(props.date)} </div> </div> ); } ReactDOM.render( <Comment author={{ avatarUrl: 'https://ss0.bdstatic.com/7Ls0a8Sm1A5BphGlnYG/sys/portrait/item/3ae1dc06.jpg', name: 'zhangyatao' }} text={'個人名字叫張亞濤'} date={new Date()}/>, document.getElementById('root') );
讓一個個可重用組件在大型應用程序中交付使用的過程當中,抽離組件起初可能看起來像又髒又累的活兒。 因此有一個好的經驗法則:若是UI的一部分被使用了好幾回(按鈕,面板,頭像),或者內部比較複雜的東西(App,FeedStory,評論),一個可重用的組件對它來講能夠達到最大的發揮空間。
不管是將組件聲明爲功能組件仍是類組件,它都不能修改本身的props。 考慮這個計算參數總和的函數:
function sum(a, b) { return a + b; }
這樣的函數被稱爲「純函數」
,由於它們不會改變它們的參數值,而且對於相同的輸入老是返回相同的結果。
相反,這個函數是不純的,由於它改變本身的參數:
function withdraw(account, amount) { account.total -= amount; }
React很是靈活,但它有一個嚴格的規則:
全部React組件必須像它們的porps的純函數那樣運行。
固然,應用中的UI大部分是動態的,隨時間變化。 在下一節中,咱們將介紹一個「state」的新概念。 狀態容許React組件響應用戶操做,網絡響應和其餘任何內容,隨時間更改其輸出,而不違反此規則。