我的问题不是如何使其工作,而是如何使其正确...我正在尝试使用RxJS并且不确定该特定用例的最佳方法是什么。
这种方法的灵感来自Firebase团队发布的示例回购:rxfire-samples - react
我的目标是在反应应用程序中使用firebase,懒惰加载WebPack和RxJS,我计划最后添加redux-observable。
目前我正在加载firebase,如下所示:
import { from, forkJoin, AsyncSubject } from 'rxjs'
import { tap, map } from 'rxjs/operators'
import { authListener } from '../auth/listener'
const CONFIG = {
...
}
const lazyLoadFireBase = (config) => {
const app$ = from(import('firebase/app'))
const firestore$ = from(import('firebase/firestore'))
const fireAuth$ = from(import('firebase/auth'))
return forkJoin(app$, firestore$, fireAuth$).pipe(
map(([firebase]) => {
const app = firebase.initializeApp(config)
app.firestore().settings({ timestampsInSnapshots: true })
app.firestore().enablePersistence()
return app
})
)
}
const firebaseApp = new AsyncSubject()
lazyLoadFireBase(CONFIG)
.pipe(
tap((app) => {
authListener(app)
})
)
.subscribe((app) => firebaseApp.next(app))
export { firebaseApp }
如果我想使用firebase做这样的工作,但感觉不是一个正确的方法。我想知道在整个项目中共享延迟加载的Firebase包的更好方法是什么。
import { firebaseApp } from '../../../store/firebase'
const logOut = (ev) => {
ev.preventDefault()
firebaseApp.subscribe((app) => {
app.auth().signOut()
})
}
实现了@ggradnig建议的更改:
import { from, forkJoin, ReplaySubject } from 'rxjs'
import { tap, map } from 'rxjs/operators'
import { authListener } from '../auth/listener'
const CONFIG = {
}
const lazyLoadFireBase = (config) => {
const app$ = from(import('firebase/app'))
const firestore$ = from(import('firebase/firestore'))
const fireAuth$ = from(import('firebase/auth'))
return forkJoin(app$, firestore$, fireAuth$).pipe(
map(([firebase]) => {
const app = firebase.initializeApp(config)
app.firestore().settings({ timestampsInSnapshots: true })
app.firestore().enablePersistence()
return app
})
)
}
const firebaseApp = new ReplaySubject(1)
lazyLoadFireBase(CONFIG)
.pipe(
tap((app) => {
authListener(app)
})
)
.subscribe((app) => firebaseApp.next(app))
firebaseApp.asObservable()
export { firebaseApp }
我建议有两个改进。首先,不要将Subject
或AsyncSubject
暴露给只需要订阅它的模块。相反,您可以使用firebaseApp.asObservable()
来获取仅实现Observable
的对象。
其次,由于Subject
签名的曝光,你可以在另一个文件中使用unsubscribe
,你绝对不应该这样做。取消订阅主题将使其无法用于其他订阅者。所以,只需删除unsubscribe
语句。 Ben Lesh even suggests not using unsubscribe
at all。
现在,除了这两种风格改进之外,您的方法可能会遇到麻烦。 AsyncSubject
用于封装单个异步操作。它没有缓存机制,这意味着您无法在同一主题上多次订阅并获得最新值。主题总是热门,因此您必须在发出之前订阅。要解决这个问题,你可以使用ReplaySubject(1)
。它将缓存最新的发射并将其重播给所有未来的用户。