Реагировать на собственный логин Redux fbsdk

Я хочу создать логин facebook в своем приложении, используя react-native, redux и react-native-fbsdk. На самом деле, я столкнулся с проблемой, когда я нахожусь в первом состоянии (не вошел в систему), я вижу это состояние:

введите здесь описание изображения

и когда я нажимаю кнопку входа в систему, у меня есть это состояние:

введите здесь описание изображения

Для аутентификации установлено значение true, но приложение остается на аутентификации, и даже если я подожду около 5 минут, после этого ничего не произойдет. Я думаю, что в моем коде что-то не хватает, но я не знаю, что.

Я пропустил свой код здесь.

Редуктор:

import {
  AUTH_SUCCESS,
  AUTH_FAILURE,
  AUTH_STARTED,
  AUTH_ERROR,
  AUTH_FAILURE_REMOVE,
  LOGOUT
} from '../actions/types';

const initialState = {
  authenticating: false,
  authToken: null,
  authError: null,
  facebookToken: null,
  facebookProfile: null
}

function authReducer(state = initialState, action) {
  switch(action.type) {
    case AUTH_STARTED:
      return Object.assign({}, state, {
        authenticating: true,
        loginText: 'Connexion..'
      });
    case AUTH_SUCCESS:
      return Object.assign({}, state, {
        authenticating: false,
        authToken: action.authToken,
        facebookToken: action.facebookToken,
        facebookProfile: action.facebookProfile,
      });
    case AUTH_FAILURE:
      return Object.assign({}, state, {
        authenticating: false,
        authError: action.authError.message,
      });
    case AUTH_FAILURE_REMOVE:
      return Object.assign({}, state, {
        authError: null,
      });
    case LOGOUT:
      return Object.assign({}, state, {
        authenticating: false,
        authToken: null,
        facebookToken: null,
        facebookProfile: null,
        loginText: null,
      });
    default:
      return state;
  }
}

export default authReducer;

Действие: (все действия находятся в отдельном файле с именем types.js)

import { facebookLoginAPI, getFacebookInfoAPI } from '../src/facebook';
import { getServerAuthToken } from '../src/auth';
import {
  AUTH_STARTED,
  AUTH_SUCCESS,
  AUTH_FAILURE,
  AUTH_ERROR,
  AUTH_FAILURE_REMOVE,
  LOGOUT
} from './types';

export function authStarted() {
  return {
    type: AUTH_STARTED,
  };
}

export function authSuccess(facebookToken, facebookProfile, serverAuthToken){
  return {
    type: AUTH_SUCCESS,
    facebookToken,
    facebookProfile,
    authToken: serverAuthToken,
  };
}

export function authFailure(authError){
  return {
    type: AUTH_FAILURE,
    authError,
  };
}

export function authFailureRemove() {
  return {
    type: AUTH_FAILURE_REMOVE,
  };
}

export function logout() {
  return {
    type: LOGOUT,
  };
}

export function facebookLogin() {
  return (dispatch) => {
    dispatch(authStarted());
    const successValues = [];
    facebookLoginAPI().then((facebookAuthResult) => {
      successValues.push(facebookAuthResult.accessToken);
      return getFacebookInfoAPI(facebookAuthResult.accessToken);
    }).then((facebookProfile) => {
      successValues.push(serverAuthToken);
      dispatch(authSuccess(...successValues));
    }).catch((error) => {
      dispatch(authFailure(error));
      setTimeOut(() => {
        dispatch(authFailureRemove());
      }, 4000);
    });
  };
}

API Facebook:

import {
  LoginManager,
  AccessToken,
  GraphRequest,
  GraphRequestManager,
} from 'react-native-fbsdk';

const facebookParams = 'id,name,email,picture.width(100).height(100)';

export function facebookLoginAPI() {
  return new Promise((resolve, reject) => {
    LoginManager.logInWithReadPermissions(['public_profile', 'user_friends', 'email'])
    .then((FBloginResult) => {
      if (FBloginResult.isCancelled) {
        throw new Error('Login cancelled');
      }

      if (FBloginResult.deniedPermissions) {
        throw new Error('We need the requested permissions');
      }

      return AccessToken.getCurrentAccessToken();
      console.log(FBloginResult);
    })
    .then((result) => {
      resolve(result);
    })
    .catch((error) => {
      reject(error);
    });
  });
}

export function getFacebookInfoAPI() {
  return new Promise((resolve, reject) => {
    const profileInfoCallback = (error, profileInfo) => {
      if (error) reject(error);

      resolve(profileInfo);
    };

    const profileInfoRequest =
      new GraphRequest(
        '/me',
        {
          parameters: {
            fields: {
              string: facebookParams,
            },
          },
        },
        profileInfoCallback
      );

    new GraphRequestManager().addRequest(profileInfoRequest).start();
  });
}

