react——组件通信

React组件通信方式

1.父子组件通信方式

1.回调方式(子传父 )

该方式主要通过父组件通过props向子组件传递一个回调函数,子组件接收到回调函数后,将数据以参数的形式回传给父组件,从而达到父子通信

1
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
import React, {Component} from 'react';

class Parent extends Component {
callback(args) {
console.log('父组件接收到子组件传递的值:',args);
}
render() {
return (
<div>
<Child cb={this.callback} />
</div>
);
}
}

class Child extends Component {
render() {
return (
<div>
<button onClick={() => {
this.props.cb("子组件的传值")
}} >给父组件传值</button>
</div>
);
}
}
export default Parent;

2.父传子

1.props
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React, {useState} from 'react';

export default function Parent() {
const [data,setData] = useState("i am superman~")
return (
<div>
<Child args={data}/>
</div>
)
}

const Child = (props) => {
return (
<h2>接收到父组件的传值:{props.args}</h2>
)
}
2.ref
1.函数式组件
1
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
import React, {forwardRef, useRef, useState} from 'react';

export default function ParentNode() {
const [data,setData] = useState("i am superman~")
const childRef = useRef()
return (
<div>
<button onClick={()=> {
childRef.current.value = ''
}}>清空子组件的input框中的值</button>
<Child ref={childRef} args={data}/>
</div>
)
}

const Child = forwardRef((props,ref) => {
const func = () => {
ref.current.value = ""
}

return (
<div>
<h2> CHILD </h2>
<input ref={ref} type="text"/>
<button onClick={() => func()}>click</button>
</div>

)
})
2.类组件
1
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
import React, { Component } from 'react'

class ChildNode extends Component {
constructor(props){
super(props)
this.state={
count:1
}
}
addCount=()=>{
let newCount = this.state.count+1;
this.setState({
count:newCount
})
}
render() {
return (
<div>
<p>子组件</p>
<p>{this.state.count}</p>
<button onClick={this.addCount}>点我+1</button>
</div>
)
}
}
class ParentNode extends Component {
state={
num:1
}
childRef = React.createRef();
logRef=()=>{
console.log(this.childRef.current)
this.childRef.current.addCount()

// 使用函数式绑定ref就得使用下面这种获取方法
// console.log(this.childRef)
// this.childRef.addCount()
}
render() {
return (
<div>
<h3>父组件</h3>
<button onClick={this.logRef}>打印且调用子组件的方法</button>
{/* 简单的使用ref获取dom */}
<ChildNode ref={this.childRef}/>
{/* 使用函数式绑定ref*/}
{/*<ChildNode ref={el=>this.childRef=el}/>*/}
</div>
)
}
}
export default ParentNode

2.非父子通信

1.状态提升

当你遇到需要同时获取多个子组件数据,或者两个组件之间需要相互通讯的情况时,需要把子组件的 state 数据提升至其共同的父组件当中保存。之后父组件可以通过 props 将状态数据传递到子组件当中。这样应用当中所有组件的状态数据就能够更方便地同步共享了。

