在 React Native(RN)里,"原生事件监听"和"全局事件通知"通常分两类:
- Native → JS 事件通知(原生主动通知 RN)
- JS 全局事件总线(RN 内部模块间通信)
下面分别讲。
一、Native → JS 原生事件监听
典型场景:
- Android 原生收到推送
- 蓝牙状态变化
- GPS 定位变化
- 登录状态变化
- 支付结果回调
- 原生 SDK 回调
流程:
yaml
Android/iOS
|
| sendEvent
↓
React Native Bridge / JSI
|
↓
JavaScript EventEmitter
|
↓
addListener()
Android 示例
1. 原生 Module 发送事件
Java:
scala
public class MyNativeModule extends ReactContextBaseJavaModule {
private ReactApplicationContext context;
public MyNativeModule(ReactApplicationContext reactContext) {
super(reactContext);
this.context = reactContext;
}
@Override
public String getName() {
return "MyNativeModule";
}
public void sendLoginEvent(String token) {
context
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(
"LoginSuccess",
token
);
}
}
这里:
scss
emit(
"LoginSuccess",
token
)
就是发送 RN 事件。
2. JS 监听
javascript
import {
DeviceEventEmitter
} from 'react-native';
useEffect(()=>{
const listener =
DeviceEventEmitter.addListener(
'LoginSuccess',
(token)=>{
console.log(
"登录成功",
token
);
}
);
return ()=>{
listener.remove();
}
},[])
效果:
makefile
Android:
emit("LoginSuccess","abc")
JS:
收到
token="abc"
iOS 示例
Objective-C:
objectivec
#import <React/RCTEventEmitter.h>
@interface MyEventEmitter : RCTEventEmitter
@end
@implementation MyEventEmitter
RCT_EXPORT_MODULE();
- (NSArray<NSString *> *)supportedEvents
{
return @[
@"LoginSuccess"
];
}
- (void)sendLogin:(NSString *)token
{
[self sendEventWithName:
@"LoginSuccess"
body:token];
}
@end
JS:
ini
import {
NativeEventEmitter,
NativeModules
} from 'react-native';
const emitter =
new NativeEventEmitter(
NativeModules.MyEventEmitter
);
const sub =
emitter.addListener(
"LoginSuccess",
token=>{
console.log(token)
}
);
sub.remove();
二、RN 内部全局事件通知
比如:
css
页面A登录
↓
通知
↓
页面B刷新用户信息
不需要 Native。
常用方案:
方案1:EventEmitter 全局事件总线
安装:
npm install eventemitter3
创建:
bash
src/utils/EventBus.js
arduino
import EventEmitter from 'eventemitter3';
export default new EventEmitter();
发送:
python
import EventBus from './EventBus';
EventBus.emit(
"USER_LOGIN",
{
id:100
}
);
监听:
javascript
import EventBus from './EventBus';
useEffect(()=>{
const handler=(user)=>{
console.log(user)
}
EventBus.on(
"USER_LOGIN",
handler
);
return ()=>{
EventBus.off(
"USER_LOGIN",
handler
);
}
},[])
结构:
scss
EventBus
A页面
emit()
|
|
↓
USER_LOGIN
|
|
↓
B页面
on()
三、React Native 推荐方案
现在 RN 项目一般不会大量使用 EventBus。
更推荐:
| 场景 | 推荐 |
|---|---|
| 组件状态共享 | Zustand |
| 复杂业务状态 | Redux Toolkit |
| 服务器数据 | React Query |
| Native通知JS | NativeEventEmitter |
| 简单跨页面通知 | EventEmitter |
例如登录:
不推荐:
csharp
LoginPage
EventBus.emit("LOGIN")
HomePage
EventBus.on("LOGIN")
推荐:
csharp
Zustand
login()
|
|
user={name:"张三"}
|
|
所有组件自动更新
四、RN 新架构 Fabric / TurboModule 下
你之前问过 Fabric,这里补充:
旧架构:
arduino
Native
|
Bridge
|
JS
事件:
scss
emit()
↓
Bridge Queue
↓
JS EventEmitter
新架构:
yaml
Native Module
|
|
JSI
|
|
JavaScript Runtime
通信更直接。
但是:
DeviceEventEmitterNativeEventEmitter
仍然大量存在。
TurboModule 推荐:
php
interface Spec extends TurboModule {
addListener(
eventName:string
):void;
removeListeners(
count:number
):void;
}
然后:
arduino
NativeModule.addListener(
"EVENT"
)
五、实际项目架构建议
例如 App:
markdown
Native
推送SDK
蓝牙SDK
支付SDK
登录SDK
|
|
↓
NativeEventEmitter
|
|
↓
event adapter
|
|
↓
Zustand / Redux
|
|
↓
React Components
不要让页面直接监听 Native。
推荐:
Native
↓
Service层
↓
Store
↓
页面
这样维护性最好。
如果你是想实现类似微信桌面端扫码登录那种"原生扫码成功通知 RN 页面刷新" ,一般就是 NativeEventEmitter + 状态管理(Store) 这一套。你前面问过微信扫码登录,这个场景正好对应。