web-dev-qa-db-ja.com

ログイン画面でのReact-Navigation

反応ナビゲーションを使用して、タブバーとヘッダーのない初期ログイン画面を作成しようとしています。ユーザーが正常に認証されると、タブバー、ヘッダー、戻るボタンオプションのないLISTRECORDという別の画面に移動します。誰でもこれに経験があり、共有できますか?

要約すると、反応ナビゲーションで達成しようとしていることを以下に説明します...

画面1:ログイン画面(ヘッダーとタブバーなし)
認証済み...
画面2:LISTRECORD(ヘッダー、タブバー、および戻るボタンなし)
タブバーには、画面3、画面4に移動するための他のタブも含まれています...

55
Hendry Lim

2017年10月これはとんでもなく紛らわしいと感じたので、トップダウンから始めた私の解決策は次のとおりです。

新しいプロジェクトを開始することをお勧めします。文字通り、これらすべてを貼り付けて、後で勉強することをお勧めします。私はコードを大々的にコメントしたので、特定の領域で立ち往生している場合は、コンテキストが軌道に乗るのに役立つ可能性があります。

この投稿は以下の方法を示しています

  1. 完全にReactをセットアップして、react-navigationを実行します
  2. Reduxと適切に統合する
  3. ハンドルAndroid戻るボタン
  4. ネストスタックナビゲーター
  5. 子から親のナビゲーターに移動する
  6. ナビゲーションスタックをリセットする
  7. 子から親への移動中にナビゲーションスタックをリセットします(ネスト)

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

また、スーパードープバックボタンを使用して、ダムスタイルの1つを紹介します

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

他のユースケースでは、より高次のコンポーネントを好む場合があります。 WebのReactとまったく同じように機能します。 Udemyに関するStephen Griderのチュートリアルは、最高の期間です。

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

そこに、それが誰かが私に言って見せてくれたことを望むすべてです。

TLDRApp.js、およびnav_reducer.jsファイルは、正しく動作するために絶対に最も重要です。残りは古いものです。私の例は、あなたを野productivityな生産性マシンへと加速させるはずです。

[編集]ログアウトアクションの作成者です。ユーザーがAndroid Hardware Back Buttonを押して認証を必要とする画面に戻ることができないようにナビゲーションスタックを消去する場合、非常に便利です。

//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 Navigatorから親Stack Navigatorに移動するにはどうすればよいですか?

子Stack Navigatorの1つから移動してスタックをリセットする場合は、次を実行します。

  1. this.props.navigationを利用できるコードを追加するコンポーネントの内部にいる
  2. <Something />のようなコンポーネントを作成します
  3. 次のようにナビゲーションを渡します:<Something navigation={this.props.navigation} />
  4. そのコンポーネントのコードに移動します
  5. この子コンポーネント内でthis.props.navigationがどのように利用できるかに注意してください
  6. これで、this.props.navigation.navigate('OtherStackScreen')を呼び出すだけで、React Nativeが問題なく魔法のようにそこに行きます。

しかし、私は親スタックにナビゲートしながらスタック全体をリセットします

  1. アクション作成者または次のようなものを呼び出します(手順6から開始):this.props.handleSubmit(data, this.props.navigation)
  2. アクションの作成者に移動し、そこにある可能性があるこのコードを観察します。

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ネイティブアプリ内でこのコードを使用していますが、これは見事に機能します。

react-navigationは関数型プログラミングのようなものです。一緒にうまく構成された小さな「純粋なナビゲーション」フラグメントで処理されるように設計されています。上記の戦略を採用すると、再利用可能なナビゲーションロジックを作成し、必要に応じて貼り付けることができます。

45
agm1984

Manjeetが提案するものは機能しますが、それは良いナビゲーション構造ではありません。

あなたがすべきことは、一歩下がって、すべてを別のレベルで処理することです。

最上位のナビゲーターは、ログイン画面をレンダリングするスタックナビゲーターである必要があります。この最上位のナビゲーター内の別の画面は、アプリのメインナビゲーターです。ログイン状態が満たされたら、メインスタックをメインナビゲーターのみにリセットします。

この構造の理由は次のとおりです。

A-今後ログインする前にオンボーディング情報を追加する必要がある場合はどうなりますか?

B-メインナビゲーション環境の外に移動する必要がある場合(たとえば、メインナビゲーションがタブであり、非タブビューが必要な場合)

