配置組件的 props

組件是相互獨立、可複用的單元,一個組件可能在不一樣地方被用到。可是在不一樣的場景下對這個組件的需求可能會根據狀況有所不一樣,例如一個點贊按鈕組件,在我這裏須要它顯示的文本是「點贊」和「取消」,當別的同事拿過去用的時候,卻須要它顯示「贊」和「已贊」。如何讓組件能適應不一樣場景下的需求,咱們就要讓組件具備必定的「可配置」性。html

React.js 的 props 就能夠幫助咱們達到這個效果。每一個組件均可以接受一個 props參數,它是一個對象,包含了全部你對這個組件的配置。就拿咱們點贊按鈕作例子:數組

下面的代碼可讓它達到上述的可配置性:函數

class LikeButton extends Component {
  constructor () {
    super()
    this.state = { isLiked: false }
  }

  handleClickOnLikeButton () {
    this.setState({
      isLiked: !this.state.isLiked
    })
  }

  render () {
    const likedText = this.props.likedText || '取消'
    const unlikedText = this.props.unlikedText || '點贊'
    return (
      <button onClick={this.handleClickOnLikeButton.bind(this)}>
        {this.state.isLiked ? likedText : unlikedText} 👍
      </button>
    )
  }
}

從 render 函數能夠看出來,組件內部是經過 this.props 的方式獲取到組件的參數的,若是 this.props 裏面有須要的屬性咱們就採用相應的屬性,沒有的話就用默認的屬性。this

那麼怎麼把 props 傳進去呢?在使用一個組件的時候,能夠把參數放在標籤的屬性當中,全部的屬性都會做爲 props 對象的鍵值:spa

class Index extends Component {
  render () {
    return (
      <div>
        <LikeButton likedText='已贊' unlikedText='贊' />
      </div>
    )
  }
}

就像你在用普通的 HTML 標籤的屬性同樣,能夠把參數放在表示組件的標籤上,組件內部就能夠經過 this.props 來訪問到這些配置參數了。code

前面的章節咱們說過,JSX 的表達式插入能夠在標籤屬性上使用。因此其實能夠把任何類型的數據做爲組件的參數,包括字符串、數字、對象、數組、甚至是函數等等。例如如今咱們把一個對象傳給點贊組件做爲參數:htm

class Index extends Component {
  render () {
    return (
      <div>
        <LikeButton wordings={{likedText: '已贊', unlikedText: '贊'}} />
      </div>
    )
  }
}

如今咱們把 likedText 和 unlikedText 這兩個參數封裝到一個叫 wordings 的對象參數內,而後傳入點贊組件中。你們看到 {{likedText: '已贊', unlikedText: '贊'}}這樣的代碼的時候,不要覺得是什麼新語法。以前討論過,JSX 的 {} 內能夠嵌入任何表達式,{{}} 就是在 {} 內部用對象字面量返回一個對象而已。對象

這時候,點贊按鈕的內部就要用 this.props.wordings 來獲取到到參數了:blog

class LikeButton extends Component {
  constructor () {
    super()
    this.state = { isLiked: false }
  }

  handleClickOnLikeButton () {
    this.setState({
      isLiked: !this.state.isLiked
    })
  }

  render () {
    const wordings = this.props.wordings || {
      likedText: '取消',
      unlikedText: '點贊'
    }
    return (
      <button onClick={this.handleClickOnLikeButton.bind(this)}>
        {this.state.isLiked ? wordings.likedText : wordings.unlikedText} 👍
      </button>
    )
  }
}

甚至能夠往組件內部傳入函數做爲參數:字符串

class Index extends Component {
  render () {
    return (
      <div>
        <LikeButton
          wordings={{likedText: '已贊', unlikedText: '贊'}}
          onClick={() => console.log('Click on like button!')}/>
      </div>
    )
  }
}

這樣能夠經過 this.props.onClick 獲取到這個傳進去的函數,修改 LikeButton 的 handleClickOnLikeButton 方法:

...
  handleClickOnLikeButton () {
    this.setState({
      isLiked: !this.state.isLiked
    })
    if (this.props.onClick) {
      this.props.onClick()
    }
  }
...

