父子通讯

父级组件调用子组件,通过 props 来传递参数,子组件通过 this.props 来接收

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React from "react";

class Children extends React.Component {
render() {
const { datalist } = this.props;
return <div></div>;
}
}
class Parent extends React.Component {
render() {
const { datalist } = [];
return (
<div>
<Children datalist={datalist}></Children>
</div>
);
}
}

子父通讯

父级组件通过 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
import React from "react";

class Children extends React.Component {
componentDidMount() {
const { getData } = this.props;
getData([1, 2, 3, 4, 5]);
}
render() {
return <div>this is children</div>;
}
}
class Parent extends React.Component {
getData(val) {
//[1,2,3,4,5]
console.log(val);
}
render() {
return (
<div>
<Children getData={this.getData}></Children>
</div>
);
}
}

同级通讯

1
2
3
4
5
6
7
8
9
10
npm install --save events
const EventEmitter = require('events')

const EventBus = new EventEmitter()
//事件订阅
EventBus.on("message", function (text) {
console.log(text) //hello world
})
//事件发布
EventBus.emit("message", 'hello world')

跨级组件通讯 - 发布订阅模式

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
const eventProxy = {
// onObj 存放多个监听事件的对象
// oneObj 存放多个监听事件的对象,获取一次清空
onObj: {},
oneObj: {},
//监听事件
$on: function (key, fn) {
// 当前请求事件在对象中是否存在
//不存在 返回一个[]
if (this.onObj[key] === undefined) {
this.onObj[key] = [];
}
//将事件处理函数添加到对应的key
this.onObj[key].push(fn);
},
$once: function (key, fn) {
if (this.oneObj[key] === undefined) {
this.oneObj[key] = [];
}
this.oneObj[key].push(fn);
},
// 移除事件监听
$remove: function (key) {
this.onObj[key] = [];
this.oneObj[key] = [];
},
// 触发器或者发射器
$emit: function () {
let key, args;
if (arguments.length == 0) {
return false;
}
//trigger("update",data1,data2,data3)
// 获取trigger函数的arguments,得到类数组
// key 获取传参序列的第一项
key = arguments[0]; //onObj[arguments[0]
//类数组没有数组的slice,通过call改变this指向,让类数组继承数组的slice方法,完成截取功能
args = [].concat(Array.prototype.slice.call(arguments, 1)); //data1,data2,data3
// console.log(this.onObj[key][0]())
if (this.onObj[key] !== undefined && this.onObj[key].length > 0) {
for (let i in this.onObj[key]) {
// console.log(args)
this.onObj[key][i].call(null, args);
}
}
if (this.oneObj[key] !== undefined && this.oneObj[key].length > 0) {
for (let i in this.oneObj[key]) {
// null 继承 this.oneObj[key][i]函数并调用,参数是args
this.oneObj[key][i].apply(null, args);
// console.log(args)
this.oneObj[key][i] = undefined;
}
this.oneObj[key] = [];
}
},
};
eventProxy.$on("update", function (val) {
console.log(val);
});
eventProxy.$once("update", function (val) {
console.log(val);
});
eventProxy.$emit("update", 1, 2, 3);

跨级通讯

案例描述:
当前有三个组件,包裹顺序依次是: Parent > Middle > Children 现在 Parent 组件有数据要传递给 Children 组件

  • Parent > Middle > Children 具体方案请参考 props 传参
  • Parent > Children 具体方案如下,通 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
import React from "react";
import PropTypes from "prop-types";
// 子级
class Children extends React.Component{
// props类型校验
static propsTypes ={
propA: PropTypes.string
methodA: PropTypes.func
}
// props默认值的设置
static defaultProps = {

}
// 跨级组件接收参数
static contextTypes = {
propA: PropTypes.string
methodA: PropTypes.func
}
render(){

return <div>
this is children: {this.context.propA}
</div>
}
}
// 中间
class Middle extends React.Component {
render () {
return <Children />
}
}
// 父级
class Parent extends React.Component{
// 声明Context对象属性
static childContextTypes = {
propA: PropTypes.string,
methodA: PropTypes.func
}
// 返回Context对象,方法名是约定好的
getChildContext () {
return {
propA: 'propA',
methodA: () => 'methodA'
}
}
render(){
return <div>
<Middle/>
</div>
}
}

跨级组件通讯(新)

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
conts { Provider ,Consumer}= React.createContect([defaultValue])
class Child extends React.Component {
render() {
//Consumer只能通过一个回调函数返回一react元素
return <Consumer>
{context => <div>
{
context.map(item=>{
return <li key={item.id}>
{item.name}
</li>
})
}
</div>}
</Consumer>
}
}
class Middleware extends React.Component {
render() {
return <div>
this is Middleware
<Child/>
</div>
}
}
class App extends React.Component {
constructor() {
super()
this.state = {
productList: [{
id: 1,
name: "zhangsan"
}, {
id: 2,
name: "lisi"
}]
}
}
render() {
return <div className="wraper">
<Header></Header>
<Layout>
//value 固定写法用来给子组件传参
<Provider value={this.state.productList}>
<Middleware/>
</Provider>
</Layout>
</div>
}
}

