Prop 验证
随着应用不断变大,保证组件被正确使用变得非常有用。为此我们引入propTypes
。React.PropTypes
提供很多验证器 (validator) 来验证传入数据的有效性。当向 props 传入无效数据时,JavaScript 控制台会抛出警告。注意为了性能考虑,只在开发环境验证 propTypes
。下面用例子来说明不同验证器的区别:
1 React.createClass({ 2 propTypes: { 3 // 可以声明 prop 为指定的 JS 基本类型。默认 4 // 情况下,这些 prop 都是可传可不传的。 5 optionalArray: React.PropTypes.array, 6 optionalBool: React.PropTypes.bool, 7 optionalFunc: React.PropTypes.func, 8 optionalNumber: React.PropTypes.number, 9 optionalObject: React.PropTypes.object, 10 optionalString: React.PropTypes.string, 11 12 // 所有可以被渲染的对象:数字, 13 // 字符串,DOM 元素或包含这些类型的数组。 14 optionalNode: React.PropTypes.node, 15 16 // React 元素 17 optionalElement: React.PropTypes.element, 18 19 // 用 JS 的 instanceof 操作符声明 prop 为类的实例。 20 optionalMessage: React.PropTypes.instanceOf(Message), 21 22 // 用 enum 来限制 prop 只接受指定的值。 23 optionalEnum: React.PropTypes.oneOf(['News', 'Photos']), 24 25 // 指定的多个对象类型中的一个 26 optionalUnion: React.PropTypes.oneOfType([ 27 React.PropTypes.string, 28 React.PropTypes.number, 29 React.PropTypes.instanceOf(Message) 30 ]), 31 32 // 指定类型组成的数组 33 optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number), 34 35 // 指定类型的属性构成的对象 36 optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number), 37 38 // 特定形状参数的对象 39 optionalObjectWithShape: React.PropTypes.shape({ 40 color: React.PropTypes.string, 41 fontSize: React.PropTypes.number 42 }), 43 44 // 以后任意类型加上 `isRequired` 来使 prop 不可空。 45 requiredFunc: React.PropTypes.func.isRequired, 46 47 // 不可空的任意类型 48 requiredAny: React.PropTypes.any.isRequired, 49 50 // 自定义验证器。如果验证失败需要返回一个 Error 对象。不要直接 51 // 使用 `console.warn` 或抛异常,因为这样 `oneOfType` 会失效。 52 customProp: function(props, propName, componentName) { 53 if (!/matchme/.test(props[propName])) { 54 return new Error('Validation failed!'); 55 } 56 } 57 }, 58 /* ... */ 59 });
默认 Prop 值
React 支持以声明式的方式来定义 props
的默认值。
1 ar ComponentWithDefaultProps = React.createClass({ 2 getDefaultProps: function() { 3 return { 4 value: 'default value' 5 }; 6 } 7 /* ... */ 8 });
当父级没有传入 props 时,getDefaultProps()
可以保证 this.props.value
有默认值,注意 getDefaultProps
的结果会被 缓存。得益于此,你可以直接使用 props,而不必写手动编写一些重复或无意义的代码。
传递 Props:小技巧
有一些常用的 React 组件只是对 HTML 做简单扩展。通常,你想少写点代码来把传入组件的 props 复制到对应的 HTML 元素上。这时 JSX 的 spread 语法会帮到你:
1 var CheckLink = React.createClass({ 2 render: function() { 3 // 这样会把 CheckList 所有的 props 复制到 <a> 4 return <a {...this.props}>{'√ '}{this.props.children}</a>; 5 } 6 }); 7 8 React.render( 9 <CheckLink href="/checked.html"> 10 Click here! 11 </CheckLink>, 12 document.getElementById('example') 13 );
单个子级
React.PropTypes.element
可以限定只能有一个子级传入
1 var MyComponent = React.createClass({ 2 propTypes: { 3 children: React.PropTypes.element.isRequired 4 }, 5 6 render: function() { 7 return ( 8 <div> 9 {this.props.children} // 有且仅有一个元素,否则会抛异常。 10 </div> 11 ); 12 } 13 14 });
Mixins
组件是 React 里复用代码最佳方式,但是有时一些复杂的组件间也需要共用一些功能。有时会被称为 跨切面关注点。React 使用 mixins
来解决这类问题。
一个通用的场景是:一个组件需要定期更新。用 setInterval()
做很容易,但当不需要它的时候取消定时器来节省内存是非常重要的。React 提供 生命周期方法 来告知组件创建或销毁的时间。下面来做一个简单的 mixin,使用 setInterval()
并保证在组件销毁时清理定时器。
1 var SetIntervalMixin = { 2 componentWillMount: function() { 3 this.intervals = []; 4 }, 5 setInterval: function() { 6 this.intervals.push(setInterval.apply(null, arguments)); 7 }, 8 componentWillUnmount: function() { 9 this.intervals.map(clearInterval); 10 } 11 }; 12 13 var TickTock = React.createClass({ 14 mixins: [SetIntervalMixin], // 引用 mixin 15 getInitialState: function() { 16 return {seconds: 0}; 17 }, 18 componentDidMount: function() { 19 this.setInterval(this.tick, 1000); // 调用 mixin 的方法 20 }, 21 tick: function() { 22 this.setState({seconds: this.state.seconds + 1}); 23 }, 24 render: function() { 25 return ( 26 <p> 27 React has been running for {this.state.seconds} seconds. 28 </p> 29 ); 30 } 31 }); 32 33 React.render( 34 <TickTock />, 35 document.getElementById('example') 36 );
关于 mixin 值得一提的优点是,如果一个组件使用了多个 mixin,并且有多个 mixin 定义了同样的生命周期方法(如:多个 mixin 都需要在组件销毁时做资源清理操作),所有这些生命周期方法都保证会被执行到。方法执行顺序是:首先按 mixin 引入顺序执行 mixin 里方法,最后执行组件内定义的方法。