當每次點擊按鈕的時候,控制檯會顯示 Click on like button! 。但這個行爲不是點贊組件本身實現的,而是咱們傳進去的。因此,一個組件的行爲、顯示形態均可以用 props 來控制,就能夠達到很好的可配置性。

默認配置 defaultProps

上面的組件默認配置咱們是經過 || 操做符來實現。這種須要默認配置的狀況在 React.js 中很是常見,因此 React.js 也提供了一種方式 defaultProps,能夠方便的作到默認配置。

class LikeButton extends Component {
  static defaultProps = {
    likedText: '取消',
    unlikedText: '點贊'
  }

  constructor () {
    super()
    this.state = { isLiked: false }
  }

  handleClickOnLikeButton () {
    this.setState({
      isLiked: !this.state.isLiked
    })
  }

  render () {
    return (
      <button onClick={this.handleClickOnLikeButton.bind(this)}>
        {this.state.isLiked
          ? this.props.likedText
          : this.props.unlikedText} 👍
      </button>
    )
  }
}

注意,咱們給點贊組件加上了如下的代碼:

static defaultProps = {
    likedText: '取消',
    unlikedText: '點贊'
  }

defaultProps 做爲點贊按鈕組件的類屬性,裏面是對 props 中各個屬性的默認配置。這樣咱們就不須要判斷配置屬性是否傳進來了:若是沒有傳進來,會直接使用 defaultProps 中的默認屬性。 因此能夠看到,在 render 函數中,咱們會直接使用 this.props 而不須要再作判斷。

props 不可變

props 一旦傳入進來就不能改變。修改上面的例子中的 handleClickOnLikeButton :

...
  handleClickOnLikeButton () {
    this.props.likedText = '取消'
    this.setState({
      isLiked: !this.state.isLiked
    })
  }
...

咱們嘗試在用戶點擊按鈕的時候改變 this.props.likedText ,而後你會看到控制檯報錯了:

你不能改變一個組件被渲染的時候傳進來的 props。React.js 但願一個組件在輸入肯定的 props 的時候,可以輸出肯定的 UI 顯示形態。若是 props 渲染過程當中能夠被修改,那麼就會致使這個組件顯示形態和行爲變得不可預測,這樣會可能會給組件使用者帶來困惑。

但這並不意味着由 props 決定的顯示形態不能被修改。組件的使用者能夠主動地經過從新渲染的方式把新的 props 傳入組件當中,這樣這個組件中由 props 決定的顯示形態也會獲得相應的改變。

修改上面的例子的 Index 組件:

class Index extends Component {
  constructor () {
    super()
    this.state = {
      likedText: '已贊',
      unlikedText: '贊'
    }
  }

  handleClickOnChange () {
    this.setState({
      likedText: '取消',
      unlikedText: '點贊'
    })
  }

  render () {
    return (
      <div>
        <LikeButton
          likedText={this.state.likedText}
          unlikedText={this.state.unlikedText} />
        <div>
          <button onClick={this.handleClickOnChange.bind(this)}>
            修改 wordings
          </button>
        </div>
      </div>
    )
  }
}

在這裏,咱們把 Index 的 state 中的 likedText 和 unlikedText 傳給 LikeButton 。Index 還有另一個按鈕,點擊這個按鈕會經過 setState 修改 Index 的 state 中的兩個屬性。

因爲 setState 會致使 Index 從新渲染,因此 LikedButton 會接收到新的 props,而且從新渲染,因而它的顯示形態也會獲得更新。這就是經過從新渲染的方式來傳入新的 props 從而達到修改 LikedButton 顯示形態的效果。

總結

  1. 爲了使得組件的可定製性更強,在使用組件的時候,能夠在標籤上加屬性來傳入配置參數。
  2. 組件能夠在內部經過 this.props 獲取到配置參數,組件能夠根據 props 的不一樣來肯定本身的顯示形態,達到可配置的效果。
  3. 能夠經過給組件添加類屬性 defaultProps 來配置默認參數。
  4. props 一旦傳入,你就不能夠在組件內部對它進行修改。可是你能夠經過父組件主動從新渲染的方式來傳入新的 props,從而達到更新的效果。

 

相關文章
相關標籤/搜索