什么是Props
props
是组件(函数组件和class组件)间的内置属性,用于在组件之间传递数据。它是父组件向子组件传递信息的一种方式,通过 props
,父组件可以向子组件传递数据、函数、配置项等。
初次使用Props
先定义一个父组件
import React from 'react';
import ReactDOM from 'react-dom/client';
import Child from './child'
const root = ReactDOM.createRoot(document.getElementById('root'));
// 父组件
function App(){
return <Child title='个人信息' name="小浩" sex="男" age="30"></Child>
}
root.render(
<>
<App></App>
</>
);
在父组件中的Child
上面添加属性和属性的值,这样父组件就把信息传递给了子组件。那么子组件要怎么使用呢?
创建子组件
import React from 'react';
class Child extends React.Component{
render(){
console.log(this.props)//输出props信息
return <div className="child">
<h2>{this.props.title}</h2>
<ul>
<li>姓名:{this.props.name}</li>
<li>性别:{this.props.sex}</li>
<li>年龄:{this.props.age}</li>
</ul>
</div>
}
}
export default Child
可以看到子组件直接使用this.props
就可以拿到父组件传的信息了。
在浏览器渲染的name、sex、age
属性和在控制台中可以看到在子组件中打印的props
对象,可以清晰看到在父组件的Child
组件上添加的属性信息。
上面我们就只传递了几个参数,直接在Child
上写还是比较方便的,那如果需要传递的属性特别多还要一个个添加吗?那如何批量传递呢?
批量传递Props
我们可以利用Js的展开运算符
来实现批量传递参数,看下面这段代码:
//父组件
import React from 'react';
import ReactDOM from 'react-dom/client';
import Child from './child'
const root = ReactDOM.createRoot(document.getElementById('root'));
function App(){
// 定义要传递的用户信息对象
const user = {
title:'个人信息',
name:'小浩',
sex:'男男',
age:30,
work:'程序员'
}
return <Child {...user}></Child>
}
root.render(
<>
<App></App>
</>
);
这里我创建了user
这个变量对象:
const user = {
title:'个人信息',
name:'小浩',
sex:'男男',
age:30,
work:'程序员'
}
然后使用{...user}
就可以一次性批量传入user
里面的属性数据,简单快捷。
// 子组件
import React from 'react';
class Child extends React.Component{
render(){
console.log(this.props)
return <div className="child">
<h2>{this.props.title}</h2>
<ul>
<li>姓名:{this.props.name}</li>
<li>性别:{this.props.sex}</li>
<li>年龄:{this.props.age}</li>
<li>工作:{this.props.work}</li>
</ul>
</div>
}
}
export default Child
浏览器输出
类组件中使用Props
在上面初次使用Props
中,可以看出在类组件,是通过this.props
拿到父组件传递的对象信息。
那如果想要年龄增加1,要怎么做呢?是直接+1
吗?下面来看看效果:
父组件中使用属性传递数据
function App(){
return <Child title='个人信息' name="小浩" sex="男" age="30" work="程序员"></Child>
}
子组件中接收传递的数据this.props.age + 1
import React from 'react';
class Child extends React.Component{
render(){
console.log(this.props)
return <div className="child">
<h2>{this.props.title}</h2>
<ul>
<li>姓名:{this.props.name}</li>
<li>性别:{this.props.sex}</li>
<li>年龄:{this.props.age + 1}</li>
<li>工作:{this.props.work}</li>
</ul>
</div>
}
}
export default Child
浏览器输出
可以看到年龄变成了301,变成字符串拼接了。那要如何传递呢?
我们只需要在父组件中传递的年龄加上花括号就会转为number类型。
function App(){
return <Child title='个人信息' name="小浩" sex="男" age={30} work="程序员"></Child>
}
浏览器输出
既然props
是个对象,那我们可以直接修改props
里面的属性值和增加属性吗?
下面试着修改props
里的work
属性值为销售
:
class Child extends React.Component{
render(){
console.log(this.props)
// 在这里试着修改props里的work属性
this.props.work = '销售'
return <div className="child">
<h2>{this.props.title}</h2>
<ul>
<li>姓名:{this.props.name}</li>
<li>性别:{this.props.sex}</li>
<li>年龄:{this.props.age}</li>
<li>工作:{this.props.work}</li>
</ul>
</div>
}
}
上面修改了props
里work
的值,浏览器就提示错误:
上面报错提示信息就是告诉你:
props
属性是只读的,不允许修改
那么为什么不能修改props
的属性呢?
扫盲知识点:关于对象的规则设置
- 冻结
冻结对象:Object.freeze(obj)
检测是否被冻结:Object.isFrozen(obj) =>true/false
被冻结的对象:不能修改成员值、不能新增成员、不能删除现有成员、不能给成员做劫持Object,defineProperty
- 密封
密封对象:Object.seal(obj)
检测是否被密封:Object.isSealed(obj)
被密封的对象: 可以修改成员的值,但也不能删、不能新增、不能劫持!! - 扩展
把对象设置为不可扩展:Object.preventExtensions(obj)
检测是否可扩展:Object.isExtensible(obj)
被设置不可扩展的对象: 除了不能新增成员、其余的操作都可以处理! !
总结:被冻结的对象,是不可扩展的,也是密封的!!同理,被密封的对象,也是不可扩展的!!
下面再来看看子组件Child
的this.props
是怎样的对象规则:
class Child extends React.Component{
render(){
console.log(Object.isFrozen(this.props)) // true
console.log(Object.isSealed(this.props)) // true
console.log(Object.isExtensible(this.props)) // false
return <div className="child">
<h2>{this.props.title}</h2>
</div>
}
}
至此,了解到为什么不能修改props
的属性了,因为props
对象是被冻结的、密封的且不可扩展的。
函数组件中使用Props
问题:函数式组件中没有this
,那如何拿到props
属性的值呢?
看下面这段代码:
import React from 'react';
function Child(props){
console.log(props) // 打印props信息
const {title, name, sex, age, work} = props
return <div className="child">
<h2>{title}</h2>
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age}</li>
<li>工作:{work}</li>
</ul>
</div>
}
export default Child
可以看到函数本身可以接收到一个props
参数拿到父组件传递的信息。
Props设置默认值
类组件中设置默认值
- 方式一:在子组件中使用
defaultProps
设置默认值
父组件就可以不用添加work
属性
function App(){
return <Child title='个人信息' name="小浩" sex="男" age={30}></Child>
}
子组件中给Child
添加defaultProps
属性对象
class Child extends React.Component{
render(){
console.log(this.props)
return <div className="child">
<h2>{this.props.title}</h2>
<ul>
<li>姓名:{this.props.name}</li>
<li>性别:{this.props.sex}</li>
<li>年龄:{this.props.age}</li>
<li>工作:{this.props.c}</li>
</ul>
</div>
}
}
// 设置默认值
Child.defaultProps ={
work:'程序员'
}
export default Child
- 方式二:在
Child
内添加静态属性static defaultProps = {}
设置默认值
class Child extends React.Component{
// 设置默认值
static defaultProps = {
work:'程序员'
}
render(){
console.log(this.props)
return <div className="child">
<h2>{this.props.title}</h2>
<ul>
<li>姓名:{this.props.name}</li>
<li>性别:{this.props.sex}</li>
<li>年龄:{this.props.age}</li>
<li>工作:{this.props.work}</li>
</ul>
</div>
}
}
export default Child
函数组件中设置默认值
- 方式一:使用
defaultProps
设置默认值
function Child(props){
const {title, name, sex, age, work} = props
return <div className="child">
<h2>{title}</h2>
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age}</li>
<li>工作:{work}</li>
</ul>
</div>
}
Child.defaultProps = {
work:'程序员'
}
export default Child
- 方式二:通过解构
props
时给属性设置默认值
function Child(props){
console.log(props)
const {title, name, sex, age, work = '程序员'} = props
return <div className="child">
<h2>{title}</h2>
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age}</li>
<li>工作:{work}</li>
</ul>
</div>
}
export default Child
Props验证
在react V15.5
之前,限制props
的写法是:React.PropTypes
class Child extends React.Component {
}
Child.propTypes = {
age: React.PropTypes.number,
}
在react V15.5
之后,限制props
的写法是:1、需要引入prop-types的库 2、PropTypes
安装
npm install prop-types -D
引入
import PropTypes from 'prop-types'
使用
import React from 'react';
import PropTypes from 'prop-types'
class Child extends React.Component{
static defaultProps = {
work:'程序员'
}
render(){
console.log(this.props)
return <div className="child">
<h2>{this.props.title}</h2>
<ul>
<li>姓名:{this.props.name}</li>
<li>性别:{this.props.sex}</li>
<li>年龄:{this.props.age}</li>
<li>工作:{this.props.work}</li>
</ul>
</div>
}
}
Child.propTypes = {
name: PropTypes.string.isRequired,
sex: PropTypes.string,
age: PropTypes.number,
work: PropTypes.string
}
export default Child
可以看到上面age
我们限制的是number
类型,如果父组件age
传过来的是string
类型会怎样呢?
function App(){
return <Child title='个人信息' name="小浩" sex="男" age='30'></Child>
}
浏览器输出
浏览器控制台提示红色告警,告诉我们age
传的是string
类型,不支持,应该传number
类型
function App(){
return <Child title='个人信息' name="小浩" sex="男" age={30}></Child>
}
Props常见的约束规则
常用的类型限制
PropTypes.array //数组
PropTypes.bool //布尔
PropTypes.func //函数
PropTypes.object //对象
PropTypes.number //数值
PropTypes.string //字符串
PropTypes.symbol //Symbol
PropTypes.element //React元素
必填项:isRequired—在类型后面添加
Child.propTypes = {
//限制age为数字类型,且必需
age: PropTypes.number.isRequired
}
仅限制必要任何类型:any.isRequired
Child.propTypes = {
//限制age类型随意,但必需
age: PropTypes.any.isRequired
}
多可选类型:oneOfType([])
Child.propTypes = {
//该方法接受一个数组参数,数组内容为允许通过的类型
age: PropTypes.oneOfType(
[PropType.string,PropType.number]
)
}
多可选值:oneOf([])
Child.propTypes = {
//sex的值只能从男和女中选择一个
sex: PropTypes.oneOf(
['男', '女']
)
}
限制对象结构:shape({})
Child.propTypes = {
//user = {name: '小浩', id: 1} 满足校验
user: PropTypes.shape({
name: PropTypes.string.isRequired,
id: PropTypes.number.isRequired
})
}
下面我们来实践下,看下面这段代码:
父组件传递属性数据
function App(){
return <Child title='个人信息' name="小浩" sex="男" age={30} info={{desc:'用户介绍',id:1}}></Child>
}
子组件做props
限制并显示
import React from 'react';
import PropTypes from 'prop-types'
class Child extends React.Component{
static defaultProps = {
work:'程序员'
}
render(){
console.log(this.props)
return <div className="child">
<h2>{this.props.title}</h2>
<ul>
<li>姓名:{this.props.name}</li>
<li>性别:{this.props.sex}</li>
<li>年龄:{this.props.age}</li>
<li>工作:{this.props.work}</li>
<li>介绍:{this.props.info.desc}</li>
</ul>
</div>
}
}
Child.propTypes = {
name: PropTypes.string.isRequired,
sex: PropTypes.oneOf(['男', '女']),
age: PropTypes.number.isRequired,
work: PropTypes.string,
info: PropTypes.shape({desc: PropTypes.string.isRequired,id: PropTypes.number.isRequired})
}
export default Child
总结:如果设置了props
验证,就必须按照规定。