React Navigation + компонент более высокого порядка (HOC) для проверки аутентификации / защищенных маршрутов

У меня проблема, когда я использую компонент более высокого порядка для проверки подлинности пользователя (checkAuth). Моя проблема в том, что маршрут кажется защищенным, поскольку он не отображается на экране, но он загружает навигацию по нижней вкладке, заголовок и не выполняет обратный путь к экрану входа в систему.

ВОТ, КАК ВЫГЛЯДИТ ПРОБЛЕМА

checkAuthTest - это просто функция, которую я написал для перехода на экран бесед:

  // Check Auth Test (Testing)
  checkAuthTest = () => {
    try {
      console.log('Navigating to App Stack')
      console.log(`Current User: ${firebase.auth().currentUser}`);

      // this.props.navigation.navigate('AppStack');
      // this.props.navigation.navigate('AuthLoading');
      this.props.navigation.navigate('Conversations');
    }
    catch (error) {
      console.log(error);
    }
  };

Компонент высшего порядка:

Если пользователь аутентифицирован, компонент более высокого порядка направляет пользователя к компоненту. Если пользователь не аутентифицирован, компонент более высокого порядка направляет пользователя обратно к экрану входа в систему.

// Imports: Dependencies
import React from 'react';
import firebase from 'firebase';

// Imports: Screens
import Login from '../../screens/auth-stack/Login';

// Higher Order Component: Check Auth
const CheckAuth = (OriginalComponent) => props => {
  class CheckAuth extends React.Component {    
    render() {
      // Check Authentication (Working)
      if (firebase.auth().currentUser !== null) {
        return <OriginalComponent {...this.props} />
      }
      // Redirect To Login (Not Working)
      else {
        return <Login />
      }
    }
  }

  // Return Check Auth Component
  return CheckAuth;
}

// Exports
export default CheckAuth;

React Navigation: я использую React Navigation, и вот мои настройки:

// React Navigation: Auth Stack Navigator
export const AuthStack = createStackNavigator({
  Login: Login,
  AuthLoading: AuthLoading,
});

// React Navigation: Messaging Stack Navigator
export const MessagingStack = createStackNavigator({
  Conversations: Conversations,
  Message: Message,
  NewMessage: NewMessage,
});

// React Navigation: Profile Stack Navigator
export const ProfileStack = createStackNavigator({
  Profile: Profile,
},
{
  mode: 'modal',
});

// React Navigation: App Stack Navigator
export const AppStack = createBottomTabNavigator({
  Message: {
    screen: MessagingStack,
    navigationOptions: {
      tabBarLabel: 'Message',
      tabBarIcon: ({ tintColor }) => (
        <Icon name="ios-chatboxes" color={tintColor} size={26} />
      ),
    }
  },
  Profile: {
    screen: ProfileStack,
    navigationOptions: {
      tabBarLabel: 'Profile',
      tabBarIcon: ({ tintColor }) => (
        <Icon name="ios-contact" color={tintColor} size={28} />
      ),
    }
  }
});

// React Navigation: Switch Container
export const AppContainer = createAppContainer(createSwitchNavigator(
  {
    AuthStack: AuthStack,
    AppStack: AppStack,
  },
    // Options
  {
    initialRouteName: 'AuthStack',
    // initialRouteName: 'AppStack',
  }
));

Экспорт экрана бесед:

export default connect(mapStateToProps, mapDispatchToProps)(checkAuth(Conversations));

Компонент входа

// Imports: Dependencies
import React, { Component } from 'react';
import { Button, SafeAreaView, StyleSheet, Text } from 'react-native';
import { connect } from 'react-redux';

// Imports: Redux Actions
import { 
  loginWithAppleRequest,
} from '../../redux/actions/authActions';

// TEST: Delete Later
import firebase from 'firebase';
import { appleAuth } from '../../firebase/firebase';

// Imports: Components
import FBLoginButton from '../../components/FacebookLoginButton';
import GoogleLoginButton from '../../components/GoogleLoginButton';
import SignOutButton from '../../components/SignOutButton';

// Screen: Login
class Login extends Component {
  constructor(props) {
    super(props);
  }

  // React Navigation: Options
  static navigationOptions = {
    headerStyle: {
      elevation: 0,
      shadowOpacity: 0,
      borderBottomWidth: 0,
    }
  };

