组合核心属性 props
props也是组件实例核心属性之一, 可以通过标签属性从组件外向组件内传递变化的数据
基本使用
通过一个案例来讲解props的基本使用
需求
需求: 自定义用来显示一个人员信息的组件, 实现如下功能
- 姓名必须指定, 且为字符串类型
- 年龄必须指定, 且为数字类型
- 性别为字符串类型, 如果没有指定默认为男
基本实现
- 代码示例
// 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
注意
- 对象的属性名就是组件的标签名
- 这种写法只是
React组件的语法糖, 跟展开运算符无关 - 这种语法只能在标签中作为语法糖使用, 直接使用不会报错但结果为空
- 代码示例
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展开运算符的使用
- 展开一个数组
let arr = [1, 3, 5, 7, 9];
console.log(...arr); // 1 3 5 7 9- 连接两个数组
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]- 函数中作为形参使用
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- 展开对象报错, 不能用于展开对象
let person = { name: "Tom", age: 18 };
console.log(...person) // Uncaught TypeError: Spread syntax requires ...iterable[Symbol.iterator] to be a function- 构造字面量对象时使用展开语法, 属于深拷贝
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}- 合并对象
// 在 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库, 用于对组件标签属性进行限制
<!-- 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类型
Person.propTypes = {
// string 字符串类型, isRequired 必传不能为空
name: PropTypes.string.isRequired,
// number 数字类型
age: PropTypes.number,
// string 字符串类型
gender: PropTypes.string,
// function 函数类型
speak: PropTypes.func
}限制默认值
使用defaultProps可以对props标签属性进行默认值限制, 当props标签属性为空时, 会自动获取默认值
- 代码示例
Person.defaultProps = {
age: 20,
gender: '不男不女'
}完整示例
<!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标签属性可以放在类式组件的内部, 要定义成静态属性
先来看看类的静态属性
类的静态属性
- 代码示例
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标签的代码作为静态属性放在组件内部
- 代码示例
// 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
class Person extends React.Component {
// 构造器 - 接收并传递 props
constructor(props) {
super(props)
console.log(this.props) // {name: 'Tom', age: 20, gender: '不男不女'}
}
}- 接收但不传递
props
class Person extends React.Component {
// 构造器 - 接收但不传递 props
constructor(props) {
super()
console.log(this.props) // undefined
}
}- 不接收且不传递
props
class Person extends React.Component {
// 构造器 - 不接收且不传递 props
constructor() {
super()
console.log(this.props) // undefined
}
}函数式组件使用 props
在函数式组件中不能使用state状态和refs, 但是可以使用props
- 代码示例
// 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数据
使用步骤
- 内部读取某个属性值
this.props.name - 对
props中的属性值进行类型限制和必要性要求