在每个选项卡中使用“身份验证”屏幕来响应导航

时间:2019-02-27 12:30:41

标签: reactjs navigation react-navigation react-navigation-stack

我有一个具有这种结构的应用程序

structure

用户是否登录都没有关系,TabBar始终应该相同。如果用户登录了应用程序将打开选项卡的内容,否则将打开“身份验证”屏幕。如何在反应导航中创建它? 抱歉,在反应导航中有些困惑。

1 个答案:

答案 0 :(得分:1)

所以我想我有一个解决方案。

  1. 创建一个事件发射器,该事件发射器将在登录状态更改时发出事件
  2. 订阅App.js
  3. 中的事件
  4. 通过screenProps将更新后的事件传递到TabNavigator。
  5. 这些更新的screenProps允许在每个标签中的登录状态之间切换。
  6. 将登录状态存储在AsyncStorage中,以便在应用关闭之间将其保持不变。请注意,AsyncStorage仅允许您存储字符串。
  7. 当用户登录时从AuthScreen发送事件,或者当用户注销时从其他屏幕发送事件。

事件发射器

要创建事件发射器,我们需要使用events依赖项。使用npm i events安装它。我们将其创建为单例,以便我们的应用程序中只能运行一个实例。

import { EventEmitter } from 'events';

class LoginEventEmitter {
  constructor () {
    this.eventEmitter = new EventEmitter();
  }

  // create a function to handle the login
  // pass the loggedIn value that you want to be emitted
  handleLogin = (loggedIn) => {
    this.eventEmitter.emit('loggedIn', { loggedIn });
  }
}

const EventEmitterController = new LoginEventEmitter();

export default EventEmitterController;

App.js

订阅事件并处理AsyncStorage

import React from 'react';
import { AsyncStorage } from 'react-native';
import AppContainer from './MainNavigation';
import LoginEventEmitter from './LoginEventEmitter';
export default class App extends React.Component {
  constructor (props) {
    super(props);

    this.state = {
      loggedIn: false,
      loaded: false
    };

    // subscribe to the events and update the values in state and in AsyncStorage
    LoginEventEmitter.eventEmitter.addListener('loggedIn', e => {
      this.setState({ loggedIn: e.loggedIn });
      let value = e.loggedIn ? 'true' : 'false';
      AsyncStorage.setItem('loggedIn', value);
    });
  }

  async componentDidMount () {
    // handle the loggedIn value when the component mounts
    try {
      let loggedIn = await AsyncStorage.getItem('loggedIn');
      if (loggedIn) {
        this.setState({
          loggedIn: loggedIn === 'true',
          loaded: true
        });
      } else {
        this.setState({ loaded: true });
      }
    } catch (error) {
      console.warn(error);
    }
  }

  render () {
    // wait until asyncstorage has returned a value before showing the App.
    // pass the loggedIn value via screen props so every screen in the TabNavigator gets updated with the new value
    if (this.state.loaded) {
      return (
        <AppContainer screenProps={{ loggedIn: this.state.loggedIn }}/>
      );
    } else {
      return null;
    }
  }
}

标签屏幕模板

这是每个TabScreen的基本模板。我在上面放了一个注销按钮,以便用户可以注销。 (主要用于测试)。

import React from 'react';
import { View, StyleSheet, Text, Button } from 'react-native';
import AuthScreen from './AuthScreen';
import LoginEventEmitter from './LoginEventEmitter';

export default class Screen1 extends React.Component {
  logout = () => {
    LoginEventEmitter.handleLogin(false);
  }

  render () {
    if (this.props.screenProps.loggedIn) {
      return (
        <View style={styles.container}>
          <Text>Screen 1</Text>
          <Button title={'logout'} onPress={this.logout} />
        </View>
      );
    } else {
      return <AuthScreen />;
    }
  }
}

在render函数中,根据所传递的值,我们将访问从screenProps传递来的TabNavigator,具体取决于呈现的内容。

示例AuthScreen

在这里,当用户点击按钮时,我们将执行“登录”。这会发出一个事件,该事件由App.js中的侦听器捕获,该事件进而更新App.js中的状态值,并且该值通过screenProps传递到每个Tab。

import React from 'react';
import { View, StyleSheet, Text, Button } from 'react-native';
import LoginEventEmitter from './LoginEventEmitter';
export default class Screen1 extends React.Component {
  render () {
    return (
      <View style={styles.container}>
        <Text>AuthScreen</Text>
        <Button title={'Login'} onPress={() => {
          LoginEventEmitter.handleLogin(true);
        }}/>
      </View>
    );
  }
}

示例TabNavigator

这是一个示例TabNavigator。

import Screen1 from './Screen1';
import Screen2 from './Screen2';
import { createBottomTabNavigator, createAppContainer } from 'react-navigation';

const screens = {
  Screen1: {
    screen: Screen1
  },
  Screen2: {
    screen: Screen2
  }
};

const config = {
  headerMode: 'none',
  initialRouteName: 'Screen1'
};

const MainNavigator = createBottomTabNavigator(screens, config);
export default createAppContainer(MainNavigator);

小吃

最后,这是一道小吃,展示了所有食物https://snack.expo.io/@andypandy/event-emitter-to-handle-login