export function getFacebookFriends() {
  return new Promise((resolve, reject) => {
    const profileInfoCallback = (error, profileInfo) => {
      if (error) reject(error);
      console.log(profileInfo);
      resolve(profileInfo);
    };

    const profileFriendsRequest =
      new GraphRequest(
        '/me/friends',
        {
          parameters: {
            fields: {
              string: facebookParams,
            },
          },
        },
        profileInfoCallback
      );

    new GraphRequestManager().addRequest(profileFriendsRequest).start();
  });
}

Кнопка для входа:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { View } from 'react-native';
import { bindActionCreators } from 'redux';
import { facebookLogin } from '../../actions/auth';
import { Button } from '../common';
import FBSDK, { LoginManager } from 'react-native-fbsdk';



class Login extends Component {
  componentWillMount() {
    this.authCheck(this.props.authToken);
  }

  componentWillReceiveProps(nextProps) {
    this.authCheck(nextProps.authToken);
  }

  authCheck(authToken){
    if (authToken) {
      return authToken;
    }
  }

  renderError() {
    if(this.props.authError){
      console.log(this.props.authError);
    }
    return null;
  }

  render() {
    return(
        <Button onPress={this.props.onLoginPressed}> Login with facebook </Button>
    );
  }
}


export default Login;

И AuthContainer:

import React, { Component, PropTypes } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { facebookLogin } from '../actions/auth';
import Login from '../components/Login';

class AuthContainer extends Component {
  onLoginPressed() {
    this.props.actions.facebookLogin();
    console.log(this.props);
  }

  render(){
    console.log(this.props);
    return (
      <Login {...this.props} onLoginPressed={this.onLoginPressed.bind(this)} />
    );
  }
}

AuthContainer.propTypes = {
  welcomeText: PropTypes.string,
  authenticating: PropTypes.bool.isRequired,
  authToken: PropTypes.oneOfType([
    PropTypes.bool,
    PropTypes.string,
  ]),
  authError: PropTypes.oneOfType([
    PropTypes.bool,
    PropTypes.string,
  ]),
  actions: PropTypes.shape({
    facebookLogin: PropTypes.func.isRequired,
  }).isRequired,
};

function mapStateToProps(state) {
  return {
    authenticating: state.auth.authenticating,
    authToken: state.auth.authToken,
    authError: state.auth.authError,
    loginText: state.auth.loginText,
  };
  console.log(state);
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators({ facebookLogin }, dispatch),
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(AuthContainer);

и App.js:

import React, { Component } from 'react';
import { Text, View, AsyncStorage } from 'react-native';
import { createStore, compose, applyMiddleware } from 'redux';
import { connect, Provider } from 'react-redux';
import { persistStore } from 'redux-persist';
import thunkMiddleware from 'redux-thunk';
import reducers from './reducers';
import { Header, Card, CardSection } from './components/common';
import AuthContainer from './containers/AuthContainer';

const store = compose(
  applyMiddleware(thunkMiddleware)
)(createStore)(reducers);

persistStore(store, { storage: AsyncStorage });


class App extends Component {
  render() {
    return(
      <Provider store={store}>
        <View>
          <Header headerText="Kiwee" />
          <Card>
            <CardSection>
              <AuthContainer />
            </CardSection>
          </Card>
        </View>
      </Provider>
    );
  }
}

export default App;

Кто-нибудь может мне помочь? Для меня это действительно важно, и я провел 1 месяц в поисках решения без каких-либо ответов.


person Antonin Mrchd    schedule 27.02.2017    source источник
comment
Я не уверен, но можете ли вы попытаться удалить функцию .push() из ваших редукторов, поскольку она мутирует операцию. Попробуйте использовать оператор concat или spread. например, попробуйте заменить successValues.push(facebookAuthResult.accessToken); с [...successValues, ..facebookAuthResult.accessToken]   -  person Manjeet Singh    schedule 28.02.2017
comment
@ManjeetSingh Да, это работает! спасибо парень! но теперь вы знаете, почему я не могу перевести accessToken в состояние authToken?   -  person Antonin Mrchd    schedule 28.02.2017
comment
хорошо, добавив это как ответ, может помочь и другим   -  person Manjeet Singh    schedule 28.02.2017
comment
@ManjeetSingh Вы должны написать ответ вместо комментария, если хотите, я отмечу его как принятый   -  person Antonin Mrchd    schedule 28.02.2017


Ответы (1)


попробуйте удалить функцию .push() из ваших редукторов, поскольку она мутирует операцию. Попробуйте использовать оператор concat или spread. например попробуй заменить

SuccessValues.push(facebookAuthResult.accessToken);

с

[...successValues, ..facebookAuthResult.accessToken]

это что-то, связанное с неизменностью, вы можете проверить это в учебнике по редуксу или найти в Google (сейчас я не в состоянии объяснить это поведение)

person Manjeet Singh    schedule 28.02.2017