【问题标题】:How to use createStackNavigator to create different home screens based on Authentication?如何使用 createStackNavigator 根据 Authentication 创建不同的主屏幕?
【发布时间】:2020-02-22 18:29:52
【问题描述】:

我正在使用 React Native,我希望根据身份验证将用户带到不同的主屏幕。我使用 Firebase 作为数据库来确定用户是管理员还是普通用户。如何根据用户提交的电子邮件将用户发送到不同的主屏幕?

这是我的 App.js 代码:

//downloaded libraries that allow different commands and tools
import React from 'react';
import {createAppContainer, createSwitchNavigator, Button, TouchableOpacity, Text} from 'react-navigation';
import {createStackNavigator} from 'react-navigation-stack';
import LoadingScreen from './screens/LoadingScreen';
import HomeScreen from './screens/HomeScreen';
import LoginScreen from './screens/LoginScreen';
import SurveyScreen from './screens/SurveyScreen';
import DetailsScreen from './screens/DetailsScreen'
import * as firebase from 'firebase';
import 'firebase/firestore';

//variable storing firebase api, authentication, and database keys
var firebaseConfig = {
    // excluded this part
};

//initializes firebase domain
firebase.initializeApp(firebaseConfig);

//navigation stacks for navigating between different screens
//one for user login (AuthStack) and the other for user screens (AppStack)
const AppStack = createStackNavigator({
  Home: {
    screen: HomeScreen,
    screen: Other
  },
  Survey: SurveyScreen,
  Details: DetailsScreen
})

const AuthStack = createStackNavigator({
  Login: {
    screen: LoginScreen,
    navigationOptions: {
      header: null
    },
  }
})

//exports navigation stacks to allow users to log in and navigate to different screens
//LoadingScreen.js is the first screen to load when app is initialized (initialRouteName: "Loading")
export default createAppContainer(
  createSwitchNavigator(
    {
      Loading: LoadingScreen,
      App: AppStack,
      Auth: AuthStack,
    },
    {
      initialRouteName: "Loading"
    }
  )
)
//navigation stacks for navigating between different screens
//one for user login (AuthStack) and the other for user screens (AppStack)
const AppStack = createStackNavigator({
  Home: {
    screen: HomeScreen,
    screen: Other
  },
  Survey: SurveyScreen,
  Details: DetailsScreen
})

const AuthStack = createStackNavigator({
  Login: {
    screen: LoginScreen,
    navigationOptions: {
      header: null
    },
  }
})

//exports navigation stacks to allow users to log in and navigate to different screens
//LoadingScreen.js is the first screen to load when app is initialized (initialRouteName: "Loading")
export default createAppContainer(
  createSwitchNavigator(
    {
      Loading: LoadingScreen,
      App: AppStack,
      Auth: AuthStack,
    },
    {
      initialRouteName: "Loading"
    }
  )
)

这是我的 LoginScreen.js 代码:

import React from 'react';
import {View, Text, StyleSheet, TextInput, TouchableOpacity, Image, KeyboardAvoidingView} from 'react-native';
import * as firebase from 'firebase';

export default class LoginScreen extends React.Component {
    //default states of values "email", "password", and "errorMessage"
    state = {
        email: "",
        password: "",
        errorMessage: null
    };

    componentDidMount() {
        console.disableYellowBox = true;
    }

    //function that logs user in and redirects them to the first screen in AppStack (HomeScreen.js)
    //if the correct email and password credentials are met. if credentials are not met, an error
    //message will be displayed
    handleLogin = () => {
        const {email, password} = this.state
        firebase
        .auth()
        .signInWithEmailAndPassword(this.state.email, this.state.password)
        .catch(error => this.setState({errorMessage: error.message}));
    };

    render() {
        //UI is coded in the return() area
        return (
            <KeyboardAvoidingView style={styles.container} behavior="padding" enabled>
                <Image style={styles.image}
                source={require('../assets/EMSlogo.png')}></Image>

                <View style={styles.errorMessage}>
                    {this.state.errorMessage && <Text style={styles.error}>{this.state.errorMessage}</Text>}
                </View>

                <View style={styles.form}>
                    <View>
                        <Text style={styles.inputTitle}>Email Address</Text>
                        <TextInput style={styles.input} autoCapitalize="none"
                        onChangeText={email => this.setState({ email })}
                        value={this.state.email}></TextInput>
                    </View>

                    <View style={{marginTop: 32}}>
                        <Text style={styles.inputTitle}>Password</Text>
                        <TextInput style={styles.input} secureTextEntry autoCapitalize="none"
                        onChangeText={password => this.setState({ password })}
                        value={this.state.password}></TextInput>
                    </View>
                </View>

                <TouchableOpacity style={styles.button} onPress={this.handleLogin}>
                    <Text style={{color: "#FFF", fontWeight: "500", fontSize: 21}}>
                        Sign In
                    </Text>
                </TouchableOpacity>
            </KeyboardAvoidingView>
        )
    }
}

