直接调用 store.dispatch() 的替代方法
Alternative to direct calling of store.dispatch()
由于在最新的 redux-observable (0.17) 中直接调用 store.dispatch() 已弃用,我想知道如果我需要从我的 redux 应用程序外部调度操作,还有什么替代方法。
示例:
假设我有这个函数可以初始化本机模块并设置本机处理程序。
const configure = (dispatch) => {
const printingModule = NativeModules.PrintingManager
const eventEmitter = new NativeEventEmitter(printingModule)
eventEmitter.addListener(
"PrintingManagerNewPrinterConnected",
(payload) => dispatch({
type: PRINTER_MANAGER_NEW_PRINTER_CONNECTED,
payload: {
macAddress: payload[2],
connectionType: payload[3],
},
}))
printingModule.initialize()
}
我通常做的是在类似 APP_STARTUP_FINISHED:
之后从 observable 调用这个函数
const appStatePrepared = (action$: Object, { dispatch }) =>
action$.ofType(APP_STATE_PREPARED)
.switchMap(() => {
configurePrinters(dispatch)
})
正确的解决方法是什么?
谢谢!
当使用 RxJS 时,理想的是组合流。所以在这种情况下,我们需要一些如何创建 "PrintingManagerNewPrinterConnected"
事件流,然后我们可以将每个事件映射到它们自己的 PRINTER_MANAGER_NEW_PRINTER_CONNECTED
action.a
让我们先学习如何完全自定义。
自定义 Observables
创建您自己的自定义 Observables 与创建 Promise 非常相似。假设你有世界上最简单的 Promise,它立即解析为数字 1
const items = new Promise(resolve => {
resolve(1);
});
等效的 Observable 看起来超级相似
const items = new Observable(observer => {
observer.next(1);
observer.complete();
});
在视觉上,主要区别在于我们没有传递 (resolve, reject)
回调,而是获得了一个观察者,因为有下一个、错误和完成。
语义上,Observables 可以通过多次调用 observer.next
来表示多个值,直到它们调用 observer.complete()
来表示流的结束;这与仅表示单个值的 Promises 形成对比。
默认情况下,Observables 也是惰性和同步的,而 Promises 总是急切的和异步的。
既然我们已经有了这样的理解,我们想接受它并包装您的 NativeEventEmitter
API,它使用 addEventListener
.
const configurePrinters = () => {
return new Observable(observer => {
const printingModule = NativeModules.PrintingManager;
const eventEmitter = new NativeEventEmitter(printingModule);
eventEmitter.addListener(
'PrintingManagerNewPrinterConnected',
(payload) => observer.next(payload)
);
printingModule.initialize();
});
};
configurePrinters()
.subscribe(payload => console.log(payload));
这有效而且非常简单,但它有一个问题:我们应该在他们取消订阅时调用 removeListener
以便我们自己清理并且不会泄漏内存。
为此,我们需要 return 在我们的自定义 Observable 中进行订阅。此上下文中的订阅是一个 object,上面有一个 unsubscribe()
方法,当订阅者取消订阅、触发错误或您的可观察对象完成时,将自动调用该方法。这是你清理的机会。
const items = new Observable(observer => {
let i = 0;
const timer = setInterval(() => {
observer.next(i++);
}, 1000);
// return a subscription that has our timer cleanup logic
return {
unsubscribe: () => {
clearInterval(timer);
}
};
});
因为 return 一个 object 有点冗长 RxJS 支持一个 shorthand 你只是 return 一个函数本身将被视为 unsubscribe
方法。
const items = new Observable(observer => {
let i = 0;
const timer = setInterval(() => {
observer.next(i++);
}, 1000);
// return an "unsubscribe" function that has our timer cleanup logic
return () => {
clearInterval(timer);
};
});
现在我们可以将其应用到我们的示例中,我们希望在调用取消订阅拆解函数时删除我们的侦听器。
const configurePrinters = () => {
return new Observable(observer => {
const printingModule = NativeModules.PrintingManager;
const eventEmitter = new NativeEventEmitter(printingModule);
const listener = (payload) => observer.next(payload);
eventEmitter.addListener(
'PrintingManagerNewPrinterConnected',
listener
);
printingModule.initialize();
return () => eventEmitter.removeListener(
'PrintingManagerNewPrinterConnected',
listener
);
});
};
现在让我们把它变成一个可重用的实用函数
const fromPrinterEvent = (eventName) => {
return new Observable(observer => {
const printingModule = NativeModules.PrintingManager;
const eventEmitter = new NativeEventEmitter(printingModule);
const listener = (payload) => observer.next(payload);
eventEmitter.addListener(eventName, listener);
printingModule.initialize();
return () => eventEmitter.removeListener(eventName, listener);
});
};
fromPrinterEvent('PrintingManagerNewPrinterConnected')
.subscribe(payload => console.log(payload));
Observable.fromEvent
虽然 NativeEventEmitter
是 react-native 的东西,但它跟在 node-style EventEmitter interface and RxJS already comes with a utility helper to create an Observable from them to save you the effort. It's called fromEvent
之后,位于 Observable.fromEvent
或 import { fromEvent } from 'rxjs/observables/fromEvent'
.
const fromPrinterEvent = (eventName) => {
return Observable.defer(() => {
const printingModule = NativeModules.PrintingManager;
const eventEmitter = new NativeEventEmitter(printingModule);
printingModule.initialize();
return Observable.fromEvent(eventEmitter, eventName);
});
};
这里我也将它包装在 Observable.defer
中,这样我们就不会创建 NativeEventEmitter
或 printingModule.initialize()
直到有人真正订阅(保持懒惰)。这对您来说可能是必要的,也可能不是必要的,我不知道 PrintingManager 的作用或行为方式。例如可能只需要创建一个发射器并预先初始化模块。
const printingModule = NativeModules.PrintingManager;
const printerEmitter = new NativeEventEmitter(printingModule);
printingModule.initialize();
const fromPrinterEvent = (eventName) =>
Observable.fromEvent(printerEmitter, eventName);
所以请记住,我只是在展示模式而不知道 PrintingManager 等的作用。
在redux-observable
内使用
在 redux-observable 中使用它,您的史诗现在与您使用任何其他 Observable 一样。所以我们希望将它的值映射到操作和
mergeMap、switchMap、concatMap 或 exhaustMap 到我们的 top-level 流中。
像这样:
const appStatePrepared = action$ =>
action$.ofType(APP_STATE_PREPARED)
.switchMap(() =>
fromPrinterEvent('PrintingManagerNewPrinterConnected')
.map(payload => ({
type: PRINTER_MANAGER_NEW_PRINTER_CONNECTED,
payload: {
macAddress: payload[2],
connectionType: payload[3],
}
}))
);
请记住,包括我们的习惯 fromPrinterEvent('PrintingManagerNewPrinterConnected')
在内的许多信息流将永远存在,直到您取消订阅它们。所以如果你只想要一个,你会使用 .take(1)
。如果你想在收到另一个操作时取消订阅,你可以使用 .takeUntil(action$.ofType(WHATEVER))
,等等。正常的 RxJS 模式。
由于在最新的 redux-observable (0.17) 中直接调用 store.dispatch() 已弃用,我想知道如果我需要从我的 redux 应用程序外部调度操作,还有什么替代方法。
示例:
假设我有这个函数可以初始化本机模块并设置本机处理程序。
const configure = (dispatch) => {
const printingModule = NativeModules.PrintingManager
const eventEmitter = new NativeEventEmitter(printingModule)
eventEmitter.addListener(
"PrintingManagerNewPrinterConnected",
(payload) => dispatch({
type: PRINTER_MANAGER_NEW_PRINTER_CONNECTED,
payload: {
macAddress: payload[2],
connectionType: payload[3],
},
}))
printingModule.initialize()
}
我通常做的是在类似 APP_STARTUP_FINISHED:
之后从 observable 调用这个函数const appStatePrepared = (action$: Object, { dispatch }) =>
action$.ofType(APP_STATE_PREPARED)
.switchMap(() => {
configurePrinters(dispatch)
})
正确的解决方法是什么?
谢谢!
当使用 RxJS 时,理想的是组合流。所以在这种情况下,我们需要一些如何创建 "PrintingManagerNewPrinterConnected"
事件流,然后我们可以将每个事件映射到它们自己的 PRINTER_MANAGER_NEW_PRINTER_CONNECTED
action.a
让我们先学习如何完全自定义。
自定义 Observables
创建您自己的自定义 Observables 与创建 Promise 非常相似。假设你有世界上最简单的 Promise,它立即解析为数字 1
const items = new Promise(resolve => {
resolve(1);
});
等效的 Observable 看起来超级相似
const items = new Observable(observer => {
observer.next(1);
observer.complete();
});
在视觉上,主要区别在于我们没有传递 (resolve, reject)
回调,而是获得了一个观察者,因为有下一个、错误和完成。
语义上,Observables 可以通过多次调用 observer.next
来表示多个值,直到它们调用 observer.complete()
来表示流的结束;这与仅表示单个值的 Promises 形成对比。
默认情况下,Observables 也是惰性和同步的,而 Promises 总是急切的和异步的。
既然我们已经有了这样的理解,我们想接受它并包装您的 NativeEventEmitter
API,它使用 addEventListener
.
const configurePrinters = () => {
return new Observable(observer => {
const printingModule = NativeModules.PrintingManager;
const eventEmitter = new NativeEventEmitter(printingModule);
eventEmitter.addListener(
'PrintingManagerNewPrinterConnected',
(payload) => observer.next(payload)
);
printingModule.initialize();
});
};
configurePrinters()
.subscribe(payload => console.log(payload));
这有效而且非常简单,但它有一个问题:我们应该在他们取消订阅时调用 removeListener
以便我们自己清理并且不会泄漏内存。
为此,我们需要 return 在我们的自定义 Observable 中进行订阅。此上下文中的订阅是一个 object,上面有一个 unsubscribe()
方法,当订阅者取消订阅、触发错误或您的可观察对象完成时,将自动调用该方法。这是你清理的机会。
const items = new Observable(observer => {
let i = 0;
const timer = setInterval(() => {
observer.next(i++);
}, 1000);
// return a subscription that has our timer cleanup logic
return {
unsubscribe: () => {
clearInterval(timer);
}
};
});
因为 return 一个 object 有点冗长 RxJS 支持一个 shorthand 你只是 return 一个函数本身将被视为 unsubscribe
方法。
const items = new Observable(observer => {
let i = 0;
const timer = setInterval(() => {
observer.next(i++);
}, 1000);
// return an "unsubscribe" function that has our timer cleanup logic
return () => {
clearInterval(timer);
};
});
现在我们可以将其应用到我们的示例中,我们希望在调用取消订阅拆解函数时删除我们的侦听器。
const configurePrinters = () => {
return new Observable(observer => {
const printingModule = NativeModules.PrintingManager;
const eventEmitter = new NativeEventEmitter(printingModule);
const listener = (payload) => observer.next(payload);
eventEmitter.addListener(
'PrintingManagerNewPrinterConnected',
listener
);
printingModule.initialize();
return () => eventEmitter.removeListener(
'PrintingManagerNewPrinterConnected',
listener
);
});
};
现在让我们把它变成一个可重用的实用函数
const fromPrinterEvent = (eventName) => {
return new Observable(observer => {
const printingModule = NativeModules.PrintingManager;
const eventEmitter = new NativeEventEmitter(printingModule);
const listener = (payload) => observer.next(payload);
eventEmitter.addListener(eventName, listener);
printingModule.initialize();
return () => eventEmitter.removeListener(eventName, listener);
});
};
fromPrinterEvent('PrintingManagerNewPrinterConnected')
.subscribe(payload => console.log(payload));
Observable.fromEvent
虽然 NativeEventEmitter
是 react-native 的东西,但它跟在 node-style EventEmitter interface and RxJS already comes with a utility helper to create an Observable from them to save you the effort. It's called fromEvent
之后,位于 Observable.fromEvent
或 import { fromEvent } from 'rxjs/observables/fromEvent'
.
const fromPrinterEvent = (eventName) => {
return Observable.defer(() => {
const printingModule = NativeModules.PrintingManager;
const eventEmitter = new NativeEventEmitter(printingModule);
printingModule.initialize();
return Observable.fromEvent(eventEmitter, eventName);
});
};
这里我也将它包装在 Observable.defer
中,这样我们就不会创建 NativeEventEmitter
或 printingModule.initialize()
直到有人真正订阅(保持懒惰)。这对您来说可能是必要的,也可能不是必要的,我不知道 PrintingManager 的作用或行为方式。例如可能只需要创建一个发射器并预先初始化模块。
const printingModule = NativeModules.PrintingManager;
const printerEmitter = new NativeEventEmitter(printingModule);
printingModule.initialize();
const fromPrinterEvent = (eventName) =>
Observable.fromEvent(printerEmitter, eventName);
所以请记住,我只是在展示模式而不知道 PrintingManager 等的作用。
在redux-observable
内使用在 redux-observable 中使用它,您的史诗现在与您使用任何其他 Observable 一样。所以我们希望将它的值映射到操作和 mergeMap、switchMap、concatMap 或 exhaustMap 到我们的 top-level 流中。
像这样:
const appStatePrepared = action$ =>
action$.ofType(APP_STATE_PREPARED)
.switchMap(() =>
fromPrinterEvent('PrintingManagerNewPrinterConnected')
.map(payload => ({
type: PRINTER_MANAGER_NEW_PRINTER_CONNECTED,
payload: {
macAddress: payload[2],
connectionType: payload[3],
}
}))
);
请记住,包括我们的习惯 fromPrinterEvent('PrintingManagerNewPrinterConnected')
在内的许多信息流将永远存在,直到您取消订阅它们。所以如果你只想要一个,你会使用 .take(1)
。如果你想在收到另一个操作时取消订阅,你可以使用 .takeUntil(action$.ofType(WHATEVER))
,等等。正常的 RxJS 模式。