  // Login With Apple
  loginWithApple = () => {
    try {
      firebase
      .auth()
      .signInWithPopup(appleAuth)
      .then((result) => {
        // The signed-in user info.
        let user = result.user;
        // You can also get the Apple OAuth Access and ID Tokens.
        let accessToken = result.credential.accessToken;
        let idToken = result.credential.idToken;

        console.log('User');
        console.log(user);

        console.log('Access Token');
        console.log(accessToken);

        console.log('ID Token');
        console.log(idToken);
      })
      .catch((error) => {
        // Handle Errors here.
        let errorCode = error.code;
        let errorMessage = error.message;
        // The email of the user's account used.
        let email = error.email;
        // The firebase.auth.AuthCredential type that was used.
        let credential = error.credential;

        console.log('Error Code');
        console.log(errorCode);

        console.log('Error Message');
        console.log(errorMessage);

        console.log('Email');
        console.log(email);

        console.log('Credential');
        console.log(credential);
      });
    }
    catch (error) {
      console.log(error);
    }
  };

  // Check Auth Test (Testing)
  checkAuthTest = () => {
    try {
      console.log('Navigating to App Stack')
      console.log(`Current User: ${firebase.auth().currentUser}`);

      // this.props.navigation.navigate('AppStack');
      // this.props.navigation.navigate('AuthLoading');
      this.props.navigation.navigate('Conversations');
    }
    catch (error) {
      console.log(error);
    }
  };

  render() {
    return (
      <SafeAreaView style={styles.container}>        
        <GoogleLoginButton />
        <FBLoginButton />

        <Button onPress={this.checkAuthTest} title="Check Auth Test" />

        <SignOutButton />

      </SafeAreaView>
    )
  }
}

// Styles
const styles = StyleSheet.create({
  container: {
    height: '100%',
    display: 'flex',
    justifyContent: 'center',
    alignItems: 'center',
  },
});

// Map State To Props (Redux Store --> Component)
const mapStateToProps = (state) => {
  // Redux Store --> Component
  return {
    // uid: state.authReducer.uid,
  };
};

// Map Dispatch To Props (Dispatch Actions To Redux Store To Grab Data)
const mapDispatchToProps = (dispatch) => {
  // Action
  return {
    // Redux: Dispatch Login With Apple Action
    reduxLoginWithAppleRequest: () => dispatch(loginWithAppleRequest()),
  };
};

// Exports
export default connect(mapStateToProps, mapDispatchToProps)(Login);

person jefelewis    schedule 21.11.2019    source источник
comment
Я думаю, это связано с тем, как экспортировать компонент входа в систему, не могли бы вы добавить этот код, чтобы я мог его просмотреть?   -  person Jurrian    schedule 22.11.2019
comment
Просто добавил код для экрана входа в систему. Спасибо, что посмотрели!   -  person jefelewis    schedule 22.11.2019


Ответы (1)


Ошибка говорит вам, что случилось. Вы возвращаете функцию вместо элемента:

const CheckAuth = (OriginalComponent) => props => {
  class CheckAuth extends React.Component {
    // ...
  }

  // Return Check Auth Component
  return CheckAuth;
}

Теперь, когда вы его используете:

CheckAuth(Conversations)

Результаты в:

const Component = props => {
  class CheckAuth extends React.Component {
    // ...
  }

  // This is a component but you're returning a function instead an element
  return CheckAuth;
}

Вы, наверное, захотите:

const CheckAuth = (OriginalComponent) => {
  class CheckAuthComponent extends React.Component {
    // ...
  }

  // Return Check Auth Component
  return CheckAuthComponent;
}

Здесь я удалил лишний props =>, так как здесь вам нужно вернуть компонент (CheckAuth), а не функцию, возвращающую компонент (props => CheckAuth).

person satya164    schedule 22.11.2019
comment
Итак, теперь он работает и переходит к экрану входа в систему, но навигатор заголовка и вкладок из React Navigation все еще присутствует. А идея, что это могло быть? Когда кнопка нажата, он должен перейти к экрану разговоров (стек приложений), но HOC возвращает экран входа в систему (стек аутентификации). - person jefelewis; 22.11.2019