1
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import React, {Component} from 'react';
class StateUp extends Component {
state = {
filmList:[
{
"filmId": 5386,
"name": "我的姐姐",
"poster": "https://pic.maizuo.com/usr/movie/75c67d58c49822d782561cdcca65189c.jpg",
"actors": [
{
"name": "殷若昕",
"role": "导演",
"avatarAddress": "https://pic.maizuo.com/usr/movie/5c9574f920a21bfea0a35b0557c6dd43.jpg"
},
{
"name": "张子枫",
"role": "安然",
"avatarAddress": "https://pic.maizuo.com/usr/movie/2bddc157bd0faf6029bbae14ba8d92fc.jpg"
},
{
"name": "肖央",
"role": "舅舅",
"avatarAddress": "https://pic.maizuo.com/usr/movie/3ce5eeb8f056391d655c2d0a6ec35675.jpg"
},
{
"name": "金遥源",
"role": "弟弟",
"avatarAddress": "https://pic.maizuo.com/usr/movie/ecda1a57d366c843f28dc68293d4ae63.jpg"
},
{
"name": "王圣迪",
"role": "童年安然",
"avatarAddress": "https://pic.maizuo.com/usr/movie/a7eb39e0b652da91c4e3a1c1c7a17a85.jpg"
}
],
"director": "殷若昕",
"category": "剧情|家庭",
"synopsis": "电影讲述失去父母的姐姐在面对追求个人独立生活还是抚养弟弟的问题上展开的一段亲情故事。",
"filmType": {
"name": "2D",
"value": 1
},
"nation": "中国大陆",
"language": "",
"videoId": "",
"premiereAt": 1617321600,
"timeType": 3,
"runtime": 127,
"grade": "7",
"item": {
"name": "2D",
"type": 1
},
"isPresale": true,
"isSale": false
},
{
"filmId": 5391,
"name": "哥斯拉大战金刚",
"poster": "https://pic.maizuo.com/usr/movie/b624c348ee645c004b1e349dbe162ec9.jpg",
"actors": [
{
"name": "亚当·温加德",
"role": "导演",
"avatarAddress": "https://pic.maizuo.com/usr/movie/885b9e96f320408abfc9d172588e753a.jpg"
},
{
"name": "亚历山大·斯卡斯加德",
"role": "Nathan Lind",
"avatarAddress": "https://pic.maizuo.com/usr/movie/8e6b49c18a8311d8665bf013ea1aa73a.jpg"
},
{
"name": "米莉·波比·布朗",
"role": "Madison Russell",
"avatarAddress": "https://pic.maizuo.com/usr/movie/c05f1e2481e04f737cd91f4d03c9ff85.jpg"
},
{
"name": "丽贝卡·豪尔",
"role": "Ilene Andrews",
"avatarAddress": "https://pic.maizuo.com/usr/movie/290e19d60a61ecc877bcd20d1969c599.jpg"
},
{
"name": "布莱恩·泰里·亨利",
"role": "Bernie Hayes",
"avatarAddress": "https://pic.maizuo.com/usr/movie/323a79599476310db5bde745910857e4.jpg"
}
],
"director": "亚当·温加德",
"category": "动作|冒险",
"synopsis": "影片中,这两位宛如神衹一般强大的对手于一场壮观的战争中相遇,彼时世界命运正悬于一线。为了找到真正的家园,金刚与他的保护者们踏上了一次艰难的旅程。与他们一道前行的还有一个年轻的孤儿女孩——吉雅,这个女孩与金刚之间存在着一种独特而强大的紧密联系。但意想不到的是,他们在前行的航道上与愤怒的哥斯拉狭路相逢,也由此在全球引起了一系列破坏。一股无形的力量造成了这两只巨兽之间的巨大冲突,深藏在地心深处的奥秘也由此揭开。",
"filmType": {
"name": "2D",
"value": 1
},
"nation": "美国",
"language": "",
"videoId": "",
"premiereAt": 1616716800,
"timeType": 3,
"runtime": 113,
"grade": "7.2",
"item": {
"name": "2D",
"type": 1
},
"isPresale": true,
"isSale": false
}],
info:''

}

render() {
return (
<div>
{
this.state.filmList.map(item =>
<FilmItem onEvent={(value) => {this.setState({info:value})}} key={item.filmId} {...item} />
)
}

<FilmDetail info={this.state.info} />
</div>
);
}
}

class FilmItem extends Component {

render() {

let {name,poster,grade,synopsis} = this.props

return <div className="filmItem" onClick={() => this.props.onEvent(synopsis)} >
<img src={poster} alt=""/>
<h4>{name}</h4>
<div>观众评分:{grade}</div>
</div>
}

}


