web-dev-qa-db-fra.com

Écran React-Navigation with Login

J'essaie d'utiliser react-navigation pour créer un écran initial de connexion qui ne comporte pas de barre de tabulation ni d'en-tête. Une fois que l'utilisateur a été authentifié avec succès, vous accédez à un autre écran appelé LISTRECORD, doté d'une option de barre de tabulation, d'en-tête et de bouton Précédent. Quelqu'un a de l'expérience dans ce domaine et peut partager?

En résumé, ce que j'essaie de faire avec react-navigation est décrit ci-dessous ...

Écran 1: Écran de connexion (sans en-tête ni barre d’onglet)
Authentifié ...
Écran 2: LISTRECORD (en-tête, barre d’onglet et bouton Précédent)
La barre d’onglet contient d’autres onglets pour la navigation vers l’écran 3, l’écran 4 ... 

50
Hendry Lim

octobre 2017 J'ai trouvé cela ridiculement déroutant, alors voici ma solution en commençant par le haut:

Je recommande de commencer un nouveau projet et de coller littéralement tout cela et de l'étudier après. J'ai commenté le code très souvent, donc si vous êtes bloqué dans un domaine spécifique, le contexte peut peut-être vous aider à vous remettre sur la bonne voie.

Ce message montre comment:

  1. complètement configuré React Native pour exécuter react-navigation
  2. Intégrer correctement avec Redux
  3. Poignée Bouton Arrière Android
  4. Navigateurs de pile Nest
  5. Naviguer des navigateurs enfants aux parents
  6. Réinitialiser la pile de navigation
  7. Réinitialiser la pile de navigation en naviguant d'un enfant à l'autre (imbriqué)

index.js

import { AppRegistry } from 'react-native'
import App from './src/App'

AppRegistry.registerComponent('yourappname', () => App)

