React Native:使用 redux saga eventChannel 从组件外部化事件监听器
React Native: using redux saga eventChannel to externalise event listeners from components
Redux saga eventChannel
是一个非常优雅的解决方案,可以从组件代码外部连接到外部事件,使它们更简洁明了。一个用例可能是对全局应用程序状态变化做出反应,例如应用程序在前台、后台、不活动...
我担心 React Native 的退订过程。
在组件内部,componentWillUnmount
是执行取消订阅的地方,因此我们有一些 UI 钩子可以保证我们成功移除侦听器。
例如,当我应用以下代码来跟踪应用程序状态变化(活动、非活动或后台)时,我是否会面临内存泄漏?
type NextAppState = 'active' | 'inactive' | 'background';
function createAppStateChannel() {
return eventChannel((emit: (nextState: NextAppState) => mixed) => {
AppState.addEventListener('change', emit);
return () => {
AppState.removeEventListener('change', emit);
};
});
}
export function* appStateListenerSaga(): Generator<*, *, *> {
try {
const appStateChannel = yield call(createAppStateChannel);
while (true) {
const nextAppState: NextAppState = yield take(appStateChannel);
if (nextAppState === 'active') {
// Do something, like syncing with server
}
} finally {
if (yield cancelled()) {
appStateChannel.close();
}
}
}
我正在考虑 JS 上下文由于某种原因被杀死的情况。
我担心的是 sagas 不会被取消(据我所知),不会执行取消订阅,因此本机侦听器将保持注册状态。下次重新打开应用程序时,我们将注册一个重复的事件侦听器等等。
任何人都可以指出这是安全的还是使用 HOC 基本上更好?我也在使用 react-native-navigation ,其中有几个反应根视图(每个屏幕一个),这就是为什么 HOC 不适合这种情况,因为我必须用 HOC 包装每个父屏幕,如果我将 3 个屏幕推入堆栈,在应用程序恢复时,逻辑将执行 3 次。
显然这取决于本机模块的实现。
如果原生模块只保留一个监听器,所有的订阅都在JS端管理,那不是问题。
但是,如果在本机端处理新的侦听器,由于内存泄漏,JS 上下文被杀死将是一个问题。
在 JS 端保持订阅的两个模块的示例是 AppState
和 BackHandler
。两者都在本机端保留一个全局侦听器,在 JS 端保留多个订阅者,因此两者都可以安全地与 redux-saga eventChannel
.
一起使用
您可以在这里查看 AppState
的源代码作为示例:https://github.com/facebook/react-native/blob/master/Libraries/AppState/AppState.js
我还没有偶然发现相反的模块。
根据经验,只需浏览 github 源代码上的模块即可了解如何管理订阅。
Redux saga eventChannel
是一个非常优雅的解决方案,可以从组件代码外部连接到外部事件,使它们更简洁明了。一个用例可能是对全局应用程序状态变化做出反应,例如应用程序在前台、后台、不活动...
我担心 React Native 的退订过程。
在组件内部,componentWillUnmount
是执行取消订阅的地方,因此我们有一些 UI 钩子可以保证我们成功移除侦听器。
例如,当我应用以下代码来跟踪应用程序状态变化(活动、非活动或后台)时,我是否会面临内存泄漏?
type NextAppState = 'active' | 'inactive' | 'background';
function createAppStateChannel() {
return eventChannel((emit: (nextState: NextAppState) => mixed) => {
AppState.addEventListener('change', emit);
return () => {
AppState.removeEventListener('change', emit);
};
});
}
export function* appStateListenerSaga(): Generator<*, *, *> {
try {
const appStateChannel = yield call(createAppStateChannel);
while (true) {
const nextAppState: NextAppState = yield take(appStateChannel);
if (nextAppState === 'active') {
// Do something, like syncing with server
}
} finally {
if (yield cancelled()) {
appStateChannel.close();
}
}
}
我正在考虑 JS 上下文由于某种原因被杀死的情况。
我担心的是 sagas 不会被取消(据我所知),不会执行取消订阅,因此本机侦听器将保持注册状态。下次重新打开应用程序时,我们将注册一个重复的事件侦听器等等。
任何人都可以指出这是安全的还是使用 HOC 基本上更好?我也在使用 react-native-navigation ,其中有几个反应根视图(每个屏幕一个),这就是为什么 HOC 不适合这种情况,因为我必须用 HOC 包装每个父屏幕,如果我将 3 个屏幕推入堆栈,在应用程序恢复时,逻辑将执行 3 次。
显然这取决于本机模块的实现。
如果原生模块只保留一个监听器,所有的订阅都在JS端管理,那不是问题。
但是,如果在本机端处理新的侦听器,由于内存泄漏,JS 上下文被杀死将是一个问题。
在 JS 端保持订阅的两个模块的示例是 AppState
和 BackHandler
。两者都在本机端保留一个全局侦听器,在 JS 端保留多个订阅者,因此两者都可以安全地与 redux-saga eventChannel
.
您可以在这里查看 AppState
的源代码作为示例:https://github.com/facebook/react-native/blob/master/Libraries/AppState/AppState.js
我还没有偶然发现相反的模块。 根据经验,只需浏览 github 源代码上的模块即可了解如何管理订阅。