class FilmDetail extends Component {
render() {
return <div className="filmdetail">
{this.props.info}
</div>
}
}

export default StateUp;

2.消息发布、订阅

  • yarn add pubsub-js
  • 两个兄弟组件,一个发布消息、一个订阅消息

发布者

1
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
import React, {Component} from 'react';
import axios from "axios";
import PubSub from 'pubsub-js'

class Search extends Component {
search = () => {
PubSub.publish('sola',{name:'alex',age:10})


// 获取用户的输入 连续解构赋值
const {keyWordElement: {value: keyWord}} = this

// 发送请求前,通知List更新状态
PubSub.publish('sola',{isFirst: false, isLoading: true})
// 发送网络请求
axios.get(`/api1/search/users?q=${keyWord}`).then(
response => {
// 请求成功后通知List更新状态
PubSub.publish('sola',{isFirst: false, isLoading: false,users:response.data.items})
},
error => {
// 请求失败后通知List更新状态
PubSub.publish('sola',{isLoading: false,err:error.message})
}
)
}

render() {
return (
<section className="jumbotron">
<h3 className="jumbotron-heading">Search Github Users</h3>
<div>
<input ref={c => this.keyWordElement = c} type="text" placeholder="enter the name you search"/>&nbsp;
<button onClick={this.search}> Search</button>
</div>
</section>
);
}
}

export default Search;

订阅者

1
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
import React, {Component} from 'react';
import './index.css'
import PubSub from 'pubsub-js'
class List extends Component {

// 初始化状态,
state = {
users:[], //users初始值为数组
isFirst:true, // 是否为第一次打开页面
isLoading:false, //标识是否处于加载中
err:'' // 存储请求得错误信息
}

componentDidMount() {
this.token = PubSub.subscribe('sola',(_,stateObj) => {
this.setState(stateObj)
})
}

componentWillUnmount() {
PubSub.unsubscribe(this.token)
}

render() {
const {users, isFirst, isLoading, err} = this.state
console.log(users);
return (
<div className="row">
{
isFirst ? <h2>输入关键字,随后点击搜索</h2> :
isLoading ? <h2>loading....</h2> :
err ? <h2>{err}</h2> :
users.map(userObj => {
return (
<div key={userObj.id} className="card">
<a rel="noreferrer" href={userObj.html_url} target="_blank">
<img alt={'noimg'} src={userObj.avatar_url}
style={{width: '100px'}}/>
</a>
<p className="card-text">{userObj.login}</p>
</div>
)
})
}
</div>
);
}
}

export default List;

3.context状态数传参

1
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
import React, {Component} from 'react';

const GlobalContext = React.createContext()

