React 中组件之间的通信方式

组件间通信方式

在使用 React 的过程中,经常需要组件之间相互传递信息,故记录一下组件间的常用通信方式:

  1. 父组件向子组件通信
    父组件向子组件传递 props, 子组件通过获取 props 中的内容得到父组件传递的信息;
    示例:父组件(App)向子组件(Root)通信

    import Root from "./components/Root";
    
    const App = (props) => {
      return (
    	<div className="app">
    	  {/* 
    		向自定义组件(Root)设置(msg)属性;
    		自定义组件(Root)会将所接收到的属性(attributes)和子组件(children)
    		转换为单个对象(props)传递给组件;
    	   */}
    	  <Root msg="this is a test message" />
    	</div>
      );
    }
    
    // 父组件 App
    export default App;
    
    const Root = (props) => {
    	// 获取父组件传递的msg属性值
    	const msg = props.msg;
    	return (
    		<div className="root">
    			{msg}  {/* this is a test message */}
    		</div>
    	);
    }
    
    // 子组件 Root
    export default Root;
    
  2. 子组件向父组件通信
    父组件向子组件传递一个回调函数属性, 子组件通过调用父组件传递的回调函数实现子组件向父组件通信;
    示例:子组件(Root)向父组件(App)通信

    import Root from "./components/Root";
    
    const App = (props) => {
      const getName = (name) => {
    	// my name is root
    	console.log(name);
      }
      return (
    	<div className="app">
    	  {/*向子组件传递callback属性,属性值为一个回调函数 */}
    	  <Root callback={getName} />
    	</div>
      );
    }
    
    // 父组件 App
    export default App;
    
    const Root = (props) => {
    	// 获取父组件传递的callback属性值(getName函数)
    	const getName = props.callback;
    	const name = "my name is Root";
    	// 调用getName函数
    	getName && getName(name);
    	return null;
    }
    
    // 子组件 Root
    export default Root;
    
  3. 跨级组件间通信
    跨级组件是指父组件的子组件的子组件,或者更深层的嵌套关系,跨级组件之间想要通信,有两种常见方式:

    1. 中间组件层层传递
    2. 使用 Context 对象

    示例:顶层组件 App 向"孙子"级组件 Content 通信

    import React from "react";
    import Root from "./components/Root";
    
    const App = (props) => {
      const context = {
    	name: "赵云"
      }
      return (
    	// Provider(生产者)共享容器,在顶层传入value
    	<App.Context.Provider value={context}>
    	  <div className="app">
    		<Root />
    	  </div>
    	</App.Context.Provider>
      );
    }
    
    // 创建一个Context
    App.Context = React.createContext();
    
    // 顶层组件 App
    export default App;
    
    import Content from "./Content";
    
    const Root = (props) => {
    	return (
    		// 中间组件
    		<Content />
    	);
    }
    
    // 中间组件 Root
    export default Root;
    
    import App from '../App';
    
    const Content = (props) => {
    	return (
    		// Consumer(消费者)容器,可以获取从顶层传递的context
    		<App.Context.Consumer>
    			{/* 以函数的方式使用context */}
    			{context => (
    				<div className='content'>
    					{context.name}  {/* 赵云 */}
    				</div>
    			)}
    		</App.Context.Consumer>
    	);
    }
    
    // 目标通信组件 Content
    export default Content;
    
  4. 非嵌套组件间通信
    非嵌套组件,就是通信组件间没有任何包含关系,包括兄弟组件以及不在同一个父级中的非兄弟组件;对于非嵌套组件,可以利用这两种方式通信:

    1. 利用二者共同父组件的 context 对象进行通信
    2. 使用自定义事件的方式
      如果采用组件间共同的父级来进行中转,会增加子组件和父组件之间的耦合度,如果组件层次较深的话,找到二者公共的父组件不是一件容易的事;

    使用自定义事件的方式来实现非嵌套组件间的通信。

    示例:Root 组件向 Content 组件通信

    # 这里需要一个 events 依赖来做发布订阅动作
    npm install events --save
    
    import React from "react";
    import Root from "./components/Root";
    import Content from "./components/Content";
    
    const App = (props) => {
      return (
    	  <div className="app">
    		<Root />
    		<Content />
    	  </div>
      );
    }
    
    // 顶层组件 App
    export default App;
    
    import React from 'react';
    import emitter from "./event";
    
    const Root = (props) => {
    	// 初始化 state, 相当于 class 组件中的 this.state = {rootName: ""}
    	const [rootName, setRootName] = React.useState("");
    
    	// 监听 setRootName 事件的回调函数 
    	const setRootNameCallback = (name) => {
    		setRootName(name);
    	}
    
    	// 类似于类组件中的 componentDidMount
    	React.useEffect(() => {
    		emitter.addListener("setRootName", setRootNameCallback);
    	}, []);
    
    	// 类似于类组价中 componentWillUnmout
    	React.useEffect(() => {
    		// 组件卸载移除监听
    		return () => {
    			emitter.removeListener("setRootName", setRootNameCallback);
    		}
    	});
    
    	return (
    		// 兄弟组件
    		<div className="root">
    			{rootName}  {/* 赵云 */}
    		</div>
    	);
    }
    
    // 兄弟组件 Root
    export default Root;
    
    import React from "react";
    import emitter from "./event";
    
    const Content = (props) => {
    
    	// 类似于类组件中的 componentDidMount
    	React.useEffect(() => {
    		// 触发 setRootName 事件,向订阅者传值;
    		emitter.emit("setRootName", "赵云");
    	}, []);
    
    	return (
    		// 兄弟组件
    		<div className="content">
    
    		</div>
    	);
    }
    
    // 兄弟组件 Content
    export default Content;
    

总结

本文记录了不同嵌套关系的组件间常用的几种通信方式:

  1. 父子嵌套关系:利用 props 对象实现父组件向子组件通信;
  2. 父子嵌套关系:利用 callback(回调函数) 实现子组件向父组件通信;
  3. 多层(父子)嵌套关系(跨级通信):利用 Context 对象, 以生产者和消费者的方式实现通信;
  4. 非嵌套关系:利用 events (发布订阅) 的方式实现通信;

如果项目比较大,嵌套关系比较复杂,state 就会变得难以管理,就需要考虑使用 Redux 库管理状态;

参考学习博客

React 中组件间通信的几种方式

posted @ 2022-03-25 10:14  太轻描淡写了  阅读(1152)  评论(0编辑  收藏  举报