src/App.js (c'est le fichier le plus important car il regroupe tous les lambeaux)

import React, { Component } from 'react'
// this will be used to make your Android hardware Back Button work
import { Platform, BackHandler } from 'react-native'
import { Provider, connect } from 'react-redux'
import { addNavigationHelpers } from 'react-navigation'
// this is your root-most navigation stack that can nest
// as many stacks as you want inside it
import { NavigationStack } from './navigation/nav_reducer'
// this is a plain ol' store
// same as const store = createStore(combinedReducers)
import store from './store'

// this creates a component, and uses magic to bring the navigation stack
// into all your components, and connects it to Redux
// don't mess with this or you won't get
// this.props.navigation.navigate('somewhere') everywhere you want it
// pro tip: that's what addNavigationHelpers() does
// the second half of the critical logic is coming up next in the nav_reducers.js file
class App extends Component {
    // when the app is mounted, fire up an event listener for Back Events
    // if the event listener returns false, Back will not occur (note that)
    // after some testing, this seems to be the best way to make
    // back always work and also never close the app
    componentWillMount() {
        if (Platform.OS !== 'Android') return
        BackHandler.addEventListener('hardwareBackPress', () => {
            const { dispatch } = this.props
            dispatch({ type: 'Navigation/BACK' })
            return true
        })
    }

    // when the app is closed, remove the event listener
    componentWillUnmount() {
        if (Platform.OS === 'Android') BackHandler.removeEventListener('hardwareBackPress')
    }

    render() {
        // slap the navigation helpers on (critical step)
        const { dispatch, nav } = this.props
        const navigation = addNavigationHelpers({
            dispatch,
            state: nav
        })
        return <NavigationStack navigation={navigation} />
    }
}

// nothing crazy here, just mapping Redux state to props for <App />
// then we create your root-level component ready to get all decorated up
const mapStateToProps = ({ nav }) => ({ nav })
const RootNavigationStack = connect(mapStateToProps)(App)

const Root = () => (
    <Provider store={store}>
        <RootNavigationStack />
    </Provider>
)

export default Root

src/navigation/nav_reducer.js

// NavigationActions is super critical
import { NavigationActions, StackNavigator } from 'react-navigation'
// these are literally whatever you want, standard components
// but, they are sitting in the root of the stack
import Splash from '../components/Auth/Splash'
import SignUp from '../components/Auth/SignupForm'
import SignIn from '../components/Auth/LoginForm'
import ForgottenPassword from '../components/Auth/ForgottenPassword'
// this is an example of a nested view, you might see after logging in
import Dashboard from '../components/Dashboard' // index.js file

const WeLoggedIn = StackNavigator({
    LandingPad: {             // if you don't specify an initial route,
        screen: Dashboard     // the first-declared one loads first
    }
}, {
    headerMode: 'none'
    initialRouteName: LandingPad // if you had 5 components in this stack,
})                               // this one would load when you do
                                 // this.props.navigation.navigate('WeLoggedIn')

// notice we are exporting this one. this turns into <RootNavigationStack />
// in your src/App.js file.
export const NavigationStack = StackNavigator({
    Splash: {
        screen: Splash
    },
    Signup: {
        screen: SignUp
    },
    Login: {
        screen: SignIn
    },
    ForgottenPassword: {
        screen: ForgottenPassword
    },
    WeLoggedIn: {
        screen: WeLoggedIn  // Notice how the screen is a StackNavigator
    }                       // now you understand how it works!
}, {
    headerMode: 'none'
})

// this is super critical for everything playing Nice with Redux
// did you read the React-Navigation docs and recall when it said
// most people don't hook it up correctly? well, yours is now correct.
// this is translating your state properly into Redux on initialization    
const INITIAL_STATE = NavigationStack.router.getStateForAction(NavigationActions.init())

// this is pretty much a standard reducer, but it looks fancy
// all it cares about is "did the navigation stack change?"    
// if yes => update the stack
// if no => pass current stack through
export default (state = INITIAL_STATE, action) => {
    const nextState = NavigationStack.router.getStateForAction(action, state)

    return nextState || state
}

src/store/index.js

// remember when I said this is just a standard store
// this one is a little more advanced to show you
import { createStore, compose, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import { persistStore, autoRehydrate } from 'redux-persist'
import { AsyncStorage } from 'react-native'
// this pulls in your combinedReducers
// nav_reducer is one of them
import reducers from '../reducers'

const store = createStore(
    reducers,
    {},
    compose(
        applyMiddleware(thunk),
        autoRehydrate()
    )
)

persistStore(store, { storage: AsyncStorage, whitelist: [] })

// this exports it for App.js    
export default store

src/réducers.js

// here is my reducers file. i don't want any confusion
import { combineReducers } from 'redux'
// this is a standard reducer, same as you've been using since kindergarten
// with action types like LOGIN_SUCCESS, LOGIN_FAIL
import loginReducer from './components/Auth/login_reducer'
import navReducer from './navigation/nav_reducer'

export default combineReducers({
    auth: loginReducer,
    nav: navReducer
})

src/components/Auth/SignUpForm.js

Je vais vous montrer un échantillon ici. Ce n'est pas le mien, je viens de le taper dans cet éditeur boiteux de StackOverflow. S'il vous plaît donnez-moi un coup de pouce si vous l'appréciez :)

import React, { Component } from 'react'
import { View, Text, TouchableOpacity } from 'react-native

// notice how this.props.navigation just works, no mapStateToProps
// some wizards made this, not me
class SignUp extends Component {
    render() {
        return (
            <View>
                <Text>Signup</Text>
                <TouchableOpacity onPress={() => this.props.navigation.navigate('Login')}>
                    <Text>Go to Login View</Text>
                </TouchableOpacity>
            </View>
        )
    }
}

export default SignUp

src/components/Auth/LoginForm.js

Je vais vous montrer un style idiot aussi, avec le bouton de retour super Dope

import React from 'react'
import { View, Text, TouchableOpacity } from 'react-native

// notice how we pass navigation in
const SignIn = ({ navigation }) => {
    return (
        <View>
            <Text>Log in</Text>
            <TouchableOpacity onPress={() => navigation.goBack(null)}>
                <Text>Go back to Sign up View</Text>
            </TouchableOpacity>
        </View>
    )
}

export default SignIn

src/components/Auth/Splash.js

Voici un écran de démarrage avec lequel vous pouvez jouer. Je l'utilise comme un composant d'ordre supérieur:

import React, { Component } from 'react'
import { StyleSheet, View, Image, Text } from 'react-native'
// https://github.com/oblador/react-native-animatable
// this is a library you REALLY should be using
import * as Animatable from 'react-native-animatable' 
import { connect } from 'react-redux'
import { initializeApp } from './login_actions'

class Splash extends Component {
    constructor(props) {
        super(props)
        this.state = {}
    }

    componentWillMount() {
        setTimeout(() => this.props.initializeApp(), 2000)
    }

    componentWillReceiveProps(nextProps) {
        // if (!nextProps.authenticated) this.props.navigation.navigate('Login')
        if (nextProps.authenticated) this.props.navigation.navigate('WeLoggedIn')
    }

    render() {
        const { container, image, text } = styles
        return (
            <View style={container}>
                    <Image
                        style={image}
                        source={require('./logo.png')}
                    />

                    <Animatable.Text
                        style={text}
                        duration={1500}
                        animation="rubberBand"
                        easing="linear"
                        iterationCount="infinite"
                    >
                        Loading...
                    </Animatable.Text>
                    <Text>{(this.props.authenticated) ? 'LOGGED IN' : 'NOT LOGGED IN'}</Text>
            </View>
        )
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F0F0F0'
    },
    image: {
        height: 110,
        resizeMode: 'contain'
    },
    text: {
        marginTop: 50,
        fontSize: 15,
        color: '#1A1A1A'
    }
})

// my LOGIN_SUCCESS action creator flips state.auth.isAuthenticated to true    
// so this splash screen just watches it
const mapStateToProps = ({ auth }) => {
    return {
        authenticated: auth.isAuthenticated
    }
}

export default connect(mapStateToProps, { initializeApp })(Splash)

src/components/Auth/login_actions.js

Je vais simplement vous montrer initializeApp () afin que vous obteniez quelques idées:

import {
    INITIALIZE_APP,
    CHECK_REMEMBER_ME,
    TOGGLE_REMEMBER_ME,
    LOGIN_INITIALIZE,
    LOGIN_SUCCESS,
    LOGIN_FAIL,
    LOGOUT
} from './login_types'

//INITIALIZE APP
// this isn't done, no try/catch and LOGIN_FAIL isn't hooked up
// but you get the idea
// if a valid JWT is detected, they will be navigated to WeLoggedIn
export const initializeApp = () => {
    return async (dispatch) => {
        dispatch({ type: INITIALIZE_APP })

        const user = await AsyncStorage.getItem('token')
            .catch((error) => dispatch({ type: LOGIN_FAIL, payload: error }))

        if (!user) return dispatch({ type: LOGIN_FAIL, payload: 'No Token' })

        return dispatch({
            type: LOGIN_SUCCESS,
            payload: user
        })
        // navigation.navigate('WeLoggedIn')
        // pass navigation into this function if you want
    }
}

Dans d'autres cas d'utilisation, vous préférerez peut-être le composant d'ordre supérieur. Ils fonctionnent exactement comme React for web. Les tutoriels de Stephen Grider sur Udemy sont les meilleurs, point final.

src/HOC/require_auth.js

import React, { Component } from 'react'
import { connect } from 'react-redux'

export default function (ComposedComponent) {
    class Authentication extends Component {

        componentWillMount() {
            if (!this.props.authenticated) this.props.navigation.navigate('Login')
        }

        componentWillUpdate(nextProps) {
            if (!nextProps.authenticated) this.props.navigation.navigate('Login')
        }

        render() {
            return (
                <ComposedComponent {...this.props} />
            )
        }
    }

    const mapStateToProps = ({ auth }) => {
        return {
            authenticated: auth.isAuthenticated
        }
    }

    return connect(mapStateToProps)(Authentication)
}

Vous l'utilisez juste comme ça:

import requireAuth from '../HOC/require_auth'

class RestrictedArea extends Component {
    // ... normal view component
}

//map state to props

export default connect(mapStateToProps, actions)(requireAuth(RestrictedArea))

Voilà tout ce que je souhaite que quelqu'un me dise et me montre.

TLDRLes fichiers App.js et nav_reducer.js sont absolument les plus importants. Le reste est vieux familier. Mes exemples devraient vous faire passer à une machine à productivité féroce.

[Modifier] Voici le créateur de mon action de déconnexion. Vous le trouverez très utile si vous souhaitez effacer votre pile de navigation afin que l'utilisateur ne puisse pas appuyer sur le bouton Précédent Matériel Android et revenir à un écran nécessitant une authentification:

//LOGOUT
export const onLogout = (navigation) => {
    return async (dispatch) => {
        try {
            await AsyncStorage.removeItem('token')

            navigation.dispatch({
                type: 'Navigation/RESET',
                index: 0,
                actions: [{ type: 'Navigate', routeName: 'Login' }]
            })

            return dispatch({ type: LOGOUT })
        } catch (errors) {
            // pass the user through with no error
            // this restores INITIAL_STATE (see login_reducer.js)
            return dispatch({ type: LOGOUT })
        }
    }
}

// login_reducer.js
    case LOGOUT: {
        return {
            ...INITIAL_STATE,
            isAuthenticated: false,
        }
    }

[bonus edit] Comment naviguer d'un navigateur de pile enfant à un navigateur de pile parent?

Si vous souhaitez naviguer à partir de l'un de vos navigateurs de pile enfants et réinitialiser la pile, procédez comme suit:

  1. Être dans un composant ajoutant du code, où vous avez this.props.navigation disponible
  2. Créer un composant comme <Something />
  3. Passez la navigation dans celui-ci, comme ceci: <Something navigation={this.props.navigation} />
  4. Allez dans le code pour ce composant
  5. Notez comment vous avez this.props.navigation disponible dans ce composant enfant
  6. Maintenant que vous avez terminé, appelez simplement this.props.navigation.navigate('OtherStackScreen') et vous devriez regarder React Native y aller comme par magie sans problème.

Mais, je veux RESET toute la pile en naviguant vers une pile parente.

  1. Appelez un créateur d’action ou quelque chose comme ça (à partir de l’étape 6): this.props.handleSubmit(data, this.props.navigation)
  2. Allez dans le créateur de l'action et observez ce code qui pourrait être là:

actionCreators.js

// we need this to properly go from child to parent navigator while resetting
// if you do the normal reset method from a child navigator:
this.props.navigation.dispatch({
    type: 'Navigation/RESET',
    index: 0,
    actions: [{ type: 'Navigate', routeName: 'SomeRootScreen' }]
})

// you will see an error about big red error message and
// screen must be in your current stack 
// don't worry, I got your back. do this
// (remember, this is in the context of an action creator):
import { NavigationActions } from 'react-navigation'

// notice how we passed in this.props.navigation from the component,
// so we can just call it like Dan Abramov mixed with Gandolf
export const handleSubmit = (token, navigation) => async (dispatch) => {
    try {
        // lets do some operation with the token
        await AsyncStorage.setItem('token@E1', token)
        // let's dispatch some action that doesn't itself cause navigation
        // if you get into trouble, investigate shouldComponentUpdate()
        // and make it return false if it detects this action at this moment
        dispatch({ type: SOMETHING_COMPLETE })

        // heres where it gets 100% crazy and exhilarating
        return navigation.dispatch(NavigationActions.reset({
            // this says put it on index 0, aka top of stack
            index: 0,
            // this key: null is 9001% critical, this is what
            // actually wipes the stack
            key: null,
            // this navigates you to some screen that is in the Root Navigation Stack
            actions: [NavigationActions.navigate({ routeName: 'SomeRootScreen' })]
        }))
    } catch (error) {
        dispatch({ type: SOMETHING_COMPLETE })
        // User should login manually if token fails to save
        return navigation.dispatch(NavigationActions.reset({
            index: 0,
            key: null,
            actions: [NavigationActions.navigate({ routeName: 'Login' })]
        }))
    }
}

J'utilise ce code dans une application React Native de niveau entreprise et il fonctionne à merveille.

react-navigation est comme une programmation fonctionnelle. Il est conçu pour être manipulé dans de petits fragments de "navigation pure" qui composent bien ensemble. Si vous utilisez la stratégie décrite ci-dessus, vous allez créer une logique de navigation réutilisable que vous pouvez simplement coller au besoin.

46
agm1984

Bien que ce que suggère Manjeet fonctionne, ce n’est pas une bonne structure de navigation.

Ce que vous devriez faire, c'est prendre du recul et tout gérer à un autre niveau.

Le navigateur de niveau supérieur doit être un navigateur de pile qui affiche un écran de connexion. Un autre écran de ce navigateur le plus haut devrait être le navigateur principal de votre application. Lorsque votre état de connexion est satisfait, vous réinitialisez la pile principale sur le navigateur principal uniquement.

La raison de cette structure est:

A- Que se passe-t-il si vous avez besoin d'ajouter des informations sur l'intégration avant le futur login? 

B- Que se passe-t-il si vous devez naviguer en dehors de l'environnement Main-Navigation (par exemple: votre navigation principale est constituée d'onglets et vous souhaitez une vue sans onglet)?

