React精髓!一篇全概括(急速)

張不慫發表於2019-05-13
React精髓!一篇全概括(急速)
一個人並不是生來要給打敗的,你儘可以把他消滅掉,可就是打不敗他。     
React精髓!一篇全概括(急速)

學和使用react有一年多了,最近想在梳理一下react基礎知識,夯實基礎,激流勇進~ 關於reacr-router,redux,redux-saga後續都會慢慢輸出,希望各位看官老爺持續關注~~要是能給個贊鼓勵一下就更了~

提醒一下: 看完之後抓緊時間趁熱打鐵,redux,react-redux,redux-saga

一篇文章總結redux、react-redux、redux-saga

react基礎知識速覽

1、什麼是JSX?

一個JSX語法的示例,如下所示

const element = <h1>Hello, world!</h1>;
複製程式碼

這種語法形式,既不是HTML,也不是字串,而是稱之為JSX,是React裡用來描述UI和樣式的語法,JSX最終會被編譯為合法的JS語句呼叫(編譯器在遇到{時採用JS語法進行解析,遇到<就採用HTML規則進行解析)

2、嵌入表示式

JSX中,可以使用花括號{}嵌入任意的JavaScript合法表示式,如:2 + 2user.firstNameformatName(user)都是合法的。示例如:

const user = {
    firstName: 'Zhang',
    lastName : 'Busong'
};

const elem = (
    <h1>Hello, {formatName(user)}</h1>
);
/*
這裡的(),實際上是可選的,但是React推薦加入(),這樣子就會被視為一個表示式,而不會導致
自動插入分號的問題
*/

ReactDOM.render(
    element,
    document.getElementById('app')
)
複製程式碼

3、JSX也是一種表示式

JSX本身也是一種表示式,所以它可以像其他表示式一樣,用於給一個變數賦值、作為函式實參、作為函式返回值,等等。如:

function getGreeting(user) {
    if (user) {
        return <h1>Hello, {formatName(user)}</h1>
    }
    return <h1>Hello, Guest!</h1>;
}
複製程式碼

注意: 1、在JSX中,宣告屬性時不要使用引號,如果宣告屬性的時候使用引號,那麼將被作為字串解析,而不會被作為一個表示式解析,如:

<div firstName="{user.firstName}" lastName={user.lastName}></div>
複製程式碼

解析後,可以得到:

<div firstName="{user.firstName}" lastName="Lau"></div>
複製程式碼

因此,當我們需要使用一個字串字面量的時候,可以使用引號,但是如果要作為表示式解析的時候,則不應當使用引號 2、在JSX中,有些屬性名稱需要進行特殊處理。如class應該用className代替,tabindex則用tabIndex代替。這是因為JSX本質上更接近於JavaScript,而class是JavaScript中的保留字。同時,應該使用camelCase來命名一個屬性,而不是使用HTML的屬性命名方式 3、JSX本身已經做了防注入處理,對於那些不是明確編寫的HTML程式碼,是不會被解析為HTML DOM的,ReactDOM會將他們一律視為字串,在渲染完成前就轉化為字串,所以可以防止XSS攻擊 4、如果JSX標籤是閉合的,那麼結尾需要用/>,另外,JSX標籤是可以互相巢狀的,這和HTML裡是一樣的

4、JSX實質

JSX通過babel編譯,而babel實際上把JSX編譯給React.createElement()呼叫。如下JSX程式碼:

const element = (
    <h1 className="greeting">
        Hello, world!
    </h1>
);
複製程式碼

是等同於以下的語句的:

const elem = React.createElement(
    'h1',
    {className: 'greeting'},
    'Hello, world!'
);
複製程式碼

React.createElement()方法會首先進行一些避免BUG的檢查,然後返回類似以下例子的物件:

const element = {
    type: 'h1',
    props: {
        className: 'greeting',
        children: 'Hello, world'
    }
}
複製程式碼

這樣的物件,則稱為React元素,代表所有呈現在螢幕上的東西。React正是通過讀取這些物件來構建DOM,並且保持資料和UI同步的

5、元素渲染

元素(elements)是構成React應用的最小單元,元素描述了想要在螢幕中看到的內容,如:

const element = <h1>Hello, world</h1>;
複製程式碼

和DOM元素不同的是,React元素是純物件,建立的代價低。並且React會進行優化處理,只把有必要的變化更新到DOM上。此外,元素和元件的概念,是不一樣的,元件是由元素組成的。

6、將元素渲染進DOM

在React中,使用ReactDOM.render()方法來將React元素渲染進一個DOM中。如:

ReactDOM.render(
    element,
    document.getElementById('root')
)
複製程式碼

React元素是不可變的,所以一旦一個元素建立完成後,我們是無法改變其內容或者屬性的。一個元素就像是動畫裡的一幀,它代表UI在某一時間點的樣子。如果非要使用元素來構成可變化的UI介面,就需要使用setInterval了,如:

function tick() {
    const element = (
        <div>Now is {new Date().toLocaleTimeString()}</div>
    );
    ReactDOM.render(
        element,
        document.getElementById('root')
    );
}
setInterval(tick, 1000);
複製程式碼

在實際開發中,大多數React應用只會呼叫一次ReactDOM.render(),所以更好的方式是使用有狀態元件

7、元件和Props

元件(component)能夠將UI劃分為獨立的、可複用的部分,這樣我們就只需專注於構建每一個單獨的部件。 從概念上看,元件就像是函式:接受任意的輸入(稱為屬性,Props),返回React元素。React中有兩種定義元件的方式:函式定義類定義

1、函式定義元件

這種方式是最簡單的定義元件的方式,就像寫一個JS函式一樣,如:

function Welcome (props) {
    return <h1>Hello, {props.name}</h1>;;
}
複製程式碼

2、類定義元件

還可以使用ES6裡的類來定義一個元件,如下所示:

class Welcome extends React.Component {
    render () {
        return <h1>Hello, {this.props.name}<h1>;
    }
}
複製程式碼

這種方式比起函式定義方式則更加靈活

3、元件渲染

先前,我們遇到的React元素只是呈現一個DOM標籤,如:

const element = <div />
複製程式碼

然而,React元素也可以是使用者自定義的元件,如:

const element = <Welcome name="Tom" />
複製程式碼

Welcome元件中宣告瞭一個屬性name="Tom",而這個屬性,將以props.name的方式傳遞給元件,如下方式:

function Welcome (props) {
    return <h1>Hello, {props.name}</h1>;
}
複製程式碼

此時,對於以下的程式碼:

ReactDOM.render(
    <Welcome name="張不慫" />,
    document.getElementById('root')
)
複製程式碼

最終就會以<h1>Hello, 張不慫</h1>的方式呈現。在這個過程中,發生瞭如下的事情:

  • <Welcome name="張不慫" />元素呼叫了ReactDOM.render()豐富
  • React將{ name: '張不慫' }作為props實參來呼叫Welcome元件
  • Welcome完成渲染,返回<h1>Hello, 張不慫</h1>元素
  • ReactDOM計算最小更新代價,然後更新DOM

4、組合元件

元件是可以組合的。即元件內部可以引用其他元件,如:

function Welcome (props) {
    return <h1>Hello, {props.name}</h1>;
}

function App () {
    return (
        <div>
            <Welcome name="Tom" />
            <Welcome name="Jack" />
            <Welcome name="Mike" />
        </div>
    )
}

ReactDOM.render(
    <App />,
    document.getElementById('root')
)
複製程式碼

注意: 在React中,元件必須返回單一的根元素,這也是為什麼App元件中需要用<div>標籤包裹的原因。如以下的方式,是錯誤的(因為它有3個根元素):

function App () {
    return (
        <Welcome name="Tom" />
        <Welcome name="Jack" />
        <Welcome name="Mike" />
    )
}
複製程式碼

5、屬性是隻讀的

考慮以下這種情況:

function sum (a, b) {
    return a + b;
}
複製程式碼

這種函式稱為純函式:它不改變自己的輸入值,且總是對相同的輸入返回相同的結果。 與之對立的,則是非純函式,如:

function withdraw (account, amount) {
    account.total -= amount;
}
複製程式碼

非純函式在函式內改變了輸入的引數。在React中,無論是通過function還是class宣告元件,我們都不應該修改它自身的屬性(props)。雖然React相當靈活,但是它也有一個嚴格的規定:所有的React元件都必須像純函式那樣來使用它們的props

8、State與生命週期

使用類定義元件有一些額外的好處,如擁有本地狀態這一特性。 以下是一個類定義元件

class Clock extends React.Component {
    render () {
        return (
            <div>
                <h1>Hello, world!</h1>
                <h2>Now is {this.props.date.toLocaleTimeString()}</h2>
            </div>
        );
    }
}
複製程式碼

需要注意的有:

  • 類名即為元件名(無論是函式定義元件還是類定義元件,元件名稱的首字母都必須大寫,並且繼承自React.Component
  • 使用 render() 方法,用來返回需要呈現的內容

1、在類中加入state

state是屬於一個元件自身的。我們可以在類的建構函式constructor中來初始化狀態,如:

constructor (props) {
    super(props)
    this.state = {
        date: new Date()
    }
}
複製程式碼

如此一來,我們就可以在render()函式中使用this.state.xxx來引用一個狀態

2、生命週期

在應用裡,往往都會有許許多多的元件。在元件銷燬後,回收和釋放它們所佔據的資源非常重要。 在時鐘應用的例子裡,我們需要在第一次渲染到DOM的時候設定一個定時器,並且需要在相應的DOM銷燬後,清除這個定時器。那麼,這種情況下,React為我們提供了生命週期的鉤子函式,方便我們進行使用。在React中,生命週期分為: 1)Mount 已插入真實DOM 2)Update 正在重新渲染 3)Unmount 已移出真實DOM 而相應的,生命週期鉤子函式有:

  • componentWillMount
  • componentDidMount
  • componentWillUpdate(newProps, nextState)
  • componentDidUpdate(prevProps, prevState)
  • componentWillUnmount()

