在 React Native 中使用令牌时无法导航到另一个屏幕 [英] Could not navigate to another screen when using token in React Native

查看:43
本文介绍了在 React Native 中使用令牌时无法导航到另一个屏幕的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用 React Native 开发应用程序,现在我的问题是登录后无法导航到主屏幕.下面是我的代码.

I'm currently developing an app using react native, right now my issue is that i couldn't navigate to main screen after login. Below is my code.

这是 App.js(已编辑)

This is App.js (EDITED)

import React from 'react';
import { Loading } from './components/common/';
import TabNavigator from './screens/TabNavigator';
import AuthNavigator from './screens/AuthNavigator';
import MainNavigator from './screens/MainNavigator';
import deviceStorage from './services/deviceStorage.js';
import { View, StyleSheet } from 'react-native';

export default class App extends React.Component {
constructor() {
super();
this.state = {
  token: '',
  loading: true
}

this.newJWT = this.newJWT.bind(this);
this.deleteJWT = deviceStorage.deleteJWT.bind(this);
this.loadJWT = deviceStorage.loadJWT.bind(this);
this.loadJWT();

}

state = {
isLoadingComplete: false,
};

newJWT(token){
this.setState({
    token: token
});
}

render() {
if (this.state.loading) {
  return (
    <Loading size={'large'} />
   );
} else if (!this.state.token) {
  return (
        <View style={styles.container}>
            <AuthNavigator screenProps = {{setToken:this.newJWT}} />
        </View>
  );
} else if (this.state.token) {
  return (
        <View style={styles.container}>
            <MainNavigator screenProps = {{token: this.state.token, 
deleteJWT:this.deleteJWT,}} />
        </View>
  );
}
}
}    

这是 Login.js (EDITED-v2)

This is Login.js (EDITED-v2)

import React, { Component, Fragment } from 'react';
import { Text, View, StyleSheet, ImageBackground, KeyboardAvoidingView, 
TouchableOpacity, TextInput, Alert } from 'react-native';
import axios from 'axios';
import deviceStorage from '../services/deviceStorage';

