React從入門到精通系列之(4)組件化和Props傳遞

4、組件化和屬性(props)

組件容許您將UI拆分爲獨立的可重用的部分,並單獨地考慮每一個部分。
從概念上講,組件就像JavaScript函數。 它們接受任意輸入(稱爲「props」),並返回應該出如今屏幕上的React元素。javascript

功能性組件(functional)和類組件(class component)

定義組件的最簡單的方法是編寫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')
);

讓咱們回顧一下在這個例子中發生了什麼:

  1. 首先調用ReactDOM.render()方法,並處理<Welcome name =「zhangyatao」/>組件。

  2. React使用{name:'zhangyatao'}做爲props調用Welcome組件。

  3. 咱們的Welcome組件返回一個<h1> Hello,zhangyatao </ h1>元素做爲結果。

  4. 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是隻讀的

不管是將組件聲明爲功能組件仍是類組件,它都不能修改本身的props。 考慮這個計算參數總和的函數:

function sum(a, b) {
    return a + b;
}

這樣的函數被稱爲「純函數」,由於它們不會改變它們的參數值,而且對於相同的輸入老是返回相同的結果。
相反,這個函數是不純的,由於它改變本身的參數:

function withdraw(account, amount) {
    account.total -= amount;
}

React很是靈活,但它有一個嚴格的規則:
全部React組件必須像它們的porps的純函數那樣運行。

固然,應用中的UI大部分是動態的,隨時間變化。 在下一節中,咱們將介紹一個「state」的新概念。 狀態容許React組件響應用戶操做,網絡響應和其餘任何內容,隨時間更改其輸出,而不違反此規則。

相關文章
相關標籤/搜索