Skip to content

组合核心属性 props

props也是组件实例核心属性之一, 可以通过标签属性从组件外向组件内传递变化的数据

基本使用

通过一个案例来讲解props的基本使用

需求

需求: 自定义用来显示一个人员信息的组件, 实现如下功能

  1. 姓名必须指定, 且为字符串类型
  2. 年龄必须指定, 且为数字类型
  3. 性别为字符串类型, 如果没有指定默认为男

基本实现

  • 代码示例
jsx
// 1. 创建组件
class Person extends React.Component {
  render() {
    // 查看 props
    console.log(this.props)
    // 从 props 中获取数据
    const { name, age, gender } = this.props
    return (
      <ul>
        <li>姓名: { name }</li>
        <li>年龄: { age }</li>
        <li>性别: { gender }</li>
      </ul>
    )
  }
}
// 2. 渲染虚拟 DOM 到页面
// 通过标签属性向 props 传递数据
ReactDOM.render(<Person name="Tom" age="18" gender="男" />, document.getElementById("app1"));
ReactDOM.render(<Person name="Jerry" age="20" gender="女" />, document.getElementById("app2"));
ReactDOM.render(<Person name="June" age="16" gender="女" />, document.getElementById("app3"));

批量传递 props

可以使用{...对象名}语法糖将对象中的属性批量传递给props

注意

  1. 对象的属性名就是组件的标签名
  2. 这种写法只是React组件的语法糖, 跟展开运算符无关
  3. 这种语法只能在标签中作为语法糖使用, 直接使用不会报错但结果为空
  • 代码示例
jsx
const man = { name: 'Tom', age: 18, gender: '男' }
// { ...对象名 } 可以将对象中的属性批量传递, 相当于语法糖, 注意: 标签名就是对象的属性名
ReactDOM.render(<Person { ...man } />, document.getElementById("app"));
// 等同于
ReactDOM.render(<Person name={man.name} age={man.age} gender={man.gender} />, document.getElementById("app"));

// 验证展开对象
console.log('man:', ...man) // man:

扩展: 关于展开运算符

虽然批量传递props的语法格式跟ES6的展开运算符相同, 但并不一样, 因为在ES6中展开运算符不能展开对象

ES6展开运算符的使用

  • 展开一个数组
js
let arr = [1, 3, 5, 7, 9];
console.log(...arr); // 1 3 5 7 9
  • 连接两个数组
js
let arrA = [1, 3, 5, 7, 9];
let arrB = [2, 4, 6, 8, 10];
let arrC = [...arrA, ...arrB];
console.log(arrC); // [1, 3, 5, 7, 9, 2, 4, 6, 8, 10]
  • 函数中作为形参使用
js
function getSum(...numbers) {
  console.log(numbers); // [1, 2, 3, 4]
  return numbers.reduce((pre, current) => {
    return pre + current;
  });
}
console.log(getSum(1, 2, 3, 4)); // 10
  • 展开对象报错, 不能用于展开对象
js
let person = { name: "Tom", age: 18 };
console.log(...person) // Uncaught TypeError: Spread syntax requires ...iterable[Symbol.iterator] to be a function
  • 构造字面量对象时使用展开语法, 属于深拷贝
js
let personA = { name: "Tom", age: 18 };
let personB = { ...personA };
personA.name = "Jerry";
console.log(personA); // {name: 'Jerry', age: 18}
console.log(personB); // {name: 'Tom', age: 18}
  • 合并对象
js
// 在 personA 的基础上修改 name 属性并新增 address 属性
let personA = { name: "Tom", age: 18 };
let personB = { ...personA, name: "Jack", address: "火星" };
console.log(personB); // {name: 'Jack', age: 18, address: '火星'}

限制 props

React中可以对props标签属性的类型和默认值进行限制

限制类型

使用PropTypes可以对props标签属性进行类型限制

注意

React 16之前版本中React核心库内置了PropTypes, 在React 16及之后版本将PropTypes从核心库中独立出来了, 需要手动引入PropTypes

  • 引入props-types库, 用于对组件标签属性进行限制
