乐趣区

关于react.js:深度讲解React-Props

一、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 版本之后,独自作为一个库应用

  1. 写法一: 给类组件的 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
  1. 应用 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
  1. 默认属性值,当某个属性没有传递的时候,就应用你定义的值
// 指定默认标签属性值 
Person.defaultProps = { 
    sex: '男', 
    age: 17 
}
  1. 函数组件反对通过给 构造函数设置属性 , 进行 组件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 属性中能够给指定的属性, 设置一个验证函数实现一些自定义验证规定。自定义验证函数个别状况下接管三个参数:propspropNamecomponentName

  • 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 个参数:propValuekeycomponentNamelocationpropsFullName

  • 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.`)
        }
    }),
 }

六、小总结

  1. 每个组件对象 都会有 props(properties 的简写)属性
  2. 组件标签的所有 属性都保留在 props
  3. 通过标签属性 从组件内向组件内传递变动的数据
  4. 留神: 组件外部不要批改 props 数据
  5. 应用propTypes 属性并配合 prop-types 三方库实现 prop 验证(不必另外下载,已集成在脚手架中)
退出移动版