父组件向子组件通讯

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
父组件
import React, { Component } from "react";
import Child from "./Child";//引入子组件
export default class Parent extends Component {
state = {
name: "sara"
};
render() {
const { name } = this.state;//解构出来定义的状态
return <Child name={name}></Child>;将状态传递给子组件
}
}

------------------------------------------------------------------------------------------

子组件可以用类组件,也可以用函数组件
类组件:
import React, { Component } from "react";
export default class Child extends Component {
componentDidMount(){
console.log(this.props);
}
render() {
const {name}=this.props
return <div>{name}</div>;
}
}
------------------------------------------------------------------------------------------
函数组件:
import React from "react";
export default function Child({ name }) {//将用到的属性从props属性上解构出来
return <div>{name}</div>;
}

父组件向子组件传 (值&&回调函数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
父组件;
class App extends Component {
state = {
bgcolor: "pink",
};
bgchange = (color) => {
this.setState({
bgcolor: color,
});
};
render() {
return (
<div className="App">
<Today
bgcolor={this.state.bgcolor}
changeColor={(color) => {
this.bgchange(color);
}}
></Today>
</div>
);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
子组件
export default class Toda extends Component {
handleClick(){
this.props.changeColor('skyblue');//从父组件传递过来的回调
}
render() {
return (
<div>
<p>父组件的背景颜色 {this.props.bgcolor}</p>
<button onClick={(e)=>{
this.handleClick(e);
}}>改变父组件背景</button>
</div>
);
}
}

子组件向父组件通讯

  • 利用回调函数传值
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
父组件
import React, { Component } from "react";
import Child from "./Child";
export default class Parent extends Component {
render() {
return (
<Child
childEvent={options => {
//向子组件传递一个函数
this.callback(options);
}}
/>
);
}
callback(options) {
console.log(options);
}
}
----------------------------------------------------------------------------------------
export default class Child extends Component {
render() {
return (
<button
onClick={() => {
this.add();
}}
>
点击
</button>
);
}
add() {
//再子组件中点击的时候 接收父组件传递参数
this.props.childEvent("我是子组件传递过来的");
}

跨级组件通讯

context 层层组件传递 props[参考链接https://www.jianshu.com/p/65b348bf86ad]

例如 A 组件和 B 组件之间进行通信,需要先找到 A 和 B 公共的父组件,A 先向 C 组件通信,C 组件通过 props 和 B 组件通信,此时 C 组件起的就是中间件的作用。
使用 context,是一个全局变量,像是一个大容器,再任何地方都可以访问到,我们可以把要通信的信息放在 context 上,然后再其他组件中可以随意取到。
React 官网不建议使用大量的 context,尽管他可以减少逐层传递,当组件结构复杂的时候,并不知道 context 是从哪里传过来的,context 是一个全局变量。


准备工作 再 src 下新建 content/index.js 目录

1
2
3
4
5
6
7
8
9
10
11
12
content / index.js;

//1.创建Context
import { createContext } from "react";
const Context = createContext();
//2.解构 内置组件Provider Consumer
const { Provider, Consumer } = Context;
//3.抛出内置组件
export {
Provider, //嵌套最外层 传递参数
Consumer, //接收参数
};
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
App.js中;
//1.引入Provider
import { Provider } from "./context/index.js";
import Parent from "./components/Parent"; //引入父组件
class App extends Component {
state = {
name: "小人头",
};
render() {
return (
<Provider value={this.state.name}>
<div className="App">
<div
style={{
border: "1px solid green",
width: "60%",
margin: "50px auto",
textAlign: "center",
}}
>
<p>父组件定义的值:{this.state.name}</p>
<Parent />
</div>
</div>
</Provider>
);
}
}

export default App;
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
父组件;
import { Consumer } from "../context/index";
import Grandson from "./Grandson";
function Parent() {
return (
//Consumer容器,可以拿到上文传递下来的name属性,并可以展示对应的值
<Consumer>
{(name) => (
<div
style={{
border: "1px solid blue",
width: "70%",
margin: "20px auto",
textAlign: "center",
}}
>
<p>子组件,获取父组件的值:{name}</p>
{/* 孙组件内容 */}
<Grandson />
</div>
)}
</Consumer>
);
}
export default Parent;
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
Consumer孙组件;
import React, { Component } from "react";
import { Consumer } from "../context/index.js";

export default function Grandson() {
return (
<div>
{/** <Consumer>{name => <div>{name}</div>}</Consumer> 格式一定不能错 */}
<Consumer>
{(name) => (
<div
style={{
border: "1px solid green",
width: "65%",
margin: "50px auto",
textAlign: "center",
}}
>
<p>孙组件。获取传递下来的值:{name}</p>
</div>
)}
</Consumer>
</div>
);
}

没有嵌套关系组件之间的通讯

  • 使用自定义事件机制

自定义事件是典型的发布订阅模式,通过向事件对象上添加事件监听器和触发事件来实现组件之间的通信

1
2
3
4
5
npm install events --save
在src下新建一个util目录里面建一个events.js
import { EventEmitter } from 'events';

export default new EventEmitter();

使用 ref

再需要获取组件实例上

再用到这个个form表单的组件内,this.refs.addForm.refs.childForm.validateFields();