//this is how you create a stylesheet in react native
const styles = StyleSheet.create({
    container: {
        flex: 1,
    },
    image: {
        margin: 30,
        marginBottom: 0,
        flex: 1,
        width: null,
        height: null,
        resizeMode: 'contain',
    },
    greeting: {
        marginTop: 32,
        fontSize: 18,
        fontWeight: "400",
        textAlign: "center"
    },
    errorMessage: {
        height: 72,
        alignItems: "center",
        justifyContent: "center",
        marginHorizontal: 30
    },
    error: {
        color: "#E9446A",
        fontSize: 16,
        fontWeight: "600",
        textAlign: "center"
    },
    form: {
        marginBottom: 48,
        marginHorizontal: 30,
    },
    inputTitle: {
        color: "#8A8F9E",
        fontSize: 16,
        textTransform: "uppercase"
    },
    input: {
        borderBottomColor: "#8A8F9E",
        borderBottomWidth: StyleSheet.hairlineWidth,
        height: 40,
        fontSize: 18,
        color: "#161F3D"
    },
    button: {
        marginHorizontal: 30,
        marginBottom: 35,
        backgroundColor: "#00235D",
        borderRadius: 4,
        height: 52,
        alignItems: "center",
        justifyContent: "center",
    }
});

【问题讨论】:

    标签: reactjs firebase react-native stack-navigator


    【解决方案1】:

    登录后导航到您的 HomeScreen 组件并根据用户类型使用条件渲染。在您的 handleLogin 检查用户类型并导航到主屏幕,将用户类型作为参数传递。

    handleLogin = () => {
      const { email, password } = this.state;
      firebase
        .auth()
        .signInWithEmailAndPassword(this.state.email, this.state.password)
        .then(() => {
          // check user type 
          // pass user type as param to home screen
          this.props.navigation.navigate('Home', { userType: 'admin or nomral user' });
        })
        .catch(error => this.setState({ errorMessage: error.message }));
    };
    

    在您的主屏幕中获取用户类型,使用const userType = this.props.navigation.getParam('userType', '');

    class HomeScreen extends React.Component {
      render = () => {
        const userType = this.props.navigation.getParam('userType', '');
        return (
          <View>
            {typeof userType === 'string' && userType.toLowerCase() === 'admin' ? (
              <Admin />
            ) : (
              <User />
            )}
          </View>
        );
      };
    }
    

    DEMO

    【讨论】:

      【解决方案2】:

      如果用户未通过身份验证,您可以使用显示登录屏幕的高阶组件,否则根据组件道具显示管理页面或基本页面,例如:

      HOC 组件

      import React, { Component } from 'react';
      
      import Login from '../templates/login';
      
      const AdminHOC = (props, Comp) => (WrappedComponent) => {
        return class LoaderHOC extends Component {
          render() {
            const { common: { user } } = this.props;
            const DefaultComponent = user ? Comp : Login;
            let valid = false;
            props.map((prop) => {
              if (user && user[prop]) {
                valid = true;
              }
              return true;
            });
            return valid
              ? (
                <WrappedComponent {...this.props} />
              )
              : (
                <DefaultComponent {...this.props} />
              );
          }
        };
      };
      
      
      export default AdminHOC;
      

      然后在您的管理页面组件中:

      class Admin extends Component {
      ...
      }
      
      class Home extends Component {
      ...
      }
      
      // admin and development are props that needs to be true to render the admin page
      // If both are false it shows a regular home page
      export default AdminHOC(['admin', 'development'], Home)(Admin);
      

      通过这种方式,您可以包装任何需要用户成为管理员的组件,如果没有,则显示其他组件。

      【讨论】:

        猜你喜欢
        • 2019-08-04
        • 2011-07-10
        • 1970-01-01
        • 2017-06-13
        • 2016-12-11
        • 1970-01-01
        • 1970-01-01
        • 2011-04-19
        • 2012-11-26
        相关资源
        最近更新 更多