组件通信

组件之进行通信的几种情况

  • 父组件向子组件通信
  • 子组件向父组件通信
  • 跨级组件通信
  • 没有嵌套关系组件之间的通信

一、父组件向子组件通信

React数据流动是单向的,父组件向子组件通信也是最常见的;父组件通过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
// Child.jsx
import React from 'react';
import PropTypes from 'prop-types';

export default function Child({ name }) {
return <h1>Hello, {name}h1>;
}

Child.propTypes = {
name: PropTypes.string.isRequired,
}


// Parent.jsx
import React, { Component } from 'react';

import Child from './Child';

class Parent extends Component {
render() {
return (

"Sara" />
</div>
);
}
}

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

class List3 extends Component {
static propTypes = {
hideConponent: PropTypes.func.isRequired,
}
render() {
return (

哈哈,我是List3
.props.hideConponent}>隐藏List3组件</button>
div>
);
}
}

export default List3;

//app.jsx

import React, { Component } from 'react';

import List3 from './components/List3';
export default class App extends Component {
constructor(...args) {
super(...args);
this.state = {
isShowList3: false,
};
}
showConponent = () => {
this.setState({
isShowList3: true,
});
}
hideConponent = () => {
this.setState({
isShowList3: false,
});
}
render() {
return (

.showConponent}>显示Lists组件</button>

{
this.state.isShowList3 ?
>
:
null
}

</div>
);
}
}

三、跨级组件通信

层层组件传递 props

例如 A 组件和 B 组件之间要进行通信,先找到 A 和 B 公共的父组件,A 先向 C 组件通信,C 组件通过 props 和 B 组件通信,此时 C 组件起的就是中间件的作用

使用 context

  • context 是一个全局变量,像是一个大容器,在任何地方都可以访问到,我们可以把要通信的信息放在 context 上,然后在其他组件中可以随意取到
  • 但是 React 官方不建议使用大量 context,尽管他可以减少逐层传递,但是当组件结构复杂的时候,我们并不知道 context 是从哪里传过来的;而且 context 是一个全局变量,全局变量正是导致应用走向混乱的罪魁祸首

下面例子中的组件关系: ListItem 是 List 的子组件,List 是 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
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
// ListItem.jsx
import React, { Component } from 'react';
import PropTypes from 'prop-types';

class ListItem extends Component {
// 子组件声明自己要使用context
static contextTypes = {
color: PropTypes.string,
}
static propTypes = {
value: PropTypes.string,
}
render() {
const { value } = this.props;
return (
  • background
  • : this.context.color }}>
    {value}</span>
    li>
    );
    }
    }

    export default ListItem;


    // List.jsx
    import ListItem from './ListItem';

    class List extends Component {
    // 父组件声明自己支持context
    static childContextTypes = {
    color: PropTypes.string,
    }
    static propTypes = {
    list: PropTypes.array,
    }
    // 提供一个函数,用来返回相应的context对象
    getChildContext() {
    return {
    color: 'red',
    };
    }
    render() {
    const { list } = this.props;
    return (


      {
      list.map((entry, index) =>
      `list-${index}`} value={entry.text} />,

      )
      }
      </ul>
      div>
      );
      }
      }

      export default List;


      // App.jsx

      import React, { Component } from 'react';
      import List from './components/List';

      const list = [
      {
      text: '题目一',
      },
      {
      text: '题目二',
      },
      ];
      export default class App extends Component {
      render() {
      return (


      list={list}
      />
      </div>
      );
      }
      }

      四、没有嵌套关系的组件通信

      使用自定义事件机制

      • componentDidMount事件中,如果组件挂载完成,再订阅事件;在组件卸载的时候,在componentWillUnmount事件中取消事件的订阅;
      • 以常用的发布/订阅模式举例,借用node.js Events模块的浏览器版实现

      下面例子中的组件关系: List1 和 List2 没有任何嵌套关系,App 是他们的父组件

      实现这样一个功能: 点击 List2 中的一个按钮,改变 List1 中的信息显示

      1
      npm install events --save

      在 src 下新建一个 util 目录里面建一个 events.js

      1
      2
      3
      import { EventEmitter } from 'events';

      export default new EventEmitter();
      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
      // List.jsx
      class List extends Component {
      constructor(props) {
      super(props);
      this.state = {
      message: 'List1',
      };
      }
      componentDidMount() {
      // 组件装载完成以后声明一个自定义事件
      this.eventEmitter = emitter.addListener('changeMessage', (message) => {
      this.setState({
      message,
      });
      });
      }
      componentWillUnmount() {
      emitter.removeListener(this.eventEmitter);
      }
      render() {
      return (

      {this.state.message}
      </div>
      );
      }
      }

      export default List;

      //List2.jsx
      import React, { Component } from 'react';
      import emitter from '../util/events';

      class List2 extends Component {
      handleClick = (message) => {
      emitter.emit('changeMessage', message);
      };
      render() {
      return (