此外,還有兩種特殊狀態的處理函式:

  • componentWillReceiveProps(nextProps) 已載入的元件收到新的引數時調動
  • shouldComponentUpdate(nextProps, nextState) 元件判斷是否重新渲染時呼叫

因此,基於生命週期鉤子函式,我們可以實現一個時鐘應用如下:

class Clock extends React.Component {
    constructor (props) {
        super(props);
        this.state = {
            date: new Date()
        }
    }
    tick () {
        this.setState({
            date: new Date()
        });
    }
    componentDidMount () {
        this.timerId = setInterval(() => {
            this.tick()
        }, 1000);
    }
    componentWillUnmount () {
        clearInterval(this.timerId);
    }
    render () {
        return (
            <div>Now is {this.state.date.toLocaleTimeString()}</div>
        );
    }
}
複製程式碼

需要注意的是: 1)render()裡用不到的state,不應該宣告在state裡 2)不能直接使用this.state.xxx = xxx的方式來改變一個state的值,應該使用this.setState()。如:

setName () {
    this.setState({
        name: '張不慫'
    })
}
複製程式碼

this.setState()會自動覆蓋this.state裡相應的屬性,並觸發render()重新渲染。 3)狀態更新可能是非同步的 React可以將多個setState()呼叫合併成一個呼叫來提升效能。且由於this.propsthis.state可能是非同步更新的,所以不應該依靠它們的值來計算下一個狀態。這種情況下,可以給setState傳入一個函式,如:

this.setState((prevState, props) => ({
    counter: prevState.counter + props.increment
}));
複製程式碼

9、事件處理

React元素的事件與DOM元素類似,不過也有一些區別,如: 1)React事件使用camelCase命名(onClick),而不是全小寫的形式(onclick) 2)使用JSX,傳入的是事件的控制程式碼,而不是一個字串 如以下的HTML:

<button onclick="increment()">ADD</button>
複製程式碼

使用React的方式描述如:

<button onClick={increment}>ADD</button>
複製程式碼

還有一個不同在於,在原生DOM中,我們可以通過返回false來阻止預設行為,但是這在React中是行不通的,在React中需要明確使用preventDefault()來阻止預設行為。如:

function ActionLink () {
    function handleClick (e) {
        e.preventDefault();
        alert('Hello, world!');
    }

    return (
        <a href="#" onClick={handleClick}>Click Me</a>
    );
}
複製程式碼

這裡,事件回撥函式裡的event是經過React特殊處理過的(遵循W3C標準),所以我們可以放心地使用它,而不用擔心跨瀏覽器的相容性問題。 注意: 在使用事件回撥函式的時候,我們需要特別注意this的指向問題,因為在React裡,除了建構函式和生命週期鉤子函式裡會自動繫結this為當前元件外,其他的都不會自動繫結this的指向為當前元件,因此需要我們自己注意好this的繫結問題, 通常而言,在一個類方式宣告的元件裡使用事件回撥,我們需要在元件的constructor裡繫結回撥方法的this指向,如:

class Counter extends React.Component {
    constructor (props) {
        super(props);
        this.state = {
            counter: 0
        }
        // 在這裡繫結指向
        this.increment = this.increment.bind(this);
    }
    increment () {
        this.setState({
            counter: this.state.counter + 1
        });
    }
    render () {
        return (
            <div>
                The counter now is: {this.state.counter}
                <button onClick={this.increment}>+1</button>
            </div>
        );
    }
}
複製程式碼

