iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 11
4
Modern Web

一步一腳印的React旅程系列 第 11

[筆記][React]使用React開發的思考模式(2)-組件的構成模式

Hi!恭喜踏入第11篇!完成1/3的賽程了!這樣子一直倒數心態是不是不太好XD,不過我還是很沈醉在給自己壓力的,哈哈哈,但是結束後還是讓我耍廢一陣子吧!欸?現在講這個好像太早XD,哈哈哈,那在結束前讓大家多陪我一下吧!

今天要說的是React的組件構成模式,哈哈,就把標題再說一次。


這篇應該比較算是小技巧,主要會繞在props上,相信經過前10天再扣掉webpack的2天,共8天的考驗,現在各位應該對props不陌生了,一開始知道他可以傳入值,昨天又知道他連function都可以傳入,那除此之外呢?讓我們接著看下去!

首先假設我們有一個簡單的組件,裡面有個簡單的div,而為了讓他看起來明顯,在設定他的背景顏色為灰色:

class MessageBlock extends React.Component {
    constructor(props){
        super(props)
        this.state = ({style:{backgroundColor:'#DDDDDD',height:200,width:'100%'}})
    }
    render(){
        return <div style={this.state.style}></div>
    }
}

ReactDOM.render(<MessageBlock  />, document.getElementById('root'))

結果如下:
https://ithelp.ithome.com.tw/upload/images/20181003/20106935oyxu2itvrD.png

感覺根本沒有展示的必要XD

那接下來我們建立另一個組件Message,如下:

class Message extends React.Component{
    constructor(props){
        super(props)
        this.state = ({style:{backgroundColor:'#FFFFFF',height:100,width:'80%'}})
    }
    render(){
        return <div style={this.state.style}>
                    {this.props.children}
               </div>
    }
}

這個組件寫好後先暫停一下,我們把視線留在{this.props.children}上面,乍看之下沒什麼奇怪,不就設定一個props,然後透過children傳入值嗎?有什麼奇怪的?欸嘿嘿!繼續跟著我一探究竟吧!

下方把Message組件寫進MessageBlock中:

class Message extends React.Component{
    constructor(props){
        super(props)
        this.state = ({style:{backgroundColor:'#FFFFFF',height:100,width:'80%'}})
    }
    render(){
        return <div style={this.state.style}>
                    {this.props.children}
               </div>
    }
}

class MessageBlock extends React.Component {
    constructor(props){
        super(props)
        this.state = ({style:{backgroundColor:'#DDDDDD',height:200,width:'100%'}})
    }
    render(){
        return (
        <div style={this.state.style}>
            <Message>
                <p>組件標籤內的內容會被傳到該組件的props.children中</p>
            </Message>
        </div>)
    }
}

ReactDOM.render(<MessageBlock  />, document.getElementById('root'))

結果如下:
https://ithelp.ithome.com.tw/upload/images/20181003/20106935tzZAWn87p0.png

GitHub程式碼連結
GitPage頁面連結

登愣!有看出來什麼端倪嗎?上方在使用Message的時候並沒有使用children='XXX'將值或是任何東西傳進去,但是渲染出來的畫面居然會有內容!原因是因為props.children的值會預設傳入被該組件包夾的內容也就是JSX,所以我們可以透過它來補洞!

不過凡事都有但書,假如要補的洞有兩個該怎麼辦?像是把Message改成下方這樣:

class Message extends React.Component{
    constructor(props){
        super(props)
        this.state = ({style:{backgroundColor:'#FFFFFF',height:100,width:'80%'}})
    }
    render(){
        return (<div>
                    <div style={this.state.style}>
                        {this.props.userName}
                    </div>
                    <div style={this.state.style}>
                        {this.props.message}
                    </div>
                </div>)
    }
}

需要同時傳入userNamemessage該怎麼做?children只有一個啊!

別慌,那不就照正常的方式傳入就好了嗎:)

class MessageBlock extends React.Component {
    constructor(props){
        super(props)
        this.state = ({style:{backgroundColor:'#DDDDDD',height:200,width:'100%'}})
    }
    render(){
        return (
        <div style={this.state.style}>
            <Message userName="GQSM" message="Hello!大家好!" />
        </div>)
    }
}