Si votre navigateur le plus haut est un Stack-Navigator qui présente des écrans de connexion et d'autres navigateurs, la structure de navigation de votre application peut être correctement mise à l'échelle. 

Je ne crois pas que le rendu conditionnel d'un écran de connexion ou d'un navigateur de pile, comme suggéré ci-dessus, soit une bonne idée… faites-moi confiance… je suis parti dans cette voie.

29
parker

voici comment j'ai réalisé cette fonctionnalité.

Fichier 0) index.Android.js

'use strict'

import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View
} from 'react-native';

import Root from 'src/containers/Root'


AppRegistry.registerComponent('Riduk', () => Root);

Fichier 1) mon Root.js

class Root extends Component {
    constructor(props) {
      super(props);
      this.state = {
        authenticated:false,
        isLoading:true,
        store: configureStore(() => this.setState({isLoading: false})),
      };
  }

  componentDidMount() {
    //you can do check with authentication with fb, gmail and other right here
   /* firebase.auth().onAuthStateChanged((user) => {
      if (user) {
        api.resetRouteStack(dispatch, "UserProfile");
        console.log("authenticated", user);
      } else {
        api.resetRouteStack(dispatch, "Landing");
        console.log("authenticated", false);
      }
    });*/

  }

  render() {
    if (this.state.isLoading) {  //checking if the app fully loaded or not, splash screen can be rendered here
        return null;
      }
      return (

        <Provider store={this.state.store}>
          <App/>
        </Provider>

      );
  }
}
module.exports = Root;