html
<!-- props-types 限制组件标签属性 -->
<script type="text/javascript" src="https://cdn.jsdelivr.net/gh/9ml/cdn@main/js/react/v16.8.4/props-types.js"></script>
  • 限制props类型
jsx
Person.propTypes = {
  // string 字符串类型, isRequired 必传不能为空
  name: PropTypes.string.isRequired,
  // number 数字类型
  age: PropTypes.number,
  // string 字符串类型
  gender: PropTypes.string,
  // function 函数类型
  speak: PropTypes.func
}

限制默认值

使用defaultProps可以对props标签属性进行默认值限制, 当props标签属性为空时, 会自动获取默认值

  • 代码示例
jsx
Person.defaultProps = {
  age: 20,
  gender: '不男不女'
}

完整示例

html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>对 props 进行限制</title>
</head>
<body>
  <!-- 准备一个容器 -->
  <div id="app1"></div>
  <div id="app2"></div>
  <div id="app3"></div>
  <!-- React 核心库 -->
  <script type="text/javascript" src="https://cdn.jsdelivr.net/gh/9ml/cdn@main/js/react/v16.8.4/react.development.js"></script>
  <!-- 操作 DOM 的扩展库 -->
  <script type="text/javascript" src="https://cdn.jsdelivr.net/gh/9ml/cdn@main/js/react/v16.8.4/react-dom.development.js"></script>
  <!-- 解析 JSX 语法库 -->
  <script type="text/javascript" src="https://cdn.jsdelivr.net/gh/9ml/cdn@main/js/react/v16.8.4/babel.min.js"></script>
  <!-- props-types 限制组件标签属性 -->
  <script type="text/javascript" src="https://cdn.jsdelivr.net/gh/9ml/cdn@main/js/react/v16.8.4/prop-types.js"></script>
  <!-- type="text/babel" 表示此标签内编写的是 JSX 语法脚本 -->
  <script type="text/babel">
    // 1. 创建组件
    class Person extends React.Component {
      render() {
        // 查看 props
        console.log(this.props)
        // 从 props 中获取数据
        const { name, age, gender } = this.props
        return (
          <ul>
            <li>姓名: { name }</li>
            <li>年龄: { age }</li>
            <li>性别: { gender }</li>
          </ul>
        )
      }
    }

    // 限制类型
    Person.propTypes = {
      // string 字符串类型, isRequired 必传不能为空
      name: PropTypes.string.isRequired,
      // number 数字类型
      age: PropTypes.number,
      // string 字符串类型
      gender: PropTypes.string,
      // function 函数类型
      speak: PropTypes.func
    }

    // 限制默认值
    Person.defaultProps = {
      age: 20,
      gender: '不男不女'
    }
    // 2. 渲染虚拟 DOM 到页面
    // 通过标签属性向 props 传递数据
    ReactDOM.render(<Person name="Tom" age={ 18 } gender="男" speak={ speak } />, document.getElementById("app1"));
    ReactDOM.render(<Person name="Jerry" />, document.getElementById("app2"));
    const man = { name: 'June', age: 16, gender: '女' }
    ReactDOM.render(<Person { ... man } />, document.getElementById("app3"));

    function speak() {
      console.log('我说话了')
    }
  </script>
</body>
</html>

props 简写方式

限制props标签属性可以放在类式组件的内部, 要定义成静态属性

先来看看类的静态属性

类的静态属性

  • 代码示例
js
class Person {
  // 公有属性 供实例使用
  name = 'Miller'

  // 静态属性 可以直接使用类名调用
  static demo = 123
}

const man = new Person()
// 通过实例获取公有属性
console.log(man.name) // Miller

// 直接通过类获取静态属性
console.log(Person.demo) // 123

// 类外部设置静态属性
Person.data = 789
console.log(Person.data) // 789

简写方式

由上例得出可以将限制props标签的代码作为静态属性放在组件内部

  • 代码示例
