教育局门户网站建设目的邱县企业做网站推广
目录
前言
正文
父组件向子组件传值
函数式写法
类式写法
子组件向父组件传值
函数式写法
类式写法
兄弟组件通信
函数式写法
类式写法
跨层级通信(使用Context)
函数式写法
类式写法
进阶通讯方式(补充说明)
一、事件总线:使用 EventEmitter
实现步骤:
二、Ref 传递:forwardRef + useImperativeHandle
实现步骤:
总结
事件总线(EventEmitter):
Ref 传递(forwardRef + useImperativeHandle):
结语
前言
在现代前端开发中,React 作为最流行的 JavaScript 库之一,以其组件化、声明式编程和高性能的特点,成为构建用户界面的首选工具。然而,随着应用复杂度的提升,组件之间的通信问题逐渐成为开发者需要面对的核心挑战之一。无论是父子组件之间的数据传递,还是跨层级组件的状态共享,如何高效、优雅地实现组件间的通信,直接影响到代码的可维护性和应用的性能。
React 提供了多种组件通信的方式,以下是几种常见的模式:
-
Props 传递:父组件通过 props 向子组件传递数据。
-
回调函数:子组件通过回调函数向父组件传递数据。
-
Context API:用于跨层级组件之间的数据共享。
-
状态提升:将共享状态提升到共同的父组件中。
-
Ref 和事件机制:用于直接操作组件或触发事件。
接下来,我们将从 函数式组件 和 类式组件 两个角度,详细讲解这些通信方式的具体实现。
正文
父组件向子组件传值
函数式写法
// 父组件
function ParentComponent() {const [message] = useState('来自父组件的消息');return <ChildComponent message={message} />;
}// 子组件
function ChildComponent({ message }) {return <div>{message}</div>;
}
类式写法
// 父组件
class ParentComponent extends React.Component {state = { message: '来自父组件的消息' };render() {return <ChildComponent message={this.state.message} />;}
}// 子组件
class ChildComponent extends React.Component {render() {return <div>{this.props.message}</div>;}
}
子组件向父组件传值
函数式写法
// 父组件
function ParentComponent() {const handleChildData = (data) => {console.log('收到子组件数据:', data);};return <ChildComponent sendData={handleChildData} />;
}// 子组件
function ChildComponent({ sendData }) {const sendMessage = () => {sendData('子组件发送的消息');};return <button onClick={sendMessage}>发送消息</button>;
}
类式写法
// 父组件
class ParentComponent extends React.Component {handleChildData = (data) => {console.log('收到子组件数据:', data);};render() {return <ChildComponent sendData={this.handleChildData} />;}
}// 子组件
class ChildComponent extends React.Component {sendMessage = () => {this.props.sendData('子组件发送的消息');};render() {return <button onClick={this.sendMessage}>发送消息</button>;}
}
兄弟组件通信
函数式写法
function Parent() {const [sharedData, setSharedData] = useState('');return (<><SiblingA setData={setSharedData} /><SiblingB data={sharedData} /></>);
}function SiblingA({ setData }) {return <input onChange={(e) => setData(e.target.value)} />;
}function SiblingB({ data }) {return <div>接收到的数据: {data}</div>;
}
类式写法
class Parent extends React.Component {state = { sharedData: '' };setSharedData = (data) => {this.setState({ sharedData: data });};render() {return (<><SiblingA setData={this.setSharedData} /><SiblingB data={this.state.sharedData} /></>);}
}class SiblingA extends React.Component {handleChange = (e) => {this.props.setData(e.target.value);};render() {return <input onChange={this.handleChange} />;}
}class SiblingB extends React.Component {render() {return <div>接收到的数据: {this.props.data}</div>;}
}
跨层级通信(使用Context)
函数式写法
const MyContext = createContext();function App() {return (<MyContext.Provider value="全局数据"><MiddleComponent /></MyContext.Provider>);
}function MiddleComponent() {return <ChildComponent />;
}function ChildComponent() {const value = useContext(MyContext);return <div>{value}</div>;
}
类式写法
const MyContext = React.createContext();class App extends React.Component {render() {return (<MyContext.Provider value="全局数据"><MiddleComponent /></MyContext.Provider>);}
}class MiddleComponent extends React.Component {render() {return <ChildComponent />;}
}class ChildComponent extends React.Component {static contextType = MyContext;render() {return <div>{this.context}</div>;}
}
进阶通讯方式(补充说明)
-
状态管理方案:Redux/MobX
-
事件总线:使用EventEmitter
-
Ref传递:forwardRef + useImperativeHandle
-
状态库:Recoil/Zustand
一、事件总线
事件总线是一种跨组件通信的方式,适用于任意组件之间的通信,尤其是非父子关系的组件。通过事件总线,组件可以订阅和触发事件,从而实现数据传递。
这里用了一个mitt,所以要下载一个依赖
npm i mitt
实现步骤:
-
创建一个全局的事件总线。
-
在需要接收数据的组件中订阅事件。
-
在需要发送数据的组件中触发事件。
import React, { useEffect, useState } from 'react';
import mitt from 'mitt'// 创建全局事件总线
const eventBus = mitt()// 组件A:发送事件
function ComponentA() {const sendMessage = () => {eventBus.emit('message', 'Hello from ComponentA!')}return (<div><button onClick={sendMessage}>发送消息</button></div>)
}// 组件B:接收事件
function ComponentB() {const [message, setMessage] = useState('')useEffect(() => {// 订阅事件function isString(value: any): value is string {return typeof value === 'string'}const handleMessage = (data: any) => {if (isString(data)) {setMessage(data)}}eventBus.on('message', handleMessage)// 清理订阅return () => {eventBus.off('message', handleMessage)}}, [])return (<div><p>接收到的消息: {message}</p></div>)
}// 父组件
function App() {return (<div><ComponentA /><ComponentB /></div>);
}export default App;
二、Ref 传递:forwardRef + useImperativeHandle
forwardRef
和 useImperativeHandle
是 React 提供的用于操作子组件实例的 API。通过它们,父组件可以访问子组件的特定方法或属性。
实现步骤:
-
使用
forwardRef
包裹子组件,使其能够接收ref
。 -
在子组件中使用
useImperativeHandle
暴露特定的方法或属性。 -
在父组件中通过
ref
调用子组件的方法。
import React, { useRef, useImperativeHandle, forwardRef } from 'react';interface ChildComponentRef {increment: () => voidgetCount: () => number
}// 子组件
const ChildComponent = forwardRef<ChildComponentRef>((props, ref) => {const [count, setCount] = useState(0)// 暴露方法给父组件useImperativeHandle(ref, () => ({increment: () => {setCount((prevCount) => prevCount + 1)},getCount: () => {return count},}))return (<div><p>子组件计数: {count}</p></div>)
})// 父组件
function ParentComponent() {const childRef = useRef<ChildComponentRef>(null)const handleIncrement = () => {if (childRef.current) {childRef.current.increment() // 调用子组件的 increment 方法}}const handleGetCount = () => {if (childRef.current) {alert('当前计数: ' + childRef.current.getCount()) // 调用子组件的 getCount 方法}}return (<div><ChildComponent ref={childRef} /><button onClick={handleIncrement}>增加计数</button><button onClick={handleGetCount}>获取计数</button></div>)
}
export default ParentComponent;
总结
事件总线(EventEmitter):
-
适用于任意组件之间的通信。
-
需要手动管理事件的订阅和清理。
-
适合非父子关系的组件通信。
Ref 传递(forwardRef + useImperativeHandle):
-
适用于父组件需要直接操作子组件方法或属性的场景。
-
通过
useImperativeHandle
暴露特定的方法,保持组件的封装性。 -
适合需要直接操作 DOM 或子组件逻辑的场景。
结语
希望本文的内容对你有用呦!