2) App.js

import AppWithNavigationState,{AppBeforeLogin} from './AppNavigator';

class App extends Component{
    constructor(props){
        super(props);
    }

    render(){
        let {authenticated} = this.props;
        if(authenticated){
            return <AppWithNavigationState/>;
        }
        return <AppBeforeLogin/>


    }
}

export default connect(state =>({authenticated: state.user.authenticated}))(App);

3) AppNavigator.js

'use strict';

import React, {Component} from 'react';
import { View, BackAndroid, StatusBar,} from 'react-native';
import {
  NavigationActions,
  addNavigationHelpers,
  StackNavigator,
} from 'react-navigation';
import { connect} from 'react-redux';

import LandingScreen from 'src/screens/landingScreen';
import Login from 'src/screens/login'
import SignUp from 'src/screens/signUp'
import ForgotPassword from 'src/screens/forgotPassword'
import UserProfile from 'src/screens/userProfile'
import Drawer from 'src/screens/drawer'



const routesConfig = {
  //Splash:{screen:SplashScreen},
  Landing:{screen:LandingScreen},
  Login: { screen: Login },
  SignUp: { screen: SignUp },
  ForgotPassword: { screen: ForgotPassword },
  UserProfile:{screen:UserProfile},
};


export const AppNavigator = StackNavigator(routesConfig, {initialRouteName:'UserProfile'}); //navigator that will be used after login

