配置组件的 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,从而达到更新的效果。

 

相关文章
相关标签/搜索