Props进阶
一、基本用法
主要作用是让使用该组件的父组件可以传入参数来配置该组件。它是外部传进来的配置参数,组件内部无法控制也无法修改。除非外部组件主动传入新的
props
,否则组件的props
永远保持不变。
没有
state
的组件叫无状态组件(stateless component),设置了 state 的叫做有状态组件(stateful component)。因为状态会带来管理的复杂性,我们尽量多地写无状态组件,尽量少地写有状态的组件。这样会降低代码维护的难度,也会在一定程度上增强组件的可复用性。
- props 和 state 都是js对象,都会触发render更新,都具有确定性(状态/属性相同,结果相同)
在使用一个组件的时候,可以把参数放在标签的属性当中,所有的属性都会作为 组件 props 对象的键值。通过箭头函数创建的组件,需要通过函数的参数来接收 props
- 组件间传值,在 Reac t中时通过只读属性 props 来完成数据传递的
- props:接收任意的传参,并返回用于描述页面展示内容的 React 元素
1.1、类组件中使用
- 注意点:
1. 必须具备父子关系
2. 通过props进行传递
3. 支持写死数据""和可变数据{}传递
4. 不要接收props形参,直接用“this.props”即可
5. 在父子关系中,类组件和函数组件可以混用,使用的方式根据当前组件决定
- 子组件
ClassCmpErZi.jsx
import React, { Component } from "react";
class ClassCmpErZi extends Component {
render() {
return (
<div>
山重水复疑无路,{this.props.next}。{this.props.name}
</div>
);
}
}
export default ClassCmpErZi;
- 父组件
ClassCmpBaBa.jsx
import React, { Component } from "react";
// 导入erzi组件
import ErZi from "./ClassCmpErZi";
class ClassCmpBaBa extends Component {
// 声明可变数据
next = "柳暗花明又一村";
render() {
return (
<div>
{/* 使用儿子组件 */}
<ErZi next={this.next} name="陆游"></ErZi>
</div>
);
}
}
export default ClassCmpBaBa;
1.2、函数组件使用
- 注意点:
1. 必须具备父子关系
2. 通过props进行传递
3. 支持写死数据""和可变数据{}传递
4. 传递过去后,子组件就有props属性了,数据都在props属性对象中
5. 要使用props,必须要通过函数形参接收props,否则props没定义
- 子组件
FunCmpErZi.jsx
import React from "react";
const FunCmpErZi = (props) => {
return <div>我劝天公重抖擞,{props.next}。{props.name}</div>;
};
export default FunCmpErZi;
- 父组件
FunCmpBaBa.jsx
import React from "react";
// 导入ErZi组件
import ErZi from "./FunCmpErZi";
const FunCmpBaBa = () => {
// 声明数据
var next = "不拘一格降人才";
return (
<div>
{/* 使用儿子组件 */}
<ErZi next={next} name="龚自珍"></ErZi>
</div>
);
};
export default FunCmpBaBa;
二、children 属性
- 介绍:
1. children 属性是只存在于 props 对象中的一个属性
2. children 属性只有在组件标签中有子节点的时候才会存在
3. children 属性的使用就类似于vue中匿名插槽
插槽就是在子组件中挖一个坑,坑里填什么由父组件决定(传值:父-子)
4. children 属性的值可以是任意的类型(可以是字符串,也可以是对象),并且标签子节点也可以是多个
5. 如果子组件标签里只存在一个子节点,则children属性值为一个字符串;如果子组件标签里存在多个子节点,那么children属性的值为一个索引数组
ClassCmpErZi.jsx
子组件
import React, { Component } from 'react';
class ClassCmpErZi extends Component {
render() {
// 接收数据
console.log(this.props.msg);
console.log(this.props.children);
return (
<div>
<div>这是一个子组件</div>
<h2>接收到的数据</h2>
<div>{this.props.children}</div>
</div>
);
}
}
export default ClassCmpErZi;
ClassCmpBaBa.jsx
父组件
import React, { Component } from 'react';
import ErZi from './ClassCmpErZi'
class ClassCmpBaBa extends Component {
render() {
return (
<div>
<ErZi msg='顺带传递一个消息'>
<div>
<p>这就是组件标签的子节点1</p>
<p>这就是组件标签的子节点1</p>
</div>
<div>
这是div2
</div>
</ErZi>
</div>
);
}
}
export default ClassCmpBaBa;
- 运行结果
三、props-type 包的使用
- 安装
prop-types
:
npm i -S prop-types
3.1、PropTypes 检查类型
- 关于JavaScript的class中的静态成员与普通成员
class App{
// 静态成员
static uname = 'lisi'
// 普通成员
name = 'lisi'
}
// 静态属性是在类里面,使用时不要实例化
console.log((new App).name);
// 普通属性是在对象里,使用前要先实例化
console.log(App.uname);
// 静态成员要优先于普通成员
React是为了构建大型应用程序而生,在一个大型开发过程中会进行多人协作,往往可能根本不知道别人使用你写的组件时候会传入什么样的参数,这样就有可能会造成应用程序运行不了但是又不报错的情况。所以必须要对于props设传入的数据类型进行效验,为了解决这个问题,React提供了一种机制,让写组件的人可以给组件的props设定参数检查。
- 在使用时,必须导入
prop-types
import PropTypes from "prop-types";
- 更多的验证规则,可以参考React官网
- 需要注意,
isRequired
规则必须放在最后且不能独立于其他规则存在。
1.optionalArray: PropTypes.array, //检测数组类型
2.optionalBool: PropTypes.bool, //检测布尔类型
3.optionalFunc: PropTypes.func, //检测函数(Function类型)
4.optionalNumber: PropTypes.number, //检测数字
5.optionalObject: PropTypes.object, //检测对象
6.optionalString: PropTypes.string, //检测字符串
7.optionalSymbol: PropTypes.symbol, //ES6新增的symbol类型
8.optionalSymbol: PropTypes.isRequired //设置必填
- 设置一个父组件
ClassCmpBaBa.jsx
// 1. 在vue中props的数据类型和默认值的指定都是可以直接写代码实现的,但是react中需要安装三方包; 命令:npm i -S prop-types
// 2. 由于prop-types是用于限制/约定默认值和数据类型的,因此得先实现父子传递的关系;
import React, { Component } from 'react';
// 导入子组件
import ErZi from "./ErZi"
class ClassCmpBaBa extends Component {
render() {
return (
<div>
<ErZi username="zhangsan" password={123456}></ErZi>
</div>
);
}
}
export default ClassCmpBaBa;
- 在函数组件中使用
import React, { Component } from "react";
import Pts from "prop-types";
function ErZi(props){
// 函数组件声明过程
return <div></div>;
}
// 为ErZi方法组件挂上验证规则
ErZi.propTypes = {
// 属性名: 约束规则
username: Pts.string,
password: Pts.number,
}
export default ErZi;
- 在类组件中使用方法1
import React, { Component } from "react";
import Pts from "prop-types";
class ErZi extends Component {
render() {
return <div></div>;
}
}
// 为ErZi方法组件挂上验证规则
ErZi.propTypes = {
// 属性名: 约束规则
username: Pts.string,
password: Pts.number,
}
export default ErZi;
- 在类组件中使用方法2(推荐)
静态属性名是固定的propTypes,为了避免导入近来的PropTypes名高度相似,建议给包导进来的模块写一个另类的名称。
import React, { Component } from "react";
import Pts from "prop-types";
class ErZi extends Component {
// 类型约束
static propTypes = {
// 属性名: 约束规则
username: Pts.string,
password: Pts.number,
}
render() {
return <div></div>;
}
}
// 为ErZi方法组件挂上验证规则
export default ErZi;
3.2、defaultProps 设置默认值
如果props有属性没有传来的数据,为了不让程序异常,我们可以根据业务情况给对应的属性设置默认值
- 说明:
1. 默认值也是基于prop-types第三方包的
2. 整体写法与类型约束一致,就是换了一个属性名:defaultProps
3. 使用方法与prop-types一致,类写里面,函数写外面
4. 空字符串算有值,所以不会触发默认值
- 设置一个父组件
ClassCmpBaBa.jsx
import React, { Component } from 'react';
// 导入子组件
import ErZi from "./ErZi"
class ClassCmpBaBa extends Component {
render() {
return (
<div>
{/* 由于设置了defaultProps, 不传props也能正常运行,如果传递了就会覆盖defaultProps的值 */}
<ErZi username="zhangsan" password={123456}></ErZi>
</div>
);
}
}
export default ClassCmpBaBa;
- 在函数组件中使用
import React, { Component } from "react";
import Pts from "prop-types";
function ErZi(props){
// 函数组件声明过程
return <div></div>;
}
ErZi.defaultProps = {
// 如果没有对应属性的数据,则使用默认值来替代
// 属性名:默认值
username: "法外狂徒",
password: "password",
msg: "11.00",
};
export default ErZi;
- 在类组件中使用方法1
import React, { Component } from "react";
import Pts from "prop-types";
class ErZi extends Component {
render() {
return <div></div>;
}
}
ErZi..defaultProps = {
// 如果没有对应属性的数据,则使用默认值来替代
// 属性名:默认值
username: "法外狂徒",
password: "password",
msg: "11.00",
};
export default ErZi;
- 在类组件中使用方法2(推荐)
静态属性名是固定的propTypes,为了避免导入近来的PropTypes名高度相似,建议给包导进来的模块写一个另类的名称。
import React, { Component } from "react";
import Pts from "prop-types";
class ErZi extends Component {
// 类中默认值约定
static propTypes = {
// 属性名: 默认值
// 如果没有对应属性的数据,则使用默认值来替代
username: "法外狂徒",
password: "password",
msg: "11.00",
}
render() {
return <div></div>;
}
}
export default ErZi;