组件是相互独立、可复用的单元,一个组件可能在不一样地方被用到。可是在不一样的场景下对这个组件的需求可能会根据状况有所不一样,例如一个点赞按钮组件,在我这里须要它显示的文本是“点赞”和“取消”,当别的同事拿过去用的时候,却须要它显示“赞”和“已赞”。如何让组件能适应不一样场景下的需求,咱们就要让组件具备必定的“可配置”性。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
来控制,就能够达到很好的可配置性。
上面的组件默认配置咱们是经过 ||
操做符来实现。这种须要默认配置的状况在 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
一旦传入进来就不能改变。修改上面的例子中的 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
显示形态的效果。
this.props
获取到配置参数,组件能够根据 props
的不一样来肯定本身的显示形态,达到可配置的效果。defaultProps
来配置默认参数。props
一旦传入,你就不能够在组件内部对它进行修改。可是你能够经过父组件主动从新渲染的方式来传入新的 props
,从而达到更新的效果。