如何使用React Redux实施Firebase身份验证?

时间:2018-10-20 18:19:43

标签: reactjs facebook firebase react-redux

我正在使用Firebase通过Facebook或google处理我的身份验证。我真正不明白的是为什么我的商店没有更新。

下面是我的代码示例:

import { createStore } from 'redux';
import {app, facebookProvider, googleProvider } from './../config/config';

const initialState = {
    SCREEN_CURRENT: "login",
    authenticated: false
}

const reducer = (state = initialState, action) => {
console.log('reducer', action);

switch(action.type){
    case "AUTH_LOGIN_FACEBOOK":
        state = {
            ...state,
            authenticated: true
        }

        app.auth().signInWithPopup(facebookProvider)
        .then((user, error) => {
            if(error){
                console.log("Unable to login with Facebook!");
            } else {
                console.log("Logged in succesfully");
                state = Object.assign({}, state, {
                    authenticated: true
                });
            }
        }).catch((error) => {
            if(error){
                console.log("Error from Facebook: " + error.message);
            }
        });
        break;

    case "AUTH_LOGIN_GOOGLE":
        app.auth().signInWithPopup(googleProvider)
        .then((user, error) => {
            if(error){
                console.log("Unable to login with Google!");
            } else {
                console.log("Logged in succesfully");
                return Object.assign({}, state, {
                    authenticated: true
                });
            }
        }).catch((error) => {
            if(error){
                console.log("Error from Google: " + error.message);
            }
        });
        break;

    default:
        break;
}

return state;
}

const store = createStore(reducer);

store.subscribe(() => {
    console.log("Store updated", store.getState());
});

export default store;

即使我成功登录后将身份验证状态更改为true(发生了什么),有人可以向我解释为什么我的商店没有更新吗?

我不明白为什么。

当我单击触发“ AUTH_LOGIN_FACEBOOK”操作的按钮时,商店将得到更新。但是,当我将authenticated的状态更改为true时,不是这样。如何获取商店更新?

1 个答案:

答案 0 :(得分:0)

减速器内部逻辑太多。这里要做的第一件事是将它们移至一个动作,一个普通的旧javascript对象,甚至一个函数。请注意,上面的代码没有考虑导入/导出,但是我想您会在这里理解我的意思。因此,您必须使其适应您的用例。

// ##########################################################################
// AUTH FUNCTIONS ###########################################################
// ##########################################################################

const FACEBOOK = 'facebook';
const GOOGLE = 'google';

// just to make sure that you'll always return a valid prodiver.
function getProviderObject(provider) {
  return {
    [FACEBOOK]: new firebase.auth.FacebookAuthProvider(),
    [GOOGLE]: new firebase.auth.GoogleAuthProvider()
  }[provider] || null;
}

// this function receives a provider object and return a User, no matter what
// provider, Google or Facebook
function signInWithProvider(provider) {  
  const providerObject = getProviderObject(provider);

  if(!providerObject) {
    throw new Error('Invalid provider');
  }

  try {
    const response = await FirebaseApp.auth().signInWithPopup(provider);

    return response.user;
  } catch(error) {
    // handle error...
    throw error;
  }
}

function signInWithFirebase({ email, password }) {
  return FirebaseApp.auth().signInAndRetrieveDataWithEmailAndPassword(email, password);
}


// ##########################################################################
// ACTIONS ##################################################################
// ##########################################################################

// this action acts like a router, which will decide to sign in with an 
// external provider (GOOGLE or FACEBOOK) or sign in with email/password
const signIn = param => async dispatch => {
  try {
    const user = await (
      [GOOGLE, FACEBOOK].includes(param) ?
        signInWithProvider(param) :
        signInWithFirebase(param)
    );

    dispatch({
      type: 'CREATE_SESSION',
      payload: user
    });

    return user;
  } catch(error) {
    console.log(error);
  }
};

// ##########################################################################
// REDUCERS #################################################################
// ##########################################################################

const initialState = { 
  authenticated: false, 
  user: null,
  // etc...
};

function sessionReducer(state = initialState, action = {}) {
  switch(action.type) {
    case 'CREATE_SESSION': return { 
      ...action.payload, 
      authenticated: true,
      // whatever props you need here...
    };

    case 'DESTROY_SESSION': return initialState;

    default: return state;
  }
}

// ##########################################################################
// EXAMPLE ##################################################################
// ##########################################################################

class Auth extends React.Component {
  state = {
    email: null,
    password: null
  };

  render() {
    const { email, password } = this.state;

    return (
      <p><a href="#" onClick={this.signInWith(FACEBOOK))>SIGN IN WITH FACEBOOK</a></p>
      <p><a href="#" onClick={this.signInWith(GOOGLE))>SIGN IN WITH GOOGLE</a></p>

      <form onSubmit={this.onSubmit}>
        <input 
          type="email" 
          onChange={this.onChange('email')} 
          value={email} placeholder="Email" 
        />

        <input 
          type="password" 
          onChange={this.onChange('email')} 
          value={password} 
          placeholder="Password" 
        />

        <button>Sign In</button>
      </form>
    )
  }

  signInWith = provider => event => {
    event.preventDefault();
    this.props.signIn(provider);
  }

  onChange = field => value => this.setState({ [field]: value });

  onSubmit = () => {
    const { email, password } = this.state;
    return this.props.signIn({ email, password });
  };
}

export default connect(null, { signIn })(Auth);

我希望这会有所帮助!