React 参数传递
# props的使用
作用:接收到传递给组件中的属性
在函数组件中通过函数的参数获取到 props
在类组件中通过 this.props
来获取到 props
props
是一个对象。可以给组件传递任何类型的数据。
注意
只读属性。只能读取 props
对象中的属性,而不能修改 props
对象中的属性
如果在 class
组件中,手动添加了 constructor
,那么,就应该通过参数获取到props
, 然后传递给super
,这样,才能够在 constructor
中,获取到 props
const Hello = props => {
// props 就表示传递给组件的属性
}
<Hello name="jack" age={19} colors={['red']} />
// 类组件:
class Hello extends React.Component {
constructor(props) {
super(props)
// console.log('在构造函数中,获取到 props ', this.props)
console.log('在构造函数中,获取到 props ', props)
}
render() {
console.log('class组件中获取到props:', this.props)
return (
<div>
<h1>props:{this.props.age}</h1>
{this.props.colors.map((item, index) => (
<p key={index}>{item}</p>
))}
</div>
)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 组件通讯
# 父到子
父组件中提供状态
在子组件标签上添加属性,值为父组件中的状态
子组件中通过 props
来接收父组件中传递过来的数据
// 父组件:
class Parent extends React.Component {
// 提供数据
state = {
lastName: '王'
}
render() {
return (
<div className="parent">
<h1>父组件:</h1>
{/* 1 通过属性给子组件传递数据 */}
<Child name={this.state.lastName} />
</div>
)
}
}
// 子组件:
// 2 子组件中通过 props 接收数据
const Child = props => {
return <p className="child">这是子组件:{props.name}</p>
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 子到父
父组件提供一个事件(函数),让子组件调用;子组件调用的时候,将数据作为参数的传递,父组件中通过事件(函数)的参数,就拿到子组件中的数据了。
父组件提供事件
将事件通过 props
传递给子组件
子组件中通过 props
接收到父组件中传递过来的事件
子组件调用该事件,将数据作为参数传递
注意点:父组件提供的方法中 this
执行问题。
- 为什么会有这个问题?因为这个方法不是父组件自己调用的,是由其他组件调用的,所以,需要处理this指向。
// 1 提供事件(回调函数,)
// 事件是子组件调用的,因此,先要通过 props 传递给子组件
// 2 将事件传递给子组件
class Parent extends React.Component {
state = {
msg: ''
}
getChildMsg = data => {
console.log('父组件中的方法调用了', data)
this.setState({
msg: data
})
}
// 注意:this指向问题,因为这个方法是由子组件调用的,所以,应该提前处理好 this 指向!
/* getChildMsg(data) {
console.log('父组件中的方法调用了', data, this)
this.setState({
msg: data
})
} */
render() {
return (
<div className="parent">
<h1>父组件:{this.state.msg}</h1>
<Child fn={this.getChildMsg} />
</div>
)
}
}
// 子组件:
// 3 子组件中通过 props 接收到父组件中传递过来的事件
// 4 子组件中调用传递过来的事件, 将数据作为事件的参数传递
const Child = props => {
// console.log(props)
const handleClick = () => {
// 调用
props.fn('撩汉子')
}
return (
<p className="child">
这是子组件:
<button onClick={handleClick}>发送数据给父组件</button>
</p>
)
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 兄弟组件
思路:状态提升,也就是:将两个兄弟组件之间的共享数据,放在父组件中。
父组件的职责:
- 提供共享数据
state
- 提供修改状态的方法
例子:如果 子组件2 要传递数据给 子组件1
子组件1:只要通过 props 接收到父组件中传递过来的数据(父 -> 子)
子组件2:调用父组件中修改状态的方法(子 -> 父)
- 但是,需要先通过 props 获取到父组件中传递过来的方法
// 父组件
// 1 提供状态
// 2 提供操作状态的方法
class Parent extends React.Component {
state = {
msg: '默认值'
}
updateMsg = data => {
this.setState({
msg: data
})
}
render() {
return (
<div className="parent">
这是父组件:
<Child1 msg={this.state.msg} />
<Child2 updateMsg={this.updateMsg} />
</div>
)
}
}
// 子组件1
// 3 接收数据(数据由父组件提供)
class Child1 extends React.Component {
render() {
return <div className="child">这是子组件1:{this.props.msg}</div>
}
}
// 子组件2:
// 4 在父组件中传递事件给子组件
// 5 给按钮绑定单击事件
// 6 调用父组件中的事件来更新数据
class Child2 extends React.Component {
// 单击事件
handleClick = () => {
// 调用父组件的事件
this.props.updateMsg('子组件2222222222222222222222')
}
render() {
return (
<div className="child2">
这是子组件2:
<button onClick={this.handleClick}>传递数据给 Child1</button>
</div>
)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# Context
使用场景:跨组件传递数据
如果两个组件是远方亲戚(比如,嵌套多层)可以使用 Context
实现组件通讯
Context
提供了两个组件:Provider
和 Consumer
Provider
组件:用来提供数据
Consumer
组件:用来消费数据
const { Provider, Consumer } = React.createContext()
<Provider value={this.state.msg}>
<div className="parent">
这是父组件:
<Child1 />
</ div>
</ Provider>
// Child1 -> Child2 -> Child3
// Child3
// data 就是 Provider 中提供的 value
<Consumer>{data => <p>接收到的数据为:{data}</p>}</Consumer>
2
3
4
5
6
7
8
9
10
11
12
13
14
# 组件的 children 属性
表示组件标签的子节点。当组建有子节点时就有该属性。
children
属性与普通的props一样值可以是任意值(文本、React 元素、组件,函数....)
children
代表父组件双标签中的子节点
<div> 父组件
<h1>children 组件</h1> 子节点
</div>
2
3
还可以自定义子组件
在组件中使用 this.props.xxxx
然后在使用时传入 xxx
属性
示例
import React from 'react';
class Test extends React.Component {
render() {
return (
<div>
<div>{this.props.left}</div>
<div>{this.props.children}</div>
<div>{this.props.right}</div>
</div>
)
}
}
export default class App extends React.Component {
render() {
return (
<Test
left={<h1>左子组件</h1>}
right={<h1>右子组件</h1>}
>
<h1>子组件 children</h1>
</Test>
)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Props 校验
在创建组件时,就指定props 的类型、格式、等。
作用: 捕获使用组件时因为props 导致的错误,给出提示,增加健壮性。
# 使用
- 安装 prop-types 包
npm i prop-types -D
- 导入 prop-types 包
- 使用
- 函数组件: 使用
组件名.proptypes = {...}
来定义prop
规则 - 类组件:使用
static proptypes = {...}
来定义规则
- 函数组件: 使用
- 校验规则通过 PropTypes 来指定
# 示例
import React from 'react';
import PropTypes, { number, string } from 'prop-types'
//类组件
class Test extends React.Component {
//定义校验规则
static propTypes = {
text: string
}
render() {
return (
<div>
{this.props.text}
</div>
)
}
}
//函数组件
function Test1(props) {
return <h1>{props.text}</h1>
}
//定义校验规则
Test1.propTypes = {
text: number
}
export default class App extends React.Component {
render() {
return (
<>
<Test text={123} /> // 传入参数类型错误 ,会警告
<Test1 text={"123"} /> // 传入参数类型错误 ,会警告
</>
)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# PropTypes
以下提供了使用不同验证器的例子:
点击显示代码
import PropTypes from 'prop-types';
MyComponent.propTypes = {
// 你可以将属性声明为 JS 原生类型,默认情况下
// 这些属性都是可选的。
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,
// 任何可被渲染的元素(包括数字、字符串、元素或数组)
// (或 Fragment) 也包含这些类型。
optionalNode: PropTypes.node,
// 一个 React 元素。
optionalElement: PropTypes.element,
// 一个 React 元素类型(即,MyComponent)。
optionalElementType: PropTypes.elementType,
// 你也可以声明 prop 为类的实例,这里使用
// JS 的 instanceof 操作符。
optionalMessage: PropTypes.instanceOf(Message),
// 你可以让你的 prop 只能是特定的值,指定它为
// 枚举类型。
optionalEnum: PropTypes.oneOf(['News', 'Photos']),
// 一个对象可以是几种类型中的任意一个类型
optionalUnion: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
PropTypes.instanceOf(Message)
]),
// 可以指定一个数组由某一类型的元素组成
optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
// 可以指定一个对象由某一类型的值组成
optionalObjectOf: PropTypes.objectOf(PropTypes.number),
// 可以指定一个对象由特定的类型值组成
optionalObjectWithShape: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number
}),
// An object with warnings on extra properties
optionalObjectWithStrictShape: PropTypes.exact({
name: PropTypes.string,
quantity: PropTypes.number
}),
// 你可以在任何 PropTypes 属性后面加上 `isRequired` ,确保
// 这个 prop 没有被提供时,会打印警告信息。
requiredFunc: PropTypes.func.isRequired,
// 任意类型的数据
requiredAny: PropTypes.any.isRequired,
// 你可以指定一个自定义验证器。它在验证失败时应返回一个 Error 对象。
// 请不要使用 `console.warn` 或抛出异常,因为这在 `onOfType` 中不会起作用。
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
},
// 你也可以提供一个自定义的 `arrayOf` 或 `objectOf` 验证器。
// 它应该在验证失败时返回一个 Error 对象。
// 验证器将验证数组或对象中的每个值。验证器的前两个参数
// 第一个是数组或对象本身
// 第二个是他们当前的键。
customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) {
if (!/matchme/.test(propValue[key])) {
return new Error(
'Invalid prop `' + propFullName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
})
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# 限制单个元素
你可以通过 PropTypes.element
来确保传递给组件的 children 中只包含一个元素。
import PropTypes from 'prop-types';
class MyComponent extends React.Component {
render() {
// 这必须只有一个元素,否则控制台会打印警告。
const children = this.props.children;
return (
<div>
{children}
</div>
);
}
}
MyComponent.propTypes = {
children: PropTypes.element.isRequired
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 默认 Prop 值
通过配置特定的 defaultProps
属性来定义 props
的默认值:
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
// 指定 props 的默认值:
Greeting.defaultProps = {
name: 'Stranger'
};
// 渲染出 "Hello, Stranger":
ReactDOM.render(
<Greeting />,
document.getElementById('example')
);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
如果你正在使用像 transform-class-properties 的 Babel 转换工具,你也可以在 React 组件类中声明 defaultProps
作为静态属性。s此语法提案还没有最终确定,需要进行编译后才能在浏览器中运行。要了解更多信息,请查阅 class fields proposal。
class Greeting extends React.Component {
static defaultProps = {
name: 'stranger'
}
render() {
return (
<div>Hello, {this.props.name}</div>
)
}
}
2
3
4
5
6
7
8
9
10
11
defaultProps
用于确保 this.props.name
在父组件没有指定其值时,有一个默认值。propTypes
类型检查发生在 defaultProps
赋值后,所以类型检查也适用于 defaultProps
。