class Login extends Component {

constructor(props) {

    super(props)

    this.state = {
        username: '',
        password: '',
        error: '',
        loading: false
    };

    this.loginUser = this.loginUser.bind(this);
    this.onLoginFail = this.onLoginFail.bind(this);

}

loginUser() {
    const { username, password, password_confirmation } = this.state;

    this.setState({ error: '', loading: true });

    // NOTE Post to HTTPS only in production
    axios.post("http://192.168.1.201:8000/api/login",{
        username: username,
        password: password
    })
    .then((response) => {
        console.log('response',response)
    deviceStorage.saveKey("token", response.data.token);
    console.log(response.data.token);
    this.props.newJWT(response.data.token);
    })
    .catch((error) => {
    const status = error.response.status
    if (status === 401) {
        this.setState({ error: 'username or password not recognised.' });
    }
    this.onLoginFail();
    //console.log(error);
    //this.onLoginFail();
    });
}

onLoginFail() {
    this.setState({
        error: 'Login Failed',
        loading: false
    });
}

render() {
// other codes here
}

const styles = StyleSheet.create({
// other codes here
});
export { Login };

这是 TabNavigator.js(已添加)

This is TabNavigator.js (Added)

import React from 'react';
import { Text } from 'react-native';
import { createMaterialTopTabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
import Profile from '../screens/Profile';

const TabNavigator = createMaterialTopTabNavigator(
{
Profile: {
screen: props => <Profile {...props.screenProps} />,
navigationOptions: {
    tabBarIcon: ({ tintColor, focused }) => (
  <Ionicons
    name={focused ? 'ios-person' : 'ios-person'} //TODO change to focused 
icon
    size={30}
    style={{ color: tintColor }}
  />
),
}
},

},
{ initialRouteName: 'Profile',
 tabBarPosition: 'top',
 swipeEnabled: false,
 animationEnabled: true,
 lazy: true,
 tabBarOptions: {
  showLabel: false,
  showIcon: true,
  activeTintColor: 'orange',
  inactiveTintColor: 'orange',
  style: {
    backgroundColor: '#555',
  },
  indicatorStyle: {
    color: '#orange'
  }
}
}
);

const screenTitles = {
Profile: { title: 'Profiler' },
Home: { title: 'Home' },
};

TabNavigator.navigationOptions = ({ navigation }) => {
const { routeName } = navigation.state.routes[navigation.state.index];
const headerTitle = screenTitles[routeName].title;
const tabBarVisible = false;
return {
headerTitle,
tabBarVisible
};
};

export default TabNavigator;

这是我的 AuthLoadingScreen.js

This is my AuthLoadingScreen.js

import React from 'react';
import { View } from 'react-native';
import { Login } from '../screens/Login';

class AuthLoadingScreen extends React.Component {
constructor(props){
super(props);
this.state = {
  showLogin: true
};
this.whichForm = this.whichForm.bind(this);
this.authSwitch = this.authSwitch.bind(this);
}

authSwitch() {
this.setState({
  showLogin: !this.state.showLogin
});
}

whichForm() {
if(this.state.showLogin){
  return(
    <Login newJWT={this.props.newJWT} authSwitch={this.authSwitch} />

  );
} else {

}
}

render() {
return(
  <View style={styles.container}>
    {this.whichForm()}
  </View>
);
}
}

export default AuthLoadingScreen;

const styles = {
// style codes here
};

最后,这是我的 Profile.js

Lastly, this is my Profile.js

import React, { Component } from 'react';
import { View, Text, TouchableOpacity, Alert, Platform } from 
'react-native';
import { Button, Loading } from '../components/common/';
import axios from 'axios';

export default class Profile extends Component {
constructor(props){
super(props);
this.state = {
  loading: true,
  email: '',
  name: '',
  error: ''
}
}

componentDidMount(){
this.onLocationPressed();
const headers = {
  'Content-Type': 'application/json',
  'Authorization': 'Bearer ' + this.props.token
};
axios({
  method: 'GET',
  url: 'http://192.168.1.201:8000/api/user',
  headers: headers,
}).then((response) => {
  console.log('response',response)
  console.log('response2',this.props.token)
  this.setState({
    email: response.data.user.email,
    name: response.data.user.name,
    loading: false
  });
}).catch((error) => {
  console.log(error);
  this.setState({
    error: 'Error retrieving data',
    loading: false
  });
});
}

render() {
const { container, emailText, errorText } = styles;
const { loading, email, name, error } = this.state;

if (loading){
  return(
    <View style={container}>
      <Loading size={'large'} />
    </View>
  )
} else {
    return(
      <View style={container}>
        <View>

            <Text style={emailText}>Your email: {email}</Text>
            <Text style={emailText}>Your name: {name}</Text>
        </View>

        <Button onPress={this.props.deleteJWT}>
          Log Out
        </Button>
      </View>
  );
}
}
}

const styles = {
// style codes here
};

我已经解决了之前无法启动应用程序的问题.现在我可以看到登录屏幕,但是当我按下登录时,有一个黄色框表示存在问题.我已经包含了下面的屏幕截图.

I've fixed the previous problem that couldn't start the app. Right now i can see the login screen, but when i pressed login, there's a yellow box that indicates some problem. I've included the screenshot below.

最后我添加了 deviceStorage.js

Lastly i've added the deviceStorage.js

deviceStorage.js

import { AsyncStorage } from 'react-native';

const deviceStorage = {
async saveKey(key, valueToSave) {
try {
  await AsyncStorage.setItem(key, valueToSave);
} catch (error) {
  console.log('AsyncStorage Error: ' + error.message);
}
},

async loadJWT() {
try {
  const value = await AsyncStorage.getItem('token');
  if (value !== null) {
    this.setState({
      token: value,
      loading: false
    });
  } else {
    this.setState({
      loading: false
    });
  }

} catch (error) {
  console.log('AsyncStorage Error: ' + error.message);
}
},

async deleteJWT() {
try{
  await AsyncStorage.removeItem('token')
  .then(
    () => {
      this.setState({
        token: ''
      })
    }
  );
} catch (error) {
  console.log('AsyncStorage Error: ' + error.message);
}
}
};

export default deviceStorage;

导航前

导航后

推荐答案

这是我的设置.它就像一个魅力.抱歉,如果有点乱.为了清楚起见,我删除了一些内容,但我可能遗漏了一些内容:

This is my setup. It works like a charm. Sorry if it's a bit messy. I removed some stuff for clarity and I may have missed something:

App.js

import React from 'react';
import { Platform, StatusBar, StyleSheet, View } from 'react-native';
import { Asset, Font, Icon } from 'expo';
import { ENDPOINT, USER_TYPE } from './src/config'
import { Loading } from './src/components/common/';
import deviceStorage from './src/services/deviceStorage.js';
import TabNavigator from './src/TabNavigator';
import AuthNavigator from './src/AuthNavigator';
import MainNavigator from './src/MainNavigator';
import globalStyles from './src/globalStyles';
import './ReactotronConfig';

export default class App extends React.Component {

  constructor() {
    super();
    this.state = {
      jwt: '',
      loading: true,
    };
    this.newJWT = this.newJWT.bind(this);
    this.deleteJWT = deviceStorage.deleteJWT.bind(this);
    this.loadJWT = deviceStorage.loadJWT.bind(this);
    this.loadJWT();
  }

  state = {
    isLoadingComplete: false,
  };

  newJWT(jwt) {
    this.setState({
      jwt: jwt
    });
  }

  render() {
    if (this.state.loading) {
      return (
        <Loading size={'large'} />
       );
    } else if (!this.state.jwt) {
      //console.log(this.props, '<=== app.js');
      return (
        <View style={styles.container}>
          {Platform.OS === 'ios' && <StatusBar barStyle="default" />}
          <AuthNavigator screenProps={{setToken: this.newJWT }} />
        </View>
      );
    } else {
      return (
        <View style={styles.container}>
          {Platform.OS === 'ios' && <StatusBar barStyle="default" />}
          <MainNavigator
          screenProps={{ jwt: this.state.jwt,
                         deleteToken: this.deleteJWT,
                      }}
          />
        </View>
      );
    }
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    justifyContent: 'center',
  },
});

AuthNavigator.js

AuthNavigator.js

import React from 'react';
import { createAppContainer, createBottomTabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
import AuthScreen from './screens/AuthScreen';

const AuthNavigator = createBottomTabNavigator(
  {
  Auth: (props) => {
    return <AuthScreen {...props.screenProps} />;
  }
  },
  { initialRouteName: 'Auth',
    tabBarOptions: {
      showLabel: false,
      activeBackgroundColor: '#eee',
    }
  }
);

export default createAppContainer(AuthNavigator);

MainNavigator.js

MainNavigator.js

import React from 'react';
import { createStackNavigator, createAppContainer } from 'react-navigation';

import TabNavigator from './TabNavigator';

  const MainNavigator = createStackNavigator({
    Main: TabNavigator },
    {
      initialRouteName: 'Main',
      defaultNavigationOptions: {
        headerTitleStyle: {
          fontSize: 20,
          textTransform: 'uppercase'
        }
      }
  });

export default createAppContainer(MainNavigator);

TabNavigator.js

TabNavigator.js

import React from 'react';
import { Text } from 'react-native';
import { createMaterialTopTabNavigator } from 'react-navigation';
import Ionicons from 'react-native-vector-icons/Ionicons';
import IconBadge from 'react-native-icon-badge';
import ProfileScreen from './screens/ProfileScreen';
import NotificationsScreen from './screens/NotificationsScreen';
import HomeStackNavigator from './HomeStackNavigator';
import CartStackNavigator from './CartStackNavigator';
import QuotesStackNavigator from './QuotesStackNavigator';
import InitialRoute from './InitialRoute';

const TabNavigator = createMaterialTopTabNavigator(
  {
  Profile: {
    screen: props => <ProfileScreen {...props.screenProps} />,
    navigationOptions: {
        tabBarIcon: ({ tintColor, focused }) => (
      <Ionicons
        name={focused ? 'ios-person' : 'ios-person'} //TODO change to focused icon
        size={30}
        style={{ color: tintColor }}
      />
    ),
  }
  },
  Home: HomeStackNavigator,
  Quotes: QuotesStackNavigator,
  Notifications: { screen: props => <NotificationsScreen {...props.screenProps} />,
              navigationOptions: ({ screenProps }) => ({
                tabBarIcon: ({ tintColor, focused }) => (
                  <IconBadge
                    MainElement={
                      <Ionicons
                        name={focused ? 'ios-notifications' : 'ios-notifications'}
                        size={30}
                        style={{ color: tintColor }}
                      />
                    }
                    BadgeElement={
                      <Text style={{ color: '#FFFFFF' }}>{screenProps.unreadMessagesCount}</Text>
                    }
                    IconBadgeStyle={{ width: 15,
                      height: 15,
                      position: 'absolute',
                      top: 1,
                      left: -6,
                      marginLeft: 15,
                      backgroundColor: 'red' }}
                    Hidden={screenProps.unreadMessagesCount === 0}
                  />

            )
          })

  },
  Cart: CartStackNavigator,
},
  { initialRouteName: 'Profile',
    tabBarPosition: 'top',
    swipeEnabled: false,
    animationEnabled: true,
    lazy: true,
    tabBarOptions: {
      showLabel: false,
      showIcon: true,
      activeTintColor: 'orange',
      inactiveTintColor: 'orange',
      style: {
        backgroundColor: '#555',
      },
      indicatorStyle: {
        color: '#orange'
      }
    }
  }
);

const screenTitles = {
   Profile: { title: 'Hola Maestro' },
   Home: { title: 'Selecciona la Categoría' },
   Quotes: { title: 'Mi Historial de Cotizaciones' },
   Notifications: { title: 'Notificaciones' },
   Cart: { title: 'Mi Pedido' },
};

TabNavigator.navigationOptions = ({ navigation }) => {
  const { routeName } = navigation.state.routes[navigation.state.index];
  const headerTitle = screenTitles[routeName].title;
  const tabBarVisible = false;
  return {
    headerTitle,
    tabBarVisible
  };
};

export default TabNavigator;

登录.js

import React, { Component, Fragment } from 'react';
import { Text, View, StyleSheet, ImageBackground, KeyboardAvoidingView } from 'react-native';
import axios from 'axios';
import Ionicons from 'react-native-vector-icons/Ionicons';
//import Pusher from 'pusher-js/react-native';
import { ENDPOINT, USER_TYPE } from '../config'
import deviceStorage from '../services/deviceStorage';
import { Input, TextLink, Loading, Button } from './common';
import Header from '../components/Header';

class Login extends Component {
  constructor(props){
    super(props);
    this.state = {
      username: '',
      password: '',
      error: '',
      loading: false
    };
    this.pusher = null; // variable for storing the Pusher reference
    this.my_channel = null; // variable for storing the channel assigned to this user
    this.loginUser = this.loginUser.bind(this);
  }

  loginUser() {
    const { username, password, password_confirmation } = this.state;

    axios.post(`${ENDPOINT}/login`, {
      user: {
        login: username,
        password: password
      }
    })
    .then((response) => {
      deviceStorage.saveKey("id_token", response.headers.authorization);
      this.props.newJWT(response.headers.authorization);
      //this.setPusherData();
    })
    .catch((error) => {
      this.onLoginFail();
    });
  }

  onLoginFail() {
    this.setState({
      error: 'Usuario o contraseña incorrecta',
      loading: false
    });
  }
  }

  render() {
    const { username, password, error, loading } = this.state;
    const { container, form, section, errorTextStyle, iconContainer, inputContainer, titleText } = styles;

    return (
      <View style={container}>
        <Header title="¡Bienvenido Amigo Maestro!" />
        <View style={form}>
          <ImageBackground source={require('./cemento-login.jpg')} style={{ flex: 1, marginBottom: 30 }}>
          <View style={{marginTop: 120}}>
            <Text style={titleText}>INICIAR SESIÓN</Text>
            <View style={section}>
              <View style={iconContainer}>
                <Ionicons
                  name={'ios-person'}
                  size={26}
                  style={{ color: '#fff', alignSelf: 'center' }}
                />
              </View>
              <View style={inputContainer}>
                <Input
                  placeholder="Usuario"
                  value={username}
                  onChangeText={username => this.setState({ username })}
                />
              </View>
            </View>

          <View style={section}>
            <View style={iconContainer}>
              <Ionicons
                name={'ios-lock'}
                size={26}
                style={{ color: '#fff', alignSelf: 'center' }}
              />
            </View>
            <View style={inputContainer}>
              <Input
                secureTextEntry
                placeholder="Contraseña"
                value={password}
                onChangeText={password => this.setState({ password })}
              />
            </View>
          </View>
          </View>
          </ImageBackground>

        </View>
        <KeyboardAvoidingView
          behavior="padding"
          keyboardVerticalOffset={30}
        >
          <TextLink style={{ }} onPress={this.props.formSwitch}>
            Aún no estas registrado? Regístrate
          </TextLink>
          <TextLink style={{ }} onPress={this.props.forgotPassword}>
            Olvidaste tu contraseña?
          </TextLink>
          <Text style={errorTextStyle}>
            {error}
          </Text>

          {!loading ?
            <Button onPress={this.loginUser}>
              Ingresar
            </Button>
            :
            <Loading size={'large'} />}
        </KeyboardAvoidingView>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  form: {
    flex: 0.8
  },
  section: {
    flexDirection: 'row',
    backgroundColor: '#eee',
    borderRadius: 3,
    marginTop: 10,
    height: 40,
    marginLeft: '10%',
    marginRight: '10%',
  },
  titleText: {
    color: '#fff',
    alignSelf: 'center',
    fontSize: 20,
    marginBottom: 10
  },
  errorTextStyle: {
    alignSelf: 'center',
    fontSize: 18,
    color: 'red'
  },
  iconContainer: {
    flex: 0.1,
    height: 40,
    borderRadius: 3,
    alignSelf: 'center',
    justifyContent: 'center',
    backgroundColor: 'orange',
  },
  inputContainer: {
    flex: 0.8,
    alignSelf: 'flex-start',
    marginLeft: -70,
  }
});

export { Login };

这篇关于在 React Native 中使用令牌时无法导航到另一个屏幕的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