React中組件通信的幾種方式
首次發表在個人博客
需要組件之進行通信的幾種情況
- 父組件向子組件通信
- 子組件向父組件通信
- 跨級組件通信
- 沒有嵌套關係組件之間的通信
1. 父組件向子組件通信
React數據流動是單向的,父組件向子組件通信也是最常見的;父組件通過props向子組件傳遞需要的信息
Child.jsximport React from react;nimport PropTypes from prop-types;nnexport default function Child({ name }) {n return <h1>Hello, {name}</h1>;n}nnChild.propTypes = {n name: PropTypes.string.isRequired,n};n
Parent.jsx
import React, { Component } from react;nnimport Child from ./Child;nnclass Parent extends Component {n render() {n return (n <div> <Child name="Sara" /> </div>n );n }n}nnexport default Parent;n
2. 子組件向父組件通信
- 利用回調函數
- 利用自定義事件機制
回調函數
實現在子組件中點擊隱藏組件按鈕可以將自身隱藏的功能
List3.jsx
import React, { Component } from react;nimport PropTypes from prop-types;nnclass List3 extends Component {n static propTypes = {n hideConponent: PropTypes.func.isRequired,n }n render() {n return (n <div>n 哈哈,我是List3n <button onClick={this.props.hideConponent}>隱藏List3組件</button> </div>n );n }n}nnexport default List3;n
App.jsx
import React, { Component } from react;nnimport List3 from ./components/List3;nexport default class App extends Component {n constructor(...args) {n super(...args);n this.state = {n isShowList3: false,n };n }n showConponent = () => {n this.setState({n isShowList3: true,n });n }n hideConponent = () => {n this.setState({n isShowList3: false,n });n }n render() {n return (n <div> <button onClick={this.showConponent}>顯示Lists組件</button>n {n this.state.isShowList3 ?n <List3 hideConponent={this.hideConponent} />n :n nulln }nn </div>n );n }n}n
觀察一下實現方法,可以發現它與傳統回調函數的實現方法一樣.而且setState一般與回調函數均會成對出現,因為回調函數即是轉換內部狀態是的函數傳統;
3. 跨級組件通信
- 層層組件傳遞props
例如A組件和B組件之間要進行通信,先找到A和B公共的父組件,A先向C組件通信,C組件通過props和B組件通信,此時C組件起的就是中間件的作用
- 使用context
context是一個全局變數,像是一個大容器,在任何地方都可以訪問到,我們可以把要通信的信息放在context上,然後在其他組件中可以隨意取到;
但是React官方不建議使用大量context,儘管他可以減少逐層傳遞,但是當組件結構複雜的時候,我們並不知道context是從哪裡傳過來的;而且context是一個全局變數,全局變數正是導致應用走向混亂的罪魁禍首.使用context
下面例子中的組件關係: ListItem是List的子組件,List是app的子組件
ListItem.jsx
import React, { Component } from react;nimport PropTypes from prop-types;nnclass ListItem extends Component {n // 子組件聲明自己要使用n context static contextTypes = {n color: PropTypes.string,n }n static propTypes = {n value: PropTypes.string,n }n render() {n const { value } = this.props;n return (n <li stylex={{ background: this.context.color }}> n <span>{value}</span> n </li>n );n }n}nnexport default ListItem;n
List.jsx
import ListItem from ./ListItem;nnclass List extends Component {n // 父組件聲明自己支持n context static childContextTypes = {n color: PropTypes.string,n }n static propTypes = {n list: PropTypes.array,n }n // 提供一個函數,用來返回相應的context對象n getChildContext() {n return {n color: red,n };n }n render() {n const { list } = this.props;n return (n <div> <ul>n {n list.map((entry, index) =>n <ListItem key={`list-${index}`} value={entry.text} />,n )n }n </ul> </div>n );n }n}nnexport default List;n
App.jsx
import React, { Component } from react;nimport List from ./components/List;nnconst list = [n {n text: 題目一,n },n {n text: 題目二,n },n];nexport default class App extends Component {n render() {n return (n <div> n <List list={list} /> n </div>n );n }n}n
4. 沒有嵌套關係的組件通信
- 使用自定義事件機制
在componentDidMount事件中,如果組件掛載完成,再訂閱事件;在組件卸載的時候,在componentWillUnmount事件中取消事件的訂閱;
以常用的發布/訂閱模式舉例,借用Node.js Events模塊的瀏覽器版實現
使用自定義事件的方式
下面例子中的組件關係: List1和List2沒有任何嵌套關係,App是他們的父組件;
實現這樣一個功能: 點擊List2中的一個按鈕,改變List1中的信息顯示
首先需要項目中安裝events 包:npm install events --saven
在src下新建一個util目錄裡面建一個events.js
import { EventEmitter } from events;nnexport default new EventEmitter();n
list1.jsx
import React, { Component } from react;nimport emitter from ../util/events;nnclass List extends Component {n constructor(props) {n super(props);n this.state = {n message: List1,n };n }n componentDidMount() {n // 組件裝載完成以後聲明一個自定義事件 this.eventEmitter = emitter.addListener(changeMessage, (message) => {n this.setState({n message,n });n });n }n componentWillUnmount() {n emitter.removeListener(this.eventEmitter);n }n render() {n return (n <div>n {this.state.message}n </div>n );n }n}nnexport default List;n
List2.jsx
import React, { Component } from react;nimport emitter from ../util/events;nnclass List2 extends Component {n handleClick = (message) => {n emitter.emit(changeMessage, message);n };n render() {n return (n <div> <button onClick={this.handleClick.bind(this, List2)}>點擊我改變List1組件中顯示信息</button> </div>n );n }n}n
APP.jsx
import React, { Component } from react;nimport List1 from ./components/List1;nimport List2 from ./components/List2;nnnexport default class App extends Component {n render() {n return (n <div> <List1 /> <List2 /> </div>n );n }n}n
自定義事件是典型的發布訂閱模式,通過向事件對象上添加監聽器和觸發事件來實現組件之間的通信。
總結
- 父組件向子組件通信: props
- 子組件向父組件通信: 回調函數/自定義事件
- 跨級組件通信: 層層組件傳遞props/context
- 沒有嵌套關係組件之間的通信: 自定義事件
推薦閱讀:
※阿里還會使用react嗎?
※說說對react中JSX語法的理解?
※沒有安卓和ios開發經驗的前端適合學rn嗎?
※基於 Webpack 的應用包體尺寸優化
※React 16 的異常/錯誤處理
TAG:React |