結果會如下:
https://ithelp.ithome.com.tw/upload/images/20181003/20106935PY2uukUUzb.png

要傳入事件也可以,而且因為JSX是透過props傳入的,所以可以直接設定事件:

class MessageBlock extends React.Component {
    constructor(props){
        super(props)
        this.state = ({style:{backgroundColor:'#DDDDDD',height:200,width:'100%'}})
        this.writeMessageConsole = this.writeMessageConsole.bind(this)
    }
    //宣告事件
    writeMessageConsole(event){
        console.log(event.target.innerText)
    }

    render(){
        return (
        <div style={this.state.style}>
            <Message>
                {/*不需要使用this.props.writeMessageConsole,
                可直接使用this.writeMessageConsole依然會執行*/}
                <p onClick={this.writeMessageConsole}>組件標籤內的內容會被傳到該組件的props.children中</p>
            </Message>
        </div>)
    }
}

結果會如下:
https://ithelp.ithome.com.tw/upload/images/20181003/20106935kE9ZY5CUu2.png

GitHub程式碼連結
GitPage頁面連結

也可以直接傳入組件哦!讓我們再新增一個組件MessageContent

class Message extends React.Component{
    constructor(props){
        super(props)
        this.state = ({style:{backgroundColor:'#FFFFFF',height:100,width:'80%'}})
    }
    render(){
        return <div style={this.state.style}>
                    {this.props.children}
               </div>
    }
}

class MessageContent extends React.Component {
    render(){
        return <p>組件標籤內的內容會被傳到該組件的props.children中</p>
    }
}

接著改寫MessageBlock組件的內容,在Message組件中放入MessageContent

class MessageBlock extends React.Component {
    constructor(props){
        super(props)
        this.state = ({style:{backgroundColor:'#DDDDDD',height:200,width:'100%'}})
    }

    render(){
        return (
        <div style={this.state.style}>
            <Message>
                <MessageContent />
            </Message>
        </div>)
    }
}

如此一來,Message中的this.props.children也會接收到MessageContent回傳的組件內容哦!
https://ithelp.ithome.com.tw/upload/images/20181003/201069350V5wzCslHo.png

GitHub程式碼連結
GitPage頁面連結

最後的貼心小題醒,如果在組件中同時傳入children,傳進去的資料會以被組件包括的內容為主:

class Message extends React.Component{
    constructor(props){
        super(props)
        this.state = ({style:{backgroundColor:'#FFFFFF',height:100,width:'80%'}})
    }
    render(){
        return <div style={this.state.style}>
                    {this.props.children}
               </div>
    }
}

class MessageBlock extends React.Component {
    constructor(props){
        super(props)
        this.state = ({style:{backgroundColor:'#DDDDDD',height:200,width:'100%'}})
    }

    render(){
        return (
        <div style={this.state.style}>
            <Message children="從props傳進內容">
                <p>props.children的內容會以這裡為主</p>
            </Message>
        </div>)
    }
}

ReactDOM.render(<MessageBlock  />, document.getElementById('root'))

結果會如下:
https://ithelp.ithome.com.tw/upload/images/20181003/20106935tt2lq3ZEUQ.png


react中的props真的很方便,連組件都可以透過props傳入子組件中,所以react特別注重在組件的組合和結構,而不是用繼承來擴充組件原本的樣子,聽說用react所寫的facebook中連一個關於組件繼承的例子都沒有!所以把組件的使用方式學起來,就在畫面上得天下了!

最後感謝各位大大的觀看,如果上方有任何不清楚或錯誤的地方,還請大大們留言告訴我,我會再盡快修正和補充文章內容的!謝謝大家/images/emoticon/emoticon41.gif

參考文章:

  1. https://reactjs.org/docs/composition-vs-inheritance.html

上一篇
[筆記][React]使用React開發的思考模式(1)-記得把共同狀態提升
下一篇
[筆記][React]使用React開發的思考模式(3)-最後來個小範例吧!
系列文
一步一腳印的React旅程30

尚未有邦友留言

立即登入留言