jsx
// 1. 创建组件
class Person extends React.Component {
  // 限制类型
  static propTypes = {
    // string 字符串类型, isRequired 必传不能为空
    name: PropTypes.string.isRequired,
    // number 数字类型
    age: PropTypes.number,
    // string 字符串类型
    gender: PropTypes.string,
    // function 函数类型
    speak: PropTypes.func
  }

  // 限制默认值
  static defaultProps = {
    age: 20,
    gender: '不男不女'
  }

  render() {
    // 查看 props
    console.log(this.props)
    // 从 props 中获取数据
    const { name, age, gender } = this.props
    return (
      <ul>
        <li>姓名: { name }</li>
        <li>年龄: { age }</li>
        <li>性别: { gender }</li>
      </ul>
    )
  }
}

// 2. 渲染虚拟 DOM 到页面
// 通过标签属性向 props 传递数据
ReactDOM.render(<Person name="Tom" age={ 18 } gender="男" speak={ speak } />, document.getElementById("app1"));
ReactDOM.render(<Person name="Jerry" />, document.getElementById("app2"));
const man = { name: 'June', age: 16, gender: '女' }
ReactDOM.render(<Person { ... man } />, document.getElementById("app3"));

function speak() {
  console.log('我说话了')
}

类中的 props 与构造器

在上一章组件实例核心属性 state 中讲到了组件constructor构造器接收props并使用super(props)传递props

那在这里就填一下坑, 看看在构造器中接收跟不接收props有什么区别

官网说明

React官网关于构造器的说明:

如果不初始化state或不进行方法绑定, 则不需要为React组件实现构造函数

React组件挂载之前, 会调用它的构造函数, 在为React.Component子类实现构造函数时, 应在其他语句之前调用super(props)否则this.props在构造函数中可能会出现为定义的bug

通常, 在React中, 构造函数仅用于以下两种情况:

  • 通过给this.state赋值对象来初始化内部state
  • 为事件出来函数绑定实例

constructor()函数中不要调用setState()方法, 如果你的组件需要使用内部state, 请直接在构造函数中为this.state赋值初始化state

验证

在官网中已经明确说明了, props在构造器中可接可不接, 取决于是否要在构造器中通过this.props获取数据

下面来验证一下这3种情况

  • 接收并传递props
jsx
class Person extends React.Component {
  // 构造器 - 接收并传递 props
  constructor(props) {
    super(props)
    console.log(this.props) // {name: 'Tom', age: 20, gender: '不男不女'}
  }
}
  • 接收但不传递props
jsx
class Person extends React.Component {
  // 构造器 - 接收但不传递 props
  constructor(props) {
    super()
    console.log(this.props) // undefined
  }
}
  • 不接收且不传递props
jsx
class Person extends React.Component {
  // 构造器 - 不接收且不传递 props
  constructor() {
    super()
    console.log(this.props) // undefined
  }
}

函数式组件使用 props

在函数式组件中不能使用state状态和refs, 但是可以使用props

  • 代码示例
jsx
// 1. 创建函数式组件
function Person(props) {
  // 在函数形参中接收 props
  console.log(props) // {name: 'Tom', age: 18, gender: '男'}
  const { name, age, gender } = props
  return (
    <ul>
      <li>姓名: { name }</li>
      <li>年龄: { age }</li>
      <li>性别: { gender }</li>
    </ul>
  )
}

// 限制类型
Person.propTypes = {
  // string 字符串类型, isRequired 必传不能为空
  name: PropTypes.string.isRequired,
  // number 数字类型
  age: PropTypes.number,
  // string 字符串类型
  gender: PropTypes.string
}

// 限制默认值
Person.defaultProps = {
  age: 20,
  gender: '不男不女'
}

// 2. 渲染虚拟 DOM 到页面
// 通过标签属性向 props 传递数据
ReactDOM.render(<Person name="Tom" />, document.getElementById("app1"));

总结

概述

每个组件对象都会有props(properties的简写)属性

组件标签的所有属性都保存在props

作用

通过标签属性从组件外向组件内传递变化的数据

注意

props是只读的, 组件内部不能修改props数据

使用步骤

  1. 内部读取某个属性值this.props.name
  2. props中的属性值进行类型限制和必要性要求