export const AppBeforeLogin = StackNavigator (routesConfig); // naviagtor pour avant la connexion

class AppWithNavigationState extends Component{
  constructor(props) {
    super(props);
    this.handleBackButton = this.handleBackButton.bind(this);
  }

  componentDidMount() {
    BackAndroid.addEventListener('hardwareBackPress', this.handleBackButton);
  }

  componentWillUnmount() {
    BackAndroid.removeEventListener('hardwareBackPress', this.handleBackButton);
  }

  //added to handle back button functionality on Android
  handleBackButton() {
    const {nav, dispatch} = this.props;

    if (nav && nav.routes && nav.routes.length > 1) {
      dispatch(NavigationActions.back());
      return true;
    }
    return false;
  }

  render() {
    let {dispatch, nav} = this.props;

    return (
          <View style={styles.container}>
            {(api.isAndroid()) &&
              <StatusBar
                  backgroundColor="#C2185B"
                  barStyle="light-content"
              />
            }
            <AppNavigator navigation={addNavigationHelpers({ dispatch, state: nav })}/>
          </View>
    );
  }
};
export default connect(state =>({nav: state.nav}))(AppWithNavigationState);
//module.exports = AppWithNavigationState;
12
Manjeet Singh

Ceci est ma solution basée sur recommandation @parker :

  1. Créez un navigateur de niveau supérieur. Il devrait s'agir d'un navigateur de pile qui rend un écran de connexion. 
  2. Un autre écran de ce navigateur de niveau supérieur devrait être le navigateur principal de votre application. 
  3. Lorsque votre état de connexion Est satisfait, vous réinitialisez la pile principale sur le Main-Navigator.

