将观察者传递到 redux-sagas

Passing observer into redux-sagas

我正在尝试利用 redux-sagas 框架内的 firebase observable,但我在没有 hack 的情况下遇到了麻烦。我正在尝试使用 firebase 的 "onAuthStateChange" 函数,如此处所示

firebase.auth().onAuthStateChanged(function(user) {
  if (user) {
    // User is signed in.
  } else {
    // No user is signed in.
  }
});

基本上,只要用户登录或注销,观察者就会执行

在我的 firebase 实用程序文件中,我的方法如下所示:

authChanged: () =>{
    return firebaseAuth.onAuthStateChanged(callback);
}

然后在我的传奇中,目前,我只是尝试在观察者观察到某事时登录到控制台:

export function* loginState(){
    Firebaseutils.authChanged(function(user){
        if(user){
            console.log('User logged in!')
        }else{
            console.log('User logged out')
        }
    });
}

由于 'callback' 未定义,此操作失败。我本质上是在试图说服观察者将其传递给 sagas,但它不起作用。我的解决方法是将完整的 firebase auth 对象传递给我的 login/logout saga,然后在其中创建观察者。那行得通,但似乎很hack。任何帮助将不胜感激。

您似乎打算将 callback 作为 authChanged 的参数,但 authChanged 目前没有参数。这可能是您想要做的:

authChanged: (callback) => {
    return firebaseAuth.onAuthStateChanged(callback);
}

我不确定我是否理解柯里化观察者的意思,但您也可以这样做来柯化 firebase 方法以用作您的方法:

{
    authChanged: ::firebaseAuth.onAuthStateChanged,
}

我认为您实际上并没有将 observer 整合到代码段中的 saga 中。它适用于 console.log b/c 这是一个同步函数,但您不能 yield 来自该回调的任何内容,因为它的上下文与 generator 的上下文是分开的。这剥夺了你很多 sagas 实用程序,如果它工作 @ all.

我必须在我的项目中使用它,而我能做的最好的是受到 this project and the architecture in this starter-kit 的启发。

基本上就是几步。

  1. 将您的观察者包装在接受 dispatch 和 returns 一个 promise 的函数中。

    export function initAuth(dispatch) {
     return new Promise((resolve, reject) => {
    
    myFirebaseAuthObj.onAuthStateChanged(
      authUser => {
        if (authUser) {
          dispatch(signInFulfilled(authUser))
        } else if (authUser === null) {
          dispatch(signOutFulfilled())
        }
        resolve()
      },
    
      error => reject(error)
    )
    })
    }
    
  2. 将顶级容器包装在一个函数中

    const initialState = window.___INITIAL_STATE__
    const store = createStore(initialState)
    let render = () => {
      const routes = require('./routes/index').default(store)
    
      ReactDOM.render(
        <AppContainer store={store} routes={routes} />,
        MOUNT_NODE
      )
    }
    
  3. render() 包裹在 initAuth 中:

    initAuth(store.dispatch)
      .then(() => render())
      .catch(error => console.error(error)) 
    
  4. 用你的 sagas 做其他事情。例如,您可以像这样从 sagas 进行路线更改:

    function* signIn(authProvider) {
      try {
        const authData = yield call([firebaseAuth, firebaseAuth.signInWithPopup], authProvider)
        yield take(SIGN_IN_FULFILLED)
        browserHistory.push('/dash')
      }
      catch (error) {
        yield put(signInFailed(error))
      }
    }