最上位のナビゲーターがログイン画面やその他のナビゲーターを表示するStack-Navigatorである場合、アプリのナビゲーション構造は適切にスケーリングできます。

上記のように、ログイン画面またはスタックナビゲーターの条件付きレンダリングは良い考えではないと思います。

30
parker

これが私がこの機能を達成した方法です。

ファイル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)my 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;
12
Manjeet Singh

これは、 @ parkerの推奨事項 に基づく私のソリューションです。

  1. トップレベルのナビゲーターを作成します。これは、ログイン画面を表示するスタックナビゲーターでなければなりません。
  2. このトップレベルナビゲータ内の別の画面は、アプリのメインナビゲータです。
  3. ログイン状態が満たされたら、メインスタックをメインナビゲーターのみにリセットします。

このコードは、上記を達成するために最低限必要なことを行います。

新しい反応ネイティブプロジェクトを作成し、以下のコードを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);
8
zechdc

アプリが必要とするほとんどの機能を適切にサポートする反応ナビゲーションを使用しているのは良いことです。 Heres私のアドバイス

1)認証時

React-nativeにはこの素敵な機能があります状態変数これは、変更されたビューが再レンダリングされるときに使用されます。状態変数を使用して、アプリのユーザーの「状態」(認証済み/訪問者)を理解できます。

これは、ユーザーがログインボタンを押してログインする簡単な実装です

ユーザーがログインするエントリーページ

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)ヘッダー付きログイン

ログインビュー

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;

ログイン画面でスタイル属性を削除し、インポートを含めてスタイル属性を追加することを忘れないでください。プロジェクトのリアクションを調整する方法とアイデアに役立つため、そのままにしておきます

ただし、スタイルなしでも機能するため、スタイルを削除できます。状態が変更され、新しい状態に応じてビューを再レンダリングする必要があるため、ログインボタンをクリックするとホーム画面に移動します

必要に応じてログイン画面にヘッダーがありません

タブ付きのホーム画面

)ヘッダー付きタブこの機能を実現する一般的な方法は、TabNavigatorStackNavigatorを追加することです。

       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;

免責事項:一部のファイルが見つからないか、タイプミスが存在する可能性があるため、コードでエラーが返される場合があります。問題はコメントとして貼り付けることができます。これが誰かを助けることを願っています。

タブ構成のアイコンを削除するか、react-native-vectorアイコンをインストールしてタブを大きくすることもできます!

3
F.E Noel Nfebe

react-navigationSwitchNavigator が追加され、望ましい動作とナビゲーター間の切り替えに役立ちます。現在、それに関するドキュメントはあまりありませんが、簡単な認証フローの実装を示すライブラリによって作成された本当に良い例のスナックがあります。確認できます こちら

SwitchNavigatorリファレンス

SwitchNavigator(RouteConfigs, SwitchNavigatorConfig)

ドキュメントの例

const AppStack = StackNavigator({ Home: HomeScreen, Other: OtherScreen });
const AuthStack = StackNavigator({ SignIn: SignInScreen });

export default SwitchNavigator(
  {
    AuthLoading: AuthLoadingScreen,
    App: AppStack,
    Auth: AuthStack,
  },
  {
    initialRouteName: 'AuthLoading',
  }
);
2
bennygenel

現在、react-navigationサイトに適切なドキュメントがあります 認証フローについて

2
cutemachine

タブバーとヘッダーを別々のコンポーネントにし、それらを他のコンポーネントにのみ含めます。 「BACK」の無効化については、ドキュメントに「ナビゲーションアクションのブロック」に関するセクションがあります。 https://reactnavigation.org/docs/routers/

これを画面2に使用できるはずです。

2
luschn

私はこれが必要でしたが、他の解決策はどれも私にとってはうまくいきませんでした。そこで、ここに引き出し付きのログインのソリューションを示します(後者は、適切な認証後にのみアクセス可能で、内部の各画面には独自のナビゲーションスタックがあります)。私のコードにはDrawerNavigatorがありますが、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);

他の人にも役立つことを願っています。

0
Francois Nadeau

私はここで年を取っていることは知っていますが、この記事は私の命を救いました。ナビゲーションに非常に苦労しており、今ではより快適に感じています。

その男は、メインスタックナビゲーターを使用して、想像どおりにナビゲーションを構築できる内部APIを説明しています。

認証の例で詳しく説明します

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

この男を拍手してください:-)

0
ScreamZ

LISTページからLOGINページに戻るボタンが必要ない場合は、次の操作を実行できます。

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