前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深度讲解React Props_2023-02-28

深度讲解React Props_2023-02-28

原创
作者头像
用户10376779
发布2023-02-28 09:59:08
2K0
发布2023-02-28 09:59:08
举报
文章被收录于专栏:前端面试12

一、props的介绍

当React遇到的元素是用户自定义的组件,它会将JSX属性作为单个对象传递给该组件,这个对象称之为“props”。

函数声明的组件,会接受一个props形参,获取属性传递的参数

代码语言:javascript
复制
function ComponentA(props) { 
    return <div>我是组件B:{props.value}</div>
}

如果函数组件需要props功能,一定不能缺少该形参 类的声明,在react组建中,使用constructor 获取Component类的props属性当组件继承了父类props后,就可以通过this.props属性名进行属性传值

代码语言:javascript
复制
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。

二、批量传递props

情景: 有时我们要传递的参数不止一个的话,那如果是每个都写,10个也许你能接受,那100个,1000个呢。那你的代码简直神了。

既然如此,我们就借用ES6中的展开运算符(...),就是三个点这玩意。

我们直接先定义好传递的参数,然后再传递。

代码语言:javascript
复制
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版本之前的方式

代码语言:javascript
复制
ComponentA.propTypes = {
    name: React.PropTypes.string.isRequired, // 限制name必传,且为字符串
}

16版本之后,单独作为一个库使用

  1. 写法一: 给类组件的class设置属性 propTypes
代码语言:javascript
复制
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,类的自身添加的属性。
代码语言:javascript
复制
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. 默认属性值,当某个属性没有传递的时候,就使用你定义的值
代码语言:javascript
复制
// 指定默认标签属性值 
Person.defaultProps = { 
    sex: '男', 
    age: 17 
}
  1. 函数组件支持通过给构造函数设置属性,进行组件props验证
代码语言:javascript
复制
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指向)
代码语言:javascript
复制
// 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之间的区别

代码语言:javascript
复制
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的使用

基础类型验证

代码语言:javascript
复制
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修饰符代表该属性是必传属性

代码语言:javascript
复制
PropTypesDemo.propTypes = {
    propsArray: PropTypes.array.isRequired, // 必传 Array 类型
    propsElement: PropTypes.element.isRequired // 必传 element 类型
    propsAny: PropTypes.any.isRequired // 必传 任意数据类型
}

prop-types 还提供了一个any数据类型表示任意数据类型,该类型主要是配合isRequired修饰符,表示当前属性不能为空

复杂类型验证

代码语言:javascript
复制
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。

代码语言:javascript
复制
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

代码语言:javascript
复制
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验证(不用另外下载,已集成在脚手架中)

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、props的介绍
  • 二、批量传递props
  • 三、props的验证
  • 四、类式组件中的构造器与props
  • 五、三方库prop-types的使用
  • 六、小总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档