iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 4
0
Modern Web

寫React的那些事系列 第 4

React Day4 - Component 與 Props

  • 分享至 

  • xImage
  •  

今天要再往下介紹components,elements是由components組合產生的,而components可以有自己的狀態,依照狀態來render HTML。

Component


我們可以把component視為class,因為它可以用javascript的function來表達,也可以用ES6 class的方式建立。而component有兩種形式:

  • DOM tags
  • User-defined components

(1) DOM tags

  • DOM tags的components如果沒有children元素,一樣要遵守之前所說用 /> 結尾。
const ele = <div />

(2) User-defined components

  • User-defined components在定義的時候,因為是Class開頭必須是大寫。
const ele = <MyComponent wording="Hello" />

React.Component


React的components透過繼承React.Component來建立,使用ES6 class定義的方式如下:

class Profile extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

另外,也有提供一個進階的React.PureComponent可以繼承,基本上它和React.Component是一樣的,唯一的差別在於會加上 shouldComponentUpdate 的function,這個function是用來避免component在不必要的狀態下被update,後續應該有機會會再說明清楚,或是可以看官網API的說明

class Profile extends React.PureComponent {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

完整的render到DOM上


上面已經學會如何定義components,加上前一天提到的ReactDOM.render(),這邊用一個完整範例,把component組成一個element,再用React.render渲染出來。

// component
class Profile extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}
// element
const ele = <Profile name="Allen" />;

// render to <div id="main"></div>
ReactDOM.render(
  ele,
  document.getElementById('main')
);

Demo

Props


Props是由父元件傳入component的參數,這是在React裡面一個很重要的單向資料流觀念,所有的資訊都是由上層往下傳遞,所以絕對不要在component裡面直接改變props,「Props must be pure」,而React也提供設定props檢查型態與設定預設值的方法。

propTypes

Profile.propTypes = {
  name: React.PropTypes.string.isRequired,
  age: React.PropTypes.number.isRequired,
  receiveMsg: React.PropTypes.bool
};
  • propTypes可以先設定props的型別,並且在傳入的時候先驗證型態是否正確,不正確會報錯。
  • isRequired設定該props是否必須傳入,如果必傳卻沒有傳入則會報錯。
  • 除了有支援多種預設型別,型別或格式也可以客製化,填入一個驗證的function,官網有完整的介紹可以參考

defaultProps

Profile.defaultProps = {
  receiveMsg: false
}
  • defaultProps用來設定預設值,當props沒傳入,就會使用這邊設定的default值。
  • 當propTypes有設定isRequired時,就不需要預設值。

Composing Components


上面已經對components有完整的了解,這邊要再提到怎麼去拆解與組合components,這是React裡面另一個重要的部分。

以FB的留言版回覆為例,假設Layout架構如下:

├── Comment 留言第一篇
│   ├── Comment 留言第一篇的回覆第一篇
│   └── Comment 留言第一篇的回覆第二篇
└── Comment 留言第二篇

那Comment就會是一個基本component,裡面可能還會包含Avatar、CommentContext、ControlBtn等其他component,例如:

class Comment extends React.Component {
  render() {
    return (
      <div>
         <Avatar
           img={this.props.img}
           name={this.props.name}
         />
         <CommentContext comment={this.props.comment} />
         <ControlBtn />
      </div>
    );
  }
}

Comment.propTypes = {
  img: React.PropTypes.string,
  name: React.PropTypes.string.isRequired,
  comment: React.PropTypes.string.isRequired
};

Comment.defaultProps = {
  img: 'default.png'
}

而整個留言板可以重複使用Comment這個元件

const board = (
    <div>
        <div className="level1">
            <Comment
                img="./images/photo1.jpg"
                name="Allen"
                comment="I think this is good!"
            />
            <div className="level2">
                <Comment
                    img="./images/photo3.jpg"
                    name="Jacky"
                    comment="Amazing!"
                />
                <Comment
                    img="./images/photo4.jpg"
                    name="Allen"
                    comment="Wonderful!"
                />
            </div>
        </div>
        <div className="level1">
            <Comment
                img="./images/photo2.jpg"
                name="John"
                comment="Good~"
            />
        </div>
    </div>
);

Comment可以被重複使用(reusable),用div區隔出來第一層與第二層,而裡面的Avatar、CommentContext、ControlBtn也都可以共用,用複合拼裝的方式reuse元件,而每一個Comment component又是獨立運作的,可以render自己的內容,各自擁有不同的props data。

通常我們可以看著Layout來思考元件該怎麼切割,哪些元件可以依照功能被切出來,哪些元件可以重複共用,多切幾次就會越來越知道怎麼拆分元件。我覺得切元件的方式有點看個人習慣,大致的原則就是依照功能與思考重複使用的可能性,有時候切太細會覺得沒必要,有時候切乾淨會比較好reuse。

參考


React官網 Components and Props


上一篇
React Day3 - Virtual DOM與ReactDOM.render
下一篇
React Day5 - state 與 setState
系列文
寫React的那些事31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言