class Context extends Component {
state = {
filmList:[
{
"filmId": 5386,
"name": "我的姐姐",
"poster": "https://pic.maizuo.com/usr/movie/75c67d58c49822d782561cdcca65189c.jpg",
"actors": [
{
"name": "殷若昕",
"role": "导演",
"avatarAddress": "https://pic.maizuo.com/usr/movie/5c9574f920a21bfea0a35b0557c6dd43.jpg"
},
{
"name": "张子枫",
"role": "安然",
"avatarAddress": "https://pic.maizuo.com/usr/movie/2bddc157bd0faf6029bbae14ba8d92fc.jpg"
},
{
"name": "肖央",
"role": "舅舅",
"avatarAddress": "https://pic.maizuo.com/usr/movie/3ce5eeb8f056391d655c2d0a6ec35675.jpg"
},
{
"name": "金遥源",
"role": "弟弟",
"avatarAddress": "https://pic.maizuo.com/usr/movie/ecda1a57d366c843f28dc68293d4ae63.jpg"
},
{
"name": "王圣迪",
"role": "童年安然",
"avatarAddress": "https://pic.maizuo.com/usr/movie/a7eb39e0b652da91c4e3a1c1c7a17a85.jpg"
}
],
"director": "殷若昕",
"category": "剧情|家庭",
"synopsis": "电影讲述失去父母的姐姐在面对追求个人独立生活还是抚养弟弟的问题上展开的一段亲情故事。",
"filmType": {
"name": "2D",
"value": 1
},
"nation": "中国大陆",
"language": "",
"videoId": "",
"premiereAt": 1617321600,
"timeType": 3,
"runtime": 127,
"grade": "7",
"item": {
"name": "2D",
"type": 1
},
"isPresale": true,
"isSale": false
},
{
"filmId": 5391,
"name": "哥斯拉大战金刚",
"poster": "https://pic.maizuo.com/usr/movie/b624c348ee645c004b1e349dbe162ec9.jpg",
"actors": [
{
"name": "亚当·温加德",
"role": "导演",
"avatarAddress": "https://pic.maizuo.com/usr/movie/885b9e96f320408abfc9d172588e753a.jpg"
},
{
"name": "亚历山大·斯卡斯加德",
"role": "Nathan Lind",
"avatarAddress": "https://pic.maizuo.com/usr/movie/8e6b49c18a8311d8665bf013ea1aa73a.jpg"
},
{
"name": "米莉·波比·布朗",
"role": "Madison Russell",
"avatarAddress": "https://pic.maizuo.com/usr/movie/c05f1e2481e04f737cd91f4d03c9ff85.jpg"
},
{
"name": "丽贝卡·豪尔",
"role": "Ilene Andrews",
"avatarAddress": "https://pic.maizuo.com/usr/movie/290e19d60a61ecc877bcd20d1969c599.jpg"
},
{
"name": "布莱恩·泰里·亨利",
"role": "Bernie Hayes",
"avatarAddress": "https://pic.maizuo.com/usr/movie/323a79599476310db5bde745910857e4.jpg"
}
],
"director": "亚当·温加德",
"category": "动作|冒险",
"synopsis": "影片中,这两位宛如神衹一般强大的对手于一场壮观的战争中相遇,彼时世界命运正悬于一线。为了找到真正的家园,金刚与他的保护者们踏上了一次艰难的旅程。与他们一道前行的还有一个年轻的孤儿女孩——吉雅,这个女孩与金刚之间存在着一种独特而强大的紧密联系。但意想不到的是,他们在前行的航道上与愤怒的哥斯拉狭路相逢,也由此在全球引起了一系列破坏。一股无形的力量造成了这两只巨兽之间的巨大冲突,深藏在地心深处的奥秘也由此揭开。",
"filmType": {
"name": "2D",
"value": 1
},
"nation": "美国",
"language": "",
"videoId": "",
"premiereAt": 1616716800,
"timeType": 3,
"runtime": 113,
"grade": "7.2",
"item": {
"name": "2D",
"type": 1
},
"isPresale": true,
"isSale": false
}],
info:''

}

render() {
return (
<GlobalContext.Provider value={{call: 'phone',info:this.state.info,changeInfo:(value) => {this.setState({info:value})}}}>
<div>
{
this.state.filmList.map(item =>
<FilmItem key={item.filmId} {...item} />
)
}

<FilmDetail />
</div>
</GlobalContext.Provider>

);
}
}

class FilmItem extends Component {

render() {

let {name,poster,grade,synopsis} = this.props

return (
<GlobalContext.Consumer>
{
(value) => {
console.log(value);
return <div className="filmItem" onClick={() => {value.changeInfo(synopsis)}} >
<img src={poster} alt=""/>
<h4>{name}</h4>
<div>观众评分:{grade}</div>
</div>
}
}
</GlobalContext.Consumer>
)


}

}


class FilmDetail extends Component {
render() {
return (
<GlobalContext.Consumer>
{
(value) => {
return <div className="filmdetail">
detail-{value.info}
</div>
}
}
</GlobalContext.Consumer>
)
}
}

export default Context;