一、props的介绍
当React遇到的元素是用户自定义的组件,它会将JSX属性作为单个对象传递给该组件,这个对象称之为“props”。
函数申明的组件,会承受一个props形参,获取属性传递的参数
function ComponentA(props) { return <div>我是组件B:{props.value}</div>}
如果函数组件须要props性能,肯定不能短少该形参
类的申明,在react组建中,应用constructor 获取Component类的props属性当组件继承了父类props后,就能够通过this.props属性名进行属性传值
class ComponentB extends React.Component { constructor(props) { super(props); } render() { return <div>我是组件B {this.props.name}</div> }}
类的继承子类必须在constructor办法中调用super办法,否则新建实例时会报错
。
这是因为子类本人的this对象,必须先通过父类的构造函数实现塑造,失去与父类同样的实例属性和办法,而后再对其进行加工,加上子类本人的实例属性和办法。如果不调用super办法,子类就得不到this对象。
留神: props能够传递任何数据类型,并且props是只读的(单项数据流),所有的React组件必须像纯函数那样应用它们的props。
React实战视频解说:进入学习
二、批量传递props
情景: 有时咱们要传递的参数不止一个的话,那如果是每个都写,10个兴许你能承受,那100个,1000个呢。那你的代码几乎神了。
既然如此,咱们就借用ES6中的开展运算符(...),就是三个点这玩意。
咱们间接先定义好传递的参数,而后再传递。
class Person extends React.Component { render() { console.log(this); // Person 实例对象 const { name, age, sex } = this.props; return ( <ul> <li>姓名: {name}</li> <li>性别: {sex}</li> <li>年龄: {age}</li> </ul> ) }}// 单个传递ReactDOM.render(<Person name="Tom" age="18" sex="woman" />, document.getElementById('test'))ReactDOM.render(<Person name="Jack" age="19" sex="man" />, document.getElementById('test1'))// 批量传递const p = { name: '老王', age: 30, sex: 'man' }ReactDOM.render(<Person {...p}/>, document.getElementById('test2'))
三、props的验证
随着利用日渐宏大,通常你心愿每个 props 都有指定的值类型,并能够通过类型查看捕捉大量谬误,便捷开发缩小异样保护工夫,要查看组件的props属性,你须要配置组件非凡的动态 propTypes 属性并配合prop-types 三方库实现prop验证。(prop-types 在react脚手架中自带无需下载)
在16版本之前的形式
ComponentA.propTypes = { name: React.PropTypes.string.isRequired, // 限度name必传,且为字符串}
16版本之后,独自作为一个库应用
- 写法一: 给类组件的class设置属性 propTypes
import React, {Component} from 'react'import PropTypes from 'prop-types'class ComponentA extends Component { render() { // 因为 jsx 元素实质上是 React.createElement() 隐式调用的 // 所以如果你的js文件中蕴含jsx元素就必须import React 反对让jsx元素隐式调用否则编译器会报错 // 'React' must be in scope when using JSX return ( <div> <p>name: {this.props.name}</p> <p>age: {this.props.age}</p> </div> ) }}ComponentA.propTypes = { name: PropTypes.string, age: PropTypes.number}export default ComponentA
- 应用class 动态属性语法(static) 设置 propTypes,
类的本身
增加的属性。
import React, {Component} from 'react'import PropTypes from 'prop-types'class ComponentA extends Component { static propTypes = { name: PropTypes.string, age: PropTypes.number } render() { // 因为 jsx 元素实质上是 React.createElement() 隐式调用的 // 所以如果你的js文件中蕴含jsx元素就必须import React 反对让jsx元素隐式调用否则编译器会报错 // 'React' must be in scope when using JSX return ( <div> <p>name: {this.props.name}</p> <p>age: {this.props.age}</p> </div> ) }}export default ComponentA
- 默认属性值,当某个属性没有传递的时候,就应用你定义的值
// 指定默认标签属性值 Person.defaultProps = { sex: '男', age: 17 }
- 函数组件反对通过给构造函数设置属性,进行组件props验证
import React, {Component} from 'react'import PropTypes from 'prop-types'class ComponentA extends Component { static propTypes = { name: PropTypes.string, age: PropTypes.number } render() { // 因为 jsx 元素实质上是 React.createElement() 隐式调用的 // 所以如果你的js文件中蕴含jsx元素就必须import React 反对让jsx元素隐式调用否则编译器会报错 // 'React' must be in scope when using JSX return ( <div> <p>name: {this.props.name}</p> <p>age: {this.props.age}</p> </div> ) }}export default ComponentA
四、类式组件中的结构器与props
如果不初始化 state 或不进行办法绑定,则不须要为 React 组件实现构造函数。
在 React 组件挂载之前,会调用它的构造函数。在为 React.Component 子类实现构造函数时,应在其余语句之前前调用 super(props)
。否则,this.props
在构造函数中可能会呈现未定义的 bug。
通常,在 React 中,构造函数仅用于以下两种状况:
- 通过给 this.state 赋值对象来初始化外部 state。
- 为事件处理函数绑定实例 (bind扭转this指向)
// state的根本应用constructor(props) { super(props); // 初始化状态 this.state = { isHot: true, wind: '大风' } // bind: 做了两件事件 ---- 生成新的函数并且扭转this为Weather的实例对象 // this.changeWeather是原型上的办法,通过bind扭转this之后生成新的办法放在了实例本身上,导致了实例中也有changeWeather这个办法,这样就能进行调用了 this.changeWeather = this.changeWeather.bind(this); }
传不传props之间的区别
class Person extends React.Component { // 1、传入props并且也传给了super constructor(props) { // console.log(props) super(props); console.log(this.props); // 组件所传入的所有props 如:{name: "Tom", sex: "男", age: 17, speak: ƒ} } // 2、传入props但不传给super constructor(props) { // console.log(props) super(); console.log(this.props); // undefined console.log(props); // 组件所传入的所有props 如:{name: "Tom", sex: "男", age: 17, speak: ƒ} } // 3、都不传 constructor() { // console.log(props) super(); console.log(this.props); // undefined }}
总结:
结构器是否接管props,是否传递给super, 取决于:是否心愿在结构器中通过this拜访props
五、三方库prop-types的应用
根底类型验证
PropTypesDemo.propTypes = { propsArray: PropTypes.array, // 数组 propsObject: PropTypes.object, // 对象 propsString: PropTypes.string, //字符串 propsNumber: PropTypes.number, // 数字 propsBool: PropTypes.bool, // 布尔值 propsSymbol: PropTypes.symbol, // 公有数据类型 propsFunc: PropTypes.func, // 函数 // 节点数据类型(任何能够渲染的数据类型) propsNode: PropTypes.node, // react元素(jsx) propsElement: PropTypes.element,}
React中 对象 bool symbol func都是不能间接渲染在页面上的这些数据类型都不属于node类型
必传属性修饰符isRequired
prop-types所有类型后丢能够跟isRequired修饰符代表该属性是必传属性
PropTypesDemo.propTypes = { propsArray: PropTypes.array.isRequired, // 必传 Array 类型 propsElement: PropTypes.element.isRequired // 必传 element 类型 propsAny: PropTypes.any.isRequired // 必传 任意数据类型}
prop-types 还提供了一个any数据类型示意任意数据类型,该类型次要是配合isRequired修饰符,示意以后属性不能为空
简单类型验证
PropTypesDemo.propTypes = { // 数据为指定构造函数函数的实例 propsCurrentProto: PropTypes.instanceOf(Dog), // 属性值为指定的值的其中之一 propsOneOf: PropTypes.oneOf(['男', '女']), // 属性的数据类型为指定类型的其中之一 propsOneOfType: PropTypes.oneOfType([ PropTypes.array, PropTypes.object, PropTypes.instanceOf(RegExp), PropTypes.oneOf(['男', '女']) ]), // 指定每一项数据类型的数组 propsStringArray: PropTypes.arrayOf(PropTypes.string), // 指定每一项键值对value数据类型的对象 propsDateObj: PropTypes.objectOf(PropTypes.instanceOf(Date)), // 指定key和value数据类型的对象 propsCurrentObject: PropTypes.shape({ name: PropTypes.string, // 这个属性能够为缺省值 age: PropTypes.number.isRequired // 该属性在以后对象中必须存在 }) }
除了 instanceOf,oneOf以外其余几个验证规定能够相互嵌套, isRequired修饰符仍然能够在上述验证规定中应用 自定义验证规定
在React 组件的propTypes属性中能够给指定的属性,设置一个验证函数实现一些自定义验证规定。自定义验证函数个别状况下接管三个参数:props,propName,componentName。
- props :以后组件接管到的属性传参的对象汇合
- propName :应用以后自定义规定的属性名
- componentName :以后组件名
当接管props的属性值不能通过验证规定时只须要向函数内部返回一个Error实例对象就好了。
案例: 实现自定义验证规定,传入的数据必须是字符串或者数字,字符串不能蕴含“fxxk”敏感字符,数字必须大于等于18 小于等于 120。
ComponentC.propTypes = { propsA: function (props, propName, componentName) { let val = props[propName] if(typeof val === 'string') { if(/fxxk/.test(val)) { return new Error(`组件:${componentName},中属性"${propName}"值为${val}蕴含敏感字符`) } } else if(typeof val === 'number') { if(val < 18 || val > 120 ){ return new Error(`组件:${componentName},中属性"${propName}"值为${val}不满足18-120区间`) } }else { return new Error(`组件:${componentName},中属性"${propName}" 值不是字串或数字`) } } }
定义验证规定配合arrayOf
或者 ObjectOf
应用
自定义验证函数能够作为参数传递给prop-types库的arrayOf 或者 ObjectOf中对数组,对象进行遍历验证。这时该验证规定函数接管5个参数:propValue,key, componentName,location,propsFullName
- propValue :以后验证的数组或者对象本身
- key : 遍历数组的下标或对象的key值
- componentName :以后组件名
- location :以后值的地位常量 "prop"
- propsFullName :遍历进去以后项的字符串全名
例子:propsCustomArrayOf[2]
,propsCustomArrayOf.name
PropTypesDemo.propTypes = { // arrayOf 或者 ObjectOf 自定义验证规定 propsCustomArrayOf: PropTypes.arrayOf(function (propValue, key, componentName, location, propsFullName) { if(!/matchme/.test(propValue[key])) { return new Error(`Failed prop type: Invalid prop '${propsFullName}' supplied to ${componentName}.Validation failed.`) } }), propsCustomObjectOf: PropTypes.objectOf(function (propValue, key, componentName, location, propsFullName) { if(!/matchme/.test(propValue[key])) { return new Error(`Failed prop type: Invalid prop '${propsFullName}' supplied to ${componentName}.Validation failed.`) } }), }
六、小总结
- 每个组件对象都会有props(properties的简写)属性
- 组件标签的所有属性都保留在props中
- 通过标签属性从组件内向组件内传递变动的数据
- 留神: 组件外部不要批改props数据
- 应用propTypes 属性并配合prop-types 三方库实现prop验证(不必另外下载,已集成在脚手架中)