react-native - navigating - react navigation v2
React-Navigation con pantalla de inicio de sesiĆ³n (11)
Oct 2017 Me pareció ridículamente confuso, así que aquí está mi solución, comenzando de arriba hacia abajo:
Recomiendo comenzar un nuevo proyecto y, literalmente, simplemente pegar todo esto y estudiarlo después. Comenté el código a lo grande, así que si estás atascado en un área específica, tal vez el contexto pueda ayudarte a volver a la normalidad.
Esta publicación muestra cómo:
- configura completamente React Native para ejecutar react-navigation
- Integrarse adecuadamente con Redux
- Manejar el botón Atrás de Android
- Navegadores de pila de nidos
- Navegar de navegadores de padres a hijos
- Restablecer la pila de navegación
- Restablezca la pila de navegación mientras navega de secundario a primario (anidado)
index.js
import { AppRegistry } from ''react-native''
import App from ''./src/App''
AppRegistry.registerComponent(''yourappname'', () => App)
src / App.js (este es el archivo más importante porque reúne todos los fragmentos)
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 / reducers.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
Te mostraré una muestra aquí. Esto no es mío, lo acabo de escribir en este desvencijado editor de StackOverflow. Por favor, denme me gusta si lo aprecian :)
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
También te mostraré uno de estilo tonto, con el botón de retroceso de super droga
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
Aquí hay una pantalla de bienvenida con la que puedes jugar. Lo estoy usando como un componente de orden superior:
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
Solo voy a mostrar initializeApp () para que tengas algunas ideas:
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
}
}
En otros casos de uso, puede preferir el componente de orden superior. Funcionan exactamente igual que React para la web. Los tutoriales de Stephen Grider sobre Udemy son los mejores, punto.
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)
}
Lo usas así:
import requireAuth from ''../HOC/require_auth''
class RestrictedArea extends Component {
// ... normal view component
}
//map state to props
export default connect(mapStateToProps, actions)(requireAuth(RestrictedArea))
Ahí, eso es todo lo que deseo que alguien me haya contado y mostrado.
TLDR Los archivos
nav_reducer.js
ynav_reducer.js
son absolutamente los más importantes para hacerlo bien. El resto es viejo y familiar. Mis ejemplos deberían acelerarlo en una máquina de productividad salvaje.
[Editar] Aquí está mi creador de acción de cierre de sesión. Le resultará muy útil si desea borrar su pila de navegación para que el usuario no pueda presionar el botón Atrás del hardware de Android y volver a una pantalla que requiere autenticación:
//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,
}
}
[edición de bonificación] ¿Cómo navego desde un Stack Navigator secundario a un Stack Navigator principal?
Si desea navegar desde uno de los navegadores de pila de su hijo y restablecer la pila, haga lo siguiente:
-
Estar dentro de un componente agregando código, donde tenga
this.props.navigation
disponible -
Hacer un componente como
<Something />
-
Pase la navegación hacia él, así:
<Something navigation={this.props.navigation} />
- Ir al código para ese componente
-
Observe cómo tiene
this.props.navigation
disponible dentro de este componente secundario -
Ahora que ha terminado, simplemente llame a
this.props.navigation.navigate(''OtherStackScreen'')
y debería ver React Native mágicamente ir allí sin problema
Pero, quiero RESTABLECER toda la pila mientras navego a una pila principal.
-
Llame a un creador de acciones o algo como esto (comenzando desde el paso 6):
this.props.handleSubmit(data, this.props.navigation)
- Entra en el creador de la acción y observa este código que podría estar allí:
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'' })]
}))
}
}
Estoy usando este código dentro de una aplicación React Native de nivel empresarial, y funciona de maravilla.
react-navigation
es como la programación funcional.
Está diseñado para ser manejado en pequeños fragmentos de "navegación pura" que se componen bien juntos.
Si emplea la estrategia descrita anteriormente, se encontrará creando una lógica de navegación reutilizable que puede pegar según sea necesario.
Estoy tratando de usar react-navigation para crear una pantalla INICIAR SESIÓN inicial que no tiene barra de pestañas ni encabezado, y una vez que el usuario se haya autenticado correctamente, navegará a otra pantalla llamada LISTRECORD que tiene una barra de pestañas, encabezado y ninguna opción de botón de retroceso. ¿Alguien tiene experiencia en esto y puede compartir?
En resumen, lo que estoy tratando de lograr con react-navigation se describe a continuación ...
Pantalla 1: pantalla de inicio de sesión (sin encabezado y barra de pestañas)
Autenticado ...
Pantalla 2: LISTRECORD (encabezado, barra de pestañas y sin botón de retroceso)
La barra de pestañas contiene otras pestañas también para navegar a la Pantalla 3, Pantalla 4 ...
Necesitaba esto, pero ninguna de las otras soluciones funcionó para mí. Así que aquí está mi solución para un inicio de sesión con un cajón (este último accesible solo después de la autenticación adecuada, y cada una de las pantallas dentro tiene su propia pila de navegación). Mi código tiene un DrawerNavigator, pero el mismo podría usarse para 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);
Espero que pueda ayudar a otros.
Ahora hay buena documentación en el sitio de navegación de reacción sobre el flujo de autenticación .
Así es como logré esta funcionalidad.
Archivo 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);
Archivo 1) mi 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 para antes de iniciar sesión
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;
Aunque lo que sugiere Manjeet funcionará, no es una buena estructura de navegación.
Lo que debe hacer es dar un paso atrás y manejar todo en otro nivel.
El navegador de nivel superior debe ser un navegador de pila que muestre una pantalla de inicio de sesión. Otra pantalla dentro de este navegador superior debería ser el navegador principal de su aplicación. Cuando se satisface su estado de inicio de sesión, restablece la pila principal solo al navegador principal.
La razón de esta estructura es:
A- ¿Qué sucede si necesita agregar información de incorporación antes de iniciar sesión en el futuro?
B- ¿Qué sucede si necesita navegar fuera del entorno de navegación principal (por ejemplo: su navegación principal son pestañas y desea una vista sin pestañas)?
Si su navegador superior es un navegador de pila que presenta pantallas de inicio de sesión y otros navegadores, entonces la estructura de navegación de su aplicación puede escalar adecuadamente.
No creo que la representación condicional de una pantalla de inicio de sesión o un navegador de pila, como se sugirió anteriormente, sea una buena idea ... créanme ... He seguido ese camino.
Es bueno que esté utilizando react-navigation que tiene un buen soporte para la mayoría de las funciones que requiere su aplicación. Heres mi consejo
1) En autenticación
React-native tiene esta agradable característica de variables de estado que cuando se cambian las vistas se vuelven a representar. Puede usar variables de estado para comprender el "estado" (autenticado / visitante) de los usuarios de su aplicación.
Aquí hay una implementación simple donde un usuario inicia sesión presionando un botón de inicio de sesión
Página de entrada donde el usuario inicia sesión
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) Iniciar sesión con encabezado
Vista de inicio de sesión
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;
Recuerde eliminar los atributos de estilo en la pantalla de inicio de sesión y agregar los suyos, incluida la importación, los dejo allí, ya que puede ayudarlo a tener una idea de cómo puede organizar su proyecto de reacción
Sin embargo, todavía funciona sin los estilos, por lo que puede quitarlos, al hacer clic en el botón de inicio de sesión lo llevará a la pantalla de Inicio, ya que el estado cambió y la vista debe volver a representarse según el nuevo estado
La pantalla de inicio de sesión no tiene un encabezado como lo requirió
Pantalla de inicio con pestañas
3) Pestañas con encabezado
El método general para lograr esta funcionalidad es agregar un
TabNavigator
en un
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;
Descargo de responsabilidad: el código puede devolver errores, ya que pueden faltar algunos archivos o algunos errores tipográficos, debe verificar los detalles cuidadosamente y cambiar dónde sea necesario si tiene que copiar este código. Cualquier problema puede ser pegado como comentarios. Espero que esto ayude a alguien.
¡También puede eliminar los íconos en las configuraciones de las pestañas o instalar los íconos react-native-vector que hacen que las pestañas sean geniales!
Esta es mi solución basada en la recomendación de @parker :
- Cree un navegador de nivel superior y debe ser un navegador de pila que muestre una pantalla de inicio de sesión.
- Otra pantalla dentro de este navegador de nivel superior debería ser el navegador principal de su aplicación.
- Cuando se satisface su estado de inicio de sesión, restablece la pila principal solo al navegador principal.
Este código hace lo mínimo para lograr lo anterior.
Cree un nuevo proyecto react-native, luego copie el siguiente código en index.ios.js y / o index.android.js para verlo funcionando.
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);
Haga que la barra de pestañas y el encabezado separen los componentes y solo los incluya en otros componentes. Sobre la desactivación de "ATRÁS", hay una sección sobre "bloqueo de acciones de navegación" en los documentos: https://reactnavigation.org/docs/routers/
Debería poder usar eso para la pantalla 2.
Sé que soy viejo aquí, pero este artículo me salvó el trasero, estoy en el infierno con la navegación y ahora me siento más cómodo.
Ese tipo está explicando la API interna que le permitirá construir su navegación exactamente como se imagina , utilizando también un navegador de pila principal.
Se profundiza con un ejemplo de autenticación
Aplauda a este chico :-)
Si no desea un botón de retroceso desde su página LISTA a la página INICIAR SESIÓN, puede hacer esto:
static navigationOptions = {
title: ''YOUR TITLE'',
headerLeft : null,
};
react-navigation
ahora tiene un
SwitchNavigator
que ayuda al comportamiento deseado y al cambio entre navegadores.
Actualmente no hay mucha documentación al respecto, pero hay un muy buen ejemplo de snack creado por la biblioteca que muestra una implementación de flujo de autenticación simple.
Puedes consultarlo
here
.
Referencia de SwitchNavigator
SwitchNavigator(RouteConfigs, SwitchNavigatorConfig)
Ejemplo de documentos
const AppStack = StackNavigator({ Home: HomeScreen, Other: OtherScreen });
const AuthStack = StackNavigator({ SignIn: SignInScreen });
export default SwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
App: AppStack,
Auth: AuthStack,
},
{
initialRouteName: ''AuthLoading'',
}
);