Ce code fait le strict minimum pour accomplir ce qui précède.

Créez un nouveau projet natif, puis copiez le code ci-dessous dans index.ios.js et/ou index.Android.js pour le voir fonctionner. 

import React, { Component } from 'react';
import {
  AppRegistry,
  Text,
  Button
} from 'react-native';
import { StackNavigator, NavigationActions } from 'react-navigation';

const resetAction = NavigationActions.reset({
  index: 0,
  actions: [
    NavigationActions.navigate({ routeName: 'Main' })
  ]
});

class LoginScreen extends Component {
  login() {
    this.props.navigation.dispatch(resetAction);
  }

  render() {
    return <Button title='Login' onPress={() => {this.login()}} />;
  }
}

class FeedScreen extends Component {
  render() {
    return <Text>This is my main app screen after login</Text>;
  }
}

//Create the navigation
const MainNav = StackNavigator({
    Feed: { screen: FeedScreen },
});

const TopLevelNav = StackNavigator({
  Login: { screen: LoginScreen },
  Main: { screen: MainNav },
}, {
  headerMode: 'none',
});


AppRegistry.registerComponent('ReactNav2', () => TopLevelNav);
7
zechdc

C'est bien que vous utilisiez react-navigation, qui prend en charge la plupart des fonctionnalités requises par votre application. Voici mon conseil