當然,我們還有另外一種方法來使用箭頭函式繫結指向,就是使用實驗性的屬性初始化語法,如:

class Counter extends React.Component {
    increment: () => {
        this.setState({
            counter: this.state.counter + 1
        });
    }
    // ...
}

複製程式碼

3)像事件處理程式傳遞引數 我們可以為事件處理程式傳遞額外的引數,方式有以下兩種:

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

複製程式碼

需要注意的是,使用箭頭函式的情況下,引數e要顯式傳遞,而使用bind的情況下,則無需顯式傳遞(引數e會作為最後一個引數傳遞給事件處理程式)

10、條件渲染

在React裡,我們可以建立不同的元件來封裝我們需要的功能。我們也可以根據元件的狀態,只渲染元件中的一部分內容,而條件渲染就是為此而準備的。在React中,我們可以像在JavaScript中寫條件語句一樣地寫條件渲染語句,如:

function Greet(props) {
    const isLogined = props.isLogined;
    if (isLogined) {
        return <div>Hello !</div>;
    }
    return <div>Please sign in</div>;
}

ReactDOM.render(
    <Greet isLogined={true} />,
    document.getElementById('root')
);

複製程式碼

這將渲染出:

<div>Hello !</div>

複製程式碼

1、使用變數來儲存元素

我們也可以使用變數來儲存元素,如:

function LogBtn(props) {
    var button;
    const isLogined = props.isLogined;
    if (isLogined) {
        button = <button>退出</button>
    } else {
        button = <button>登陸</button>
    }
    return <div>You can {button}</div>;
}

ReactDOM.render(
    <LogBtn isLogined={false} />,
    document.getElementById('root')
);

複製程式碼

2、使用&&運算子進行渲染

由於JavaScript語法對待&&運算子的性質,我們也可以使用&&運算子來完成條件渲染,如:

function LogBtn(props) {
    var button;
    const isLogined = props.isLogined;
    return (
        <div>Hello
        {!isLogined && (
            <button>請登陸</button>
        )}
        </div>
    )
}

複製程式碼

props.isLogined為false的時候,就會渲染出:

<div>Hello <button>請登入</button></div>

複製程式碼

3、使用三目運算子進行渲染

我們可能已經發現了,其實JSX可以像一個表示式那樣子靈活使用,所以,我們自然也可以使用三目運算子進行渲染,如:

function LogBtn (props) {
    const isLogined = props.isLogined;
    return (
        <div>You can 
            <button>{isLogined ? '退出' : '登陸'}</button>
        </div>
    )
}

複製程式碼

4、阻止整個元件的渲染

有時候,我們希望是整個元件都不渲染,而不僅僅是區域性不渲染,那麼這種情況下,我們就可以在render()函式裡返回一個null,來實現我們想要的效果,如:

function LogBtn (props) {
    const isLogined = props.isLogined;
    const isShow = props.isShow;
    if (isShow) {
        return (
            <div>You can 
                <button>{isLogined ? '退出' : '登陸'}</button>
            </div>
        )
    }
    return null;
}

複製程式碼

注意: 元件裡返回null不會影響元件生命週期的觸發,如componentWillUpdatecomponentDidUpdate仍然會被呼叫

11、列表渲染與keys

在JavaScript中,我們可以使用map()函式來對一個陣列列表進行操作,如:

const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(number => number*2);
console.log(doubled); // 得到[2, 4, 6, 8, 10]

複製程式碼

同樣的,在React裡,我們也可以使用map()來進行列表渲染,如:

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map(number => {
    return (
        <li>{number}</li>
    )
});

ReactDOM.render(
    <ul>{listItems}</ul>,
    document.getElementById('root')
)

複製程式碼

這將得到:

<ul><li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
</ul>

複製程式碼

當然,我們還可以進行更好的封裝,如:

function NumberList (props) {
    const numbers = props.numbers;
    const listItems = numbers.map(number => {
        return (
            <li>{number}</li>
        )
    });

    return <ul>{listItems}</ul>
}

複製程式碼

當我們執行以上的程式碼的時候,會發現控制檯提示:Each child in an array or iterator should have a unique "key" prop,因此,我們需要為列表項的每一個項分配一個key,來解決這個問題,通常而言,我們可以使用以下幾種方式來提供key

  • 使用資料項自身的ID,如<li key={item.itemId}>
  • 使用索引下標(index),如:
const listItems = numbers.map((number, index) => {
    <li key={index}>{number}</li>
});

複製程式碼

但是React不推薦在需要重新排序的列表裡使用索引下標,因為會導致變得很慢。

注意: 只有在一個項的同胞裡區分彼此的時候,才需要使用到key,key不需要全域性唯一,只需要在一個陣列內部區分彼此時唯一便可。key的作用是給React一個提示,而不會傳遞給元件。如果我們在元件內需要同樣的一個值,可以換個名字傳遞,如:

const content = posts.map(post => (
    <Post key={post.id} id={post.id} title={post.title} />
));

複製程式碼

12、表單

表單和其他的React中的DOM元素有所不同,因為表單元素生來就是為了儲存一些內部狀態。在React中,表單和HTML中的表單略有不同

1、受控元件

HTML中,<input><textarea><select>這類表單元素會維持自身狀態,並根據使用者輸入進行更新。不過React中,可變的狀態通常儲存在元件的this.state中,且只能用setState()方法進行更新,如:

class NameForm extends React.Component {
    constructor (props) {
        super(props);
        this.state = {
            value: ''
        }
        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }
    handleChange (event) {
        this.setState({
            value: event.target.value
        });
    }
    handleSubmit (event) {
        alert('Your name is '+this.state.value);
        event.preventDefault();
    } 
    render () {
        return (
            <form onSubmit={this.handleSubmit}>
            Name: <input type="text" value={this.state.value} onChange={this.handleChange} />
            <input type="submit" value="Submit" />
            </form>
        )
    }
}

複製程式碼

和HTML中不同的是,React中的textarea並不需要寫成<textarea></textarea>的形式,而是寫成<textarea value="" ... />的形式便可。而對於HTML中的select標籤,通常做法是:

<select>
    <option value="A">A</option>
    <option value="B" selected>B</option>
    <option value="C">C</option>
</select>

複製程式碼

但是React中,不需要在需要選中的option處加入selected,而只需要傳入一個value,就會自動根據value來選中相應的選項,如:

<select value="C">
    <option value="A">A</option>
    <option value="B">B</option>
    <option value="C">C</option>
</select>

複製程式碼

那麼如上述例子,C所在的這個option就會被選中

2、多個輸入的解決辦法

通常一個表單都有多個輸入,如果我們為每一個輸入新增處理事件,那麼將會非常繁瑣。好的一個解決辦法是,使用name,然後根據event.target.name來選擇做什麼。如:

class Form extends React.Component {
    constructor (props) {
        super(props);
        this.state = {
            name: '',
            gender: '男',
            attend: false,
            profile: ''
        };
        this.handleInputChange = this.handleInputChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }
    handleInputChange (event) {
        const target = event.target;
        const value = target.type==='checkbox' ? target.checked : target.value;
        const name = target.name;
        this.setState({
            [name]: value
        });
    }
    handleSubmit (event) {
        this.setState({
            profile: `姓名:${this.state.name}${this.state.gender}${this.state.attend ? '參加' : '不參加'}活動`
        });
        event.preventDefault();
    } 
    render () {
        return (
            <form>
            <p>姓名:<input name="name" value={this.state.name} onChange={this.handleInputChange} /></p>
            <p>性別:
                <select name="gender" value={this.state.gender} onChange={this.handleInputChange}>
                    <option value="男">男</option>
                    <option value="女">女</option>
                </select>
            </p>
            <p>是否參加:<input name="attend" type="checkbox" onChange={this.handleInputChange} checked={this.state.attend} /></p>
            <input type="submit" value="Submit" onClick={this.handleSubmit} />
            <p>您的報名資訊:{this.state.profile}</p>
            </form>
        )
    }
}

複製程式碼

3、非受控元件

大多數情況下,使用受控元件實現表單是首選,在受控元件中,表單資料是交由React元件處理的。如果想要讓表單資料由DOM處理(即資料不儲存在React的狀態裡,而是儲存在DOM中),那麼可以使用非受控元件,使用非受控元件,可以無需為每個狀態更新編寫事件處理程式,使用ref即可實現,如:

class NameForm extends React.Component {
    constrcutor(props) {
        super(props)
    }
    handleSubmit(event) {
        console.log('A name was submitted: ', this.input.value)
        event.preventDefault()
    }
    render() {
        return (
            <form onSubmit={this.handleSubmit}>
                <label>
                Name: <input type="text" ref={input => this.input = input} />
                </label>
                <input type="submit" value="submit" />
            </form>
        )
    }
}

