首页 文章

使用登录屏幕进行反应导航

提问于
浏览
50

我正在尝试使用react-navigation创建一个没有tabbar和header的初始LOGIN屏幕,一旦用户成功通过身份验证,就会导航到另一个名为LISTRECORD的屏幕,该屏幕有一个tabbar,header和no back按钮选项 . 任何人都有这方面的经验,可以分享?

总之,我试图用反应导航实现的目标如下所述......

屏幕1:登录屏幕(无 Headers 和标签栏)
经过身份验证...
屏幕2:LISTRECORD( Headers ,标签栏和无后退按钮)
标签栏还包含其他标签,用于导航到屏幕3,屏幕4 ...

10 回答

  • 1

    使tabbar和header成为单独的组件,并仅将它们包含在其他组件中 . 关于禁用"BACK",文档中有一个关于"blocking navigation actions"的部分:https://reactnavigation.org/docs/routers/

    您应该能够将其用于屏幕2 .

  • 2

    如果您不想从LIST页面到LOGIN页面的后退按钮,您可以这样做:

    static navigationOptions = {
            title: 'YOUR TITLE',
            headerLeft : null,
        };
    
  • 2

    这是我基于@parker recommendation的解决方案:

    • 创建顶级导航器,它应该是呈现登录屏幕的堆栈导航器 .

    • 此顶级导航器中的另一个屏幕应该是您的应用程序的主导航器 .

    • 满足登录状态时,将主堆栈重置为主导航器 .

    这段代码完全可以完成上述任务 .

    创建一个新的react-native项目,然后将下面的代码复制到index.ios.js和/或index.android.js中以查看它是否正常工作 .

    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);
    
  • 45

    我知道我在这里已经老了,但是这篇文章救了我的屁股,我在导航中处于地狱状态,现在我感觉更加舒适 .

    That guy is explaining the internal API that will allows you to build your navigation as exactly as you imagine ,也使用主堆栈导航器 .

    It goes deep with an authentication example

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

    请拍这个家伙:-)

  • 0

    虽然Manjeet认为会起作用,但它并不是一个好的导航结构 .

    你应该做的是退后一步,处理另一个层面的一切 .

    顶级导航器应该是呈现登录屏幕的堆栈导航器 . 这个最顶级导航器中的另一个屏幕应该是您的应用程序的主导航器 . 满足登录状态后,将主堆栈重置为Main-Navigator .

    这种结构的原因是:

    A-如果您需要在登录未来之前添加入职信息,该怎么办?

    B-如果您需要在主导航环境之外导航(例如:您的主导航是标签并且您想要非标签视图),该怎么办?

    如果您的最顶层导航器是一个显示登录屏幕和其他导航器的Stack-Navigator,那么您的应用程序的导航结构可以正确缩放 .

    我不相信如上所述,登录屏幕或堆栈导航器的条件渲染是一个好主意....相信我......我走了那条路 .

  • -2

    这就是我实现这一功能的方式 .

    文件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);
    

    文件1)我的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

    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;
    
  • 28

    2017年10月我发现这个令人难以置信的混乱,所以这是我从上到下的解决方案:我建议开始一个新项目,然后将所有这些粘贴并研究之后 . 我对代码进行了大量评论,所以如果您遇到任何特定领域,也许上下文可以帮助您重回正轨 . 这篇文章展示了如何:完全设置React Native以运行react-navigation正确集成Redux Handle Android后退按钮Nest Stack Navigators从子导航器导航到导航器重置导航堆栈在从子节点导航到父节点时重置导航堆栈(嵌套)

    index.js

    import { AppRegistry } from 'react-native'
    import App from './src/App'
    
    AppRegistry.registerComponent('yourappname', () => App)
    

    src/App.js (这是最重要的文件,因为它将所有碎片整合在一起)

    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

    我会在这里给你看一个例子 . 这不是我的,我只是在这个摇摇晃晃的StackOverflow编辑器中输入它 . 如果你欣赏它,请给我竖起大拇指:)

    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

    我会用超级涂料后退按钮向你展示一种愚蠢的款式

    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

    这是一个你可以玩的闪屏 . 我正在使用它像一个更高阶的组件:

    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

    我将向您展示initializeApp(),以便您获得一些想法:

    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
        }
    }
    

    在其他用例中,您可能更喜欢高阶组件 . 它们的工作方式与React for web完全相同 . 斯蒂芬格里德关于Udemy的教程是最好的时期 .

    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)
    }
    

    你就像这样使用它:

    import requireAuth from '../HOC/require_auth'
    
    class RestrictedArea extends Component {
        // ... normal view component
    }
    
    //map state to props
    
    export default connect(mapStateToProps, actions)(requireAuth(RestrictedArea))
    

    在那里,这就是我希望有人告诉并向我展示的一切 .

    TLDR App.js和nav_reducer.js文件绝对是最重要的 . 其余的都是熟悉的 . 我的例子可以让你加速进入一个野蛮的 生产环境 力机器 .

    [编辑]这是我的退出动作创建者 . 如果您希望擦除导航堆栈以便用户无法按下Android硬件后退按钮并返回需要身份验证的屏幕,您会发现它非常有用:

    //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,
            }
        }
    

    [奖励编辑]如何从子堆栈导航器导航到父堆栈导航器?

    如果要从其中一个子Stack Navigators导航并重置堆栈,请执行以下操作:

    • 在添加代码的组件内部,您可以使用 this.props.navigation

    • 制作像 <Something /> 这样的组件

    • 将导航传递给它,如下所示: <Something navigation={this.props.navigation} />

    • 进入该组件的代码

    • 请注意您在此子组件中如何使用 this.props.navigation

    • 现在你已经完成了,只需拨打 this.props.navigation.navigate('OtherStackScreen') 就可以看到React Native神奇地去那里没有问题

    但是,我希望在导航到父堆栈时重置整个堆栈 .

    • 调用动作创建者或类似的东西(从第6步开始): this.props.handleSubmit(data, this.props.navigation)

    • 进入动作创建者并观察可能存在的代码:

    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' })]
            }))
        }
    }
    

    我在企业级React Native应用程序中使用此代码,它工作得很漂亮 .

    react-navigation 就像函数式编程一样 . 它被设计成以小的"pure navigation"片段处理,这些片段组合在一起 . 如果您采用上述策略,您将发现自己创建可重复使用的导航逻辑,您可以根据需要粘贴它 .

  • 12

    现在反应导航网站about the authentication flow上有很好的文档 .

  • 3

    react-navigation 现在有一个SwitchNavigator,它有助于在导航器之间进行所需的行为和切换 . 目前没有太多关于它的文档,但是库创建了一个非常好的示例小吃,它显示了一个简单的认证流程实现 . 你可以查一下here .

    SwitchNavigator参考SwitchNavigator(RouteConfigs,SwitchNavigatorConfig)

    来自docs的示例

    const AppStack = StackNavigator({ Home: HomeScreen, Other: OtherScreen });
    const AuthStack = StackNavigator({ SignIn: SignInScreen });
    
    export default SwitchNavigator(
      {
        AuthLoading: AuthLoadingScreen,
        App: AppStack,
        Auth: AuthStack,
      },
      {
        initialRouteName: 'AuthLoading',
      }
    );
    
  • 7

    很好的是,您正在使用react-navigation,它可以很好地支持您的应用程序所需的大多数功能 . 继承人我的建议

    1) On Authentication

    React-native具有这个很好的功能状态变量,当重新呈现更改的视图时 . 您可以使用状态变量来了解应用用户的"state"(经过身份验证/访问者) .

    这是一个简单的实现,用户通过按登录按钮登录

    用户登录的输入页面

    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) Login with header

    登录视图

    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;
    

    请记住在登录界面中删除样式属性并添加包括导入在内的样式属性,我将它们留在那里,因为它可以帮助您了解如何安排您的反应项目

    但是它仍然可以在没有样式的情况下工作,因此您可以将它们关闭,单击登录按钮将转到主屏幕,因为状态已更改且视图必须根据新状态重新呈现

    The login screen is without a header as you required

    主屏幕带标签

    3) Tabs with header 实现此功能的一般方法是在 StackNavigator 中添加 TabNavigator .

    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;
    

    Disclaimer : 代码可能会返回错误,因为某些文件可能丢失或者可能存在某些拼写错误,您应仔细检查详细信息,并在需要复制此代码时更改必要的位置 . 任何问题都可以粘贴为评论 . 希望这有助于某人 .

    您也可以删除选项卡配置中的图标或安装react-native-vector图标,这样可以使选项卡变得更好!

相关问题