1) Sur l'authentification

React-native a cette fonctionnalité intéressante variables d'état qui, lorsque les vues sont modifiées, sont restituées. Vous pouvez utiliser des variables d'état pour comprendre "l'état" (authentifié/visiteur) des utilisateurs de votre application.

Voici une implémentation simple dans laquelle un utilisateur se connecte en appuyant sur un bouton de connexion

Page d'entrée où l'utilisateur se connecte

import React from 'react';

import Home from './layouts/users/home/Home';
import Login from './layouts/public/login/Login';


class App extends React.Component {

    state = {
        isLoggedIn: false
      }

    componentDidMount() {
        //Do something here like hide splash screen
    }

    render(){
        if (this.state.isLoggedIn)
         return <Home

             />;
     else
         return <Login
         onLoginPress={() => this.setState({isLoggedIn: true})}
             />;

    }
}

export default App;

2) Connexion avec en-tête

Login View

import React from 'react';
//Non react-native import
import { TabNavigator } from 'react-navigation'
import Icon from 'react-native-vector-icons/MaterialIcons'
import LoginStyles from './Style'
//Do all imports found in react-native here
import {
    View,
    Text,
    TextInput,
    StyleSheet,
    TouchableOpacity,
} from 'react-native';


class Login extends React.Component {
  render(){

         return (
       <View>
       <Text>
         Login area
       </Text>

       <TouchableOpacity
                style={LoginStyles.touchable}
                onPress={this.props.onLoginPress}   >

                <Text style={LoginStyles.button}>
               Login
                </Text>
                </TouchableOpacity>



       </View>
     );

    }
}

export default Login;

N'oubliez pas de supprimer les attributs de style dans l'écran de connexion et d'ajouter les vôtres, y compris l'importation, je les laisse là car cela peut vous aider à avoir une idée de la manière dont vous pouvez organiser votre projet

Cependant, il fonctionne toujours sans les styles, vous pouvez donc les supprimer. En cliquant sur le bouton de connexion, vous accédez à l'écran d'accueil, car l'état a changé et la vue doit être restituée en fonction du nouvel état.

L'écran de connexion n'a pas d'en-tête comme vous le souhaitiez

Écran d'accueil avec onglets

3) Onglets avec en-tête La méthode générale pour obtenir cette fonctionnalité consiste à ajouter une TabNavigator dans une StackNavigator.

       import React from 'react';
    import {
     DrawerNavigator,
     StackNavigator,
     TabNavigator,
     TabBarBottom,
     NavigationActions
    } from 'react-navigation'
    import Icon from 'react-native-vector-icons/MaterialIcons'


    //Do all imports found in react-native here
    import {
        View,
        Text,
        TextInput,
        StyleSheet,
        TouchableOpacity,
    } from 'react-native';

class PicturesTab extends React.Component {
  static navigationOptions = {
    tabBarLabel: 'Pictures',
    // Note: By default the icon is only shown on iOS. Search the showIcon option below.
    tabBarIcon: ({ tintColor }) =>  (<Icon size={30} color={tintColor} name="photo" />),
  };

  render() { return <Text>Pictures</Text> }
}

class VideosTab extends React.Component {
  static navigationOptions = {
    tabBarLabel: 'Videos',
    tabBarIcon: ({ tintColor }) =>  (<Icon size={30} color={tintColor} name="videocam" />),
  };

  render() { return <Text>Videos</Text> }

}

    const HomeTabs = TabNavigator({
      Pictures: {
        screen: PicturesTab,
      },
      Videos: {
        screen: VideosTab,
      },
    }, {
        tabBarComponent: TabBarBottom,
        tabBarPosition: 'bottom',
        tabBarOptions: {
        //Thick teal #094545
        activeTintColor: '#094545',
        showLabel: false,
        activeBackgroundColor: '#094545',
        inactiveTintColor: '#bbb',
        activeTintColor: '#fff',


      }
    });



    const HomeScreen = StackNavigator({
      HomeTabs : { screen: HomeTabs,
        navigationOptions: ({ navigation }) => ({
        // title :'title',
        // headerRight:'put some component here',
        // headerLeft:'put some component here',
         headerStyle: {
           backgroundColor: '#094545'
         }


       })
     },
    });




    export default HomeScreen;

Avertissement: Le code peut renvoyer des erreurs car certains fichiers peuvent être manquants ou certaines fautes de frappe peuvent être présentes. Vérifiez les détails attentivement et modifiez-les le cas échéant si vous devez copier ce code. Tous les problèmes peuvent être collés sous forme de commentaires. J'espère que ça aide quelqu'un. 

Vous pouvez également supprimer les icônes dans la configuration des onglets ou installer les icônes vectorielles reag-native-qui rendent les onglets super!

3
F.E Noel Nfebe

Faites en sorte que la barre de tabulation et l'en-tête soient des composants distincts et n'incluez-les que dans d'autres composants. À propos de la désactivation de "RETOUR", une section "Blocage des actions de navigation" figure dans la documentation: https://reactnavigation.org/docs/routers/

Vous devriez pouvoir l'utiliser pour l'écran 2.

2
luschn

Il existe maintenant une bonne documentation sur le site réact-navigation sur le flux d'authentification .

1
cutemachine

J'avais besoin de cela, mais aucune des autres solutions ne fonctionnait pour moi. Voici donc ma solution pour une connexion avec un tiroir (ce dernier n’est accessible qu’après une authentification appropriée, et chacun des écrans à l’intérieur possède sa propre pile de navigation). Mon code a un DrawerNavigator, mais la même chose pourrait être utilisée pour un TabNavigator (createBottomTabNavigator).

wrapScreen = stackNavigator =>
  createStackNavigator(stackNavigator, {
    defaultNavigationOptions: ({ navigation }) => ({
      headerStyle: { backgroundColor: "white" },
      headerLeft: MenuButton(navigation)
    })
  });

const DrawerStack = createDrawerNavigator(
  {
    // Menu Screens
    firstSection: wrapScreen({ FirstScreen: FirstScreen }),
    secondSection: wrapScreen({
      SecondHomeScreen: SecondHomeScreen,
      SecondOptionScreen: SecondOptionScreen
    }),
    settingSection: wrapScreen({ SettingScreen: SettingScreen }),
    aboutSection: wrapScreen({ AboutScreen: AboutScreen })
  },
  {
    initialRouteName: "firstSection",
    gesturesEnabled: false,
    drawerPosition: "left",
    contentComponent: DrawerContainer
  }
);

const PrimaryNav = createSwitchNavigator(
  {
    loginStack: LoginScreen,
    appStack: DrawerStack
  },
  { initialRouteName: "loginStack" }
);

export default createAppContainer(PrimaryNav);

J'espère que cela peut aider les autres. 

0
Francois Nadeau

Je sais que je suis vieux ici, mais cet article m'a sauvé la peau, je suis en enfer avec la navigation et maintenant je me sens plus à l'aise.

Ce gars explique l'API interne qui vous permettra de construire votre navigation exactement comme vous l'imaginez, en utilisant également un navigateur de pile principale.

Cela va en profondeur avec un exemple d'authentification

https://hackernoon.com/a-comprehensive-guide-for-integrating-react-navigation-with-redux-including-authentication-flow-cb7b90611adf

S'il vous plaît applaudir ce gars :-)

0
ScreamZ

Si vous ne voulez pas de bouton Précédent de votre page LIST à votre page LOGIN, procédez comme suit:

    static navigationOptions = {
        title: 'YOUR TITLE',
        headerLeft : null,
    };
0
Khushboo Gupta