複製程式碼

對於非受控元件,如果要指定預設值,那麼可以使用defaultValue,如:

<input type="text" defaultValue="Hello" ref={input => this.input = input} />

複製程式碼

相應的,type="checkbox"type="radio",則使用defaultChecked

13、狀態提升

當需要幾個元件共用狀態資料的時候,可以使用狀態提升技術。核心思想在於:把資料抽離到最近的共同父元件,父元件管理狀態(state),然後通過屬性(props)傳遞給子元件。如實現一個貨幣轉換的元件,可以如下:

1、首先定義轉換函式

function USD2RMB (amount) {
    return amount * 6.7925;
}

function RMB2USD (amount) {
    return amount * 0.1472;
}

function convert (amount, typeFn) {
    return typeFn(amount);
}

複製程式碼

2、定義元件

我們希望在RMB的輸入表單上上輸入的時候,USD的輸入表單上的數值也同步更新,這種情況下,如果RMB元件自己管理自己的狀態,是很難以實現的,因此,我們需要讓這個狀態提升自父元件進行管理。如下:

class CurrencyInput extends React.Component {
    constructor (props) {
        super(props)
        this.handleChange = this.handleChange.bind(this)
    }
    handleChange (event) {
        this.props.onInputChange(event.target.value)
    }
    render () {
        const value = this.props.value
        const type = this.props.type
        return (
            <p>{type}: <input type="text" value={value} onChange={this.handleChange} /></p>
        );
    }
}

複製程式碼

最後定義一個共同的父元件,如下:

class CurrencyConvert extends Component {
    constructor (props) {
        super(props);
        this.state = {
            type: 'RMB',
            amount: 0
        }
        this.handleRMBChange = this.handleRMBChange.bind(this);
        this.handleUSDChange = this.handleUSDChange.bind(this);
    }
    handleRMBChange (amount) {
        this.setState({
            type: 'RMB',
            amount
        });
    }
    handleUSDChange (amount) {
        this.setState({
            type: 'USD',
            amount
        });
    }
    render () {
        const type = this.state.type;
        const amount = this.state.amount;
        const RMB = type==='RMB' ? amount : convert(amount, USB2RMB);
        const USD = type==='USD' ? amount : convert(amount, RMB2USB);
        return (
            <div>
                <p>Please Input:</p>
                <CurrencyInput type="RMB" value={RMB} onInputChange={this.handleRMBChange} />
                <CurrencyInput type="USD" value={USD} onInputChange={this.handleUSDChange} />
            </div>
        );
    }
}

複製程式碼

14、組合vs繼承

React推崇更多的是使用組合,而非使用繼承。對於一些使用場景,React給出的建議如下:

1、包含關係

當父元件不知道子元件可能的內容是什麼的時候,可以使用props.children,如:

function Article (props) {
    return (
        <section>
            <aside>側邊欄</aside>
            <article>{props.children}</article>
        </section>
    );
}

function App () {
    return (
        <Article>這是一篇文章</Article>
    );
}

複製程式碼

這將渲染得到:

<section>
    <aside>側邊欄</aside>
    <article>這是一篇文章</article>
</section>

複製程式碼

我們還可以自定義名稱,因為JSX實際上會被轉化為合法的JS表示式,所以,還可以有:

function Article (props) {
    return (
        <section>
            <aside>{props.aside}</aside>
            <article>{props.children}</article>
        </section>
    );
}

function App () {
    return (
        <Article aside={
            <h1>這是一個側欄</h1>
        }>這是一篇文章</Article>
    );
}

複製程式碼

這將渲染得到:

<section>
    <aside><h1>這是一個側欄</h1></aside>
    <article>這是一篇文章</article>
</section>

複製程式碼

2、何時使用繼承?

在Facebook的網站上,使用了數以千計的元件,但是實踐證明還沒有發現需要使用繼承才能解決的情況。 屬性和組合為我們提供了清晰的、安全的方式來自定義元件的樣式和行為,元件可以接受任意元素,包括:基本資料型別、React元素、函式。 如果要在元件之間複用UI無關的功能,那麼應該將其提取到單獨的JavaScript模組中,這樣子可以在不對元件進行擴充套件的前提下匯入並使用函式、物件、類

覺得對你有幫助,不妨點個

贊,

不妨再點個關注,不迷路,下一篇關於redux的明天就發!!~

相關文章