ReactNative ? react-navigation 3.x

React Native 中文網(wǎng)
React Navigation 官網(wǎng)

簡(jiǎn)介

一、安裝步驟
1精续、打開(kāi)終端坝锰,cd到工程所在文件夾

2、yarn add react-navigation

3重付、yarn add react-native-gesture-handler

4顷级、react-native link react-native-gesture-handler
二、關(guān)于React Native工程的一些知識(shí)點(diǎn)

1确垫、在ReactNative中弓颈,所有的類(lèi)都視為組件。

2删掀、我們?cè)诔跏蓟疪eact Native新項(xiàng)目的時(shí)候翔冀,會(huì)有一個(gè)App.js文件。我們運(yùn)行Xcode顯示在屏幕上的根視圖就是在這個(gè)文件中通過(guò)export default導(dǎo)出的那個(gè)組件披泪。

3纤子、在3.x的版本中,需要通過(guò)createAppContainer方法將設(shè)置好路由的導(dǎo)航器包裝為組件。
否則報(bào)錯(cuò)如下:

不使用createAppContainer方法報(bào)錯(cuò)

4控硼、組件的導(dǎo)入,在es6+中跌捆,通過(guò)import導(dǎo)入其他自定義組件

三、官網(wǎng)Demo分析

// In App.js in a new project

import React from "react";
import { View, Text } from "react-native";
import { createStackNavigator, createAppContainer } from "react-navigation";

class HomeScreen extends React.Component {
  render() {
    return (
      <View style={{ flex: 1, alignItems: "center", justifyContent: "center"   }}>
        <Text>Home Screen</Text>
      </View>
    );
  }
}

const AppNavigator = createStackNavigator({
  Home: {
    screen: HomeScreen
  }
});

export default createAppContainer(AppNavigator);

結(jié)合上面的知識(shí)點(diǎn)象颖,分析如下

  • 在App.js文件中
  • 導(dǎo)入react-navigation
  • 定義HomeScreen組件
  • 定義導(dǎo)航器組件,設(shè)置路由
  • 將導(dǎo)航器組件包裝后導(dǎo)出姆钉,此時(shí)導(dǎo)航控制器就是應(yīng)用的根視圖控制器

運(yùn)行結(jié)果:


導(dǎo)航控制器

四说订、注意點(diǎn)

1、在導(dǎo)入navigation組件后通常需要重啟終端潮瓶,否則報(bào)錯(cuò)陶冷。

2、我們?cè)谑褂?code>WebStorm打開(kāi)初始化工程項(xiàng)目時(shí)毯辅,都會(huì)默認(rèn)導(dǎo)出名為App的組件

export default class App extends Component<Props> {
  render() {
    return (
      <View></View>
    );
  }
}

與直接導(dǎo)出 stack navigator 相比埂伦,對(duì)應(yīng)用程序根部的組件進(jìn)行更多的控制通常更有用,所以我們導(dǎo)出一個(gè)只渲染了 stack navigator 的組件思恐。

const AppNavigator = createStackNavigator({
      Home: {
        screen: HomeScreen
      }
    });

const AppContainer = createAppContainer(AppNavigator);

export default class App extends React.Component {
   render() {
     return <AppContainer />;
   }
 }

這里需要注意沾谜,我們不可以像書(shū)寫(xiě)StyleSheet那樣把

const AppNavigator = createStackNavigator({
      Home: {
        screen: HomeScreen
      }
    });

寫(xiě)到App組件的下方,這樣做報(bào)錯(cuò)如下:


將導(dǎo)航器寫(xiě)在下方報(bào)錯(cuò)

3胀莹、頁(yè)面組件就是創(chuàng)建StackNavigator配置路由的組件基跑。只有頁(yè)面組件才會(huì)擁有導(dǎo)航的一些屬性。

頁(yè)面切換

一描焰、跳轉(zhuǎn)新的頁(yè)面
<Button
     title="Go to Details"
     onPress={() => this.props.navigation.navigate('Details')}
 />

如果我們使用未在 stack navigator 中定義的路由名稱調(diào)用this.props.navigation.navigate 方法媳否,則不會(huì)發(fā)生任何事情。 換句話說(shuō)荆秦,我們只能導(dǎo)航到已經(jīng)在我們的 stack navigator 上定義的路由; 不能隨便導(dǎo)航到任意組件篱竭。

二、多次導(dǎo)航到同一路由
class DetailsScreen extends React.Component {
  render() {
    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Details Screen</Text>
        <Button
          title="Go to Details... again"
          onPress={() => this.props.navigation.navigate('Details')}
        />
      </View>
    );
  }
}

如果我們使用this.props.navigation.navigate導(dǎo)航到同一路由是不起作用的步绸。
我們需要使用this.props.navigation.push來(lái)實(shí)現(xiàn)

每次調(diào)用 push 時(shí), 我們會(huì)向?qū)Ш蕉褩V刑砑有侣酚伞?/p>

三掺逼、總結(jié)

1、我們可以使用this.props.navigation.navigate('RouteName')跳轉(zhuǎn)到在stack navigator中已經(jīng)定義的路由名稱對(duì)應(yīng)的新頁(yè)面靡努,但要注意新路由和當(dāng)前路由不相等坪圾。
2、我們可以使用this.props.navigation.navigate('RouteName')返回堆棧中的現(xiàn)有頁(yè)面惑朦,如果有多個(gè)相同頁(yè)面兽泄,則返回到最底層的頁(yè)面

生命周期

React Navigation中漾月,react的生命周期仍然適用病梢。

只要頁(yè)面處于加載的狀態(tài),react生命周期中的componentDidMountcomponentWillUnmount方法就不會(huì)被調(diào)用,這類(lèi)似于iOS開(kāi)發(fā)中的ViewDidLoad方法和dealloc方法蜓陌,在生命周期中觅彰,只會(huì)調(diào)用一次。那么類(lèi)比OC钮热,我們?nèi)绾伪O(jiān)聽(tīng)ViewWillAppear填抬、ViewDidAppearViewWillDisappearViewDidDisappear的方法呢隧期?

主要有下面兩種方式
1飒责、訂閱React Navigation事件
2、使用 withNavigationFocus HOC或者 <NavigationEvents />組件仆潮。

<NavigationEvents />組件為例:

假定這樣一個(gè)場(chǎng)景:導(dǎo)航控制器的根視圖控制器是HomeScreen宏蛉,點(diǎn)擊HomeScreen上面的按鈕跳轉(zhuǎn)到下一個(gè)控制器。那么我們要監(jiān)聽(tīng)HomeScreen的四個(gè)事件性置。
代碼如下:

class HomeScreen extends  Component{

    render() {
    return (
        <View style={styles.container}>
            <NavigationEvents
                onWillFocus={payload => console.log('will focus',payload)}
                onDidFocus={payload => console.log('did focus',payload)}
                onWillBlur={payload => console.log('will blur',payload)}
                onDidBlur={payload => console.log('did blur',payload)}
            />
            <Text>Home頁(yè)面</Text>
            <Button
                title={"Go to Login"}
                onPress={()=> {
                  this.props.navigation.navigate('Details');
                }}
            />
        </View>
    )
  }
}

打印如下:


監(jiān)聽(tīng)React Navigation事件

傳遞參數(shù)給路由

一拾并、參數(shù)傳遞

1、使用this.props.navigation.navigate('RouteName', { /* params go here */ })
方法的第二個(gè)參數(shù)傳遞給路由

2鹏浅、推薦傳遞的參數(shù)是 JSON序列化的

 this.props.navigation.navigate('Details', {
              itemId: 86,
              otherParam: 'anything you want here',
            });
二嗅义、獲取參數(shù)

1、直接使用this.props.navigation.state.params進(jìn)行訪問(wèn)篡石,如果沒(méi)有對(duì)應(yīng)參數(shù)芥喇,則可能是null。
2凰萨、使用his.props.navigation.getParam進(jìn)行訪問(wèn)

const { navigation } = this.props;
//第二個(gè)參數(shù)是設(shè)置默認(rèn)值
const itemId = navigation.getParam('itemId', 'NO-ID');

3继控、如果你想通過(guò) prop 直接訪問(wèn) params(例如: this.props.itemId)而不是this.props.navigation.getParam,您可以使用社區(qū)開(kāi)發(fā)的 react-navigation-props-mapper軟件包胖眷。

4武通、官方Demo

class HomeScreen extends React.Component {
  render() {
    return (
       <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Home Screen</Text>
        <Button
          title="Go to Details"
           => {
            /* 1. Navigate to the Details route with params */
            this.props.navigation.navigate('Details', {
              itemId: 86,
              otherParam: 'anything you want here',
           });
          }}
        />
      </View>
    );
  }
}

class DetailsScreen extends React.Component {
  render() {
    /* 2. Get the param, provide a fallback value if not available */
    const { navigation } = this.props;
    const itemId = navigation.getParam('itemId', 'NO-ID');
    const otherParam = navigation.getParam('otherParam', 'some default     value');

    return (
      <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
        <Text>Details Screen</Text>
        <Text>itemId: {JSON.stringify(itemId)}</Text>
        <Text>otherParam: {JSON.stringify(otherParam)}</Text>
        <Button
          title="Go to Details... again"
          onPress={() =>
            this.props.navigation.push('Details', {
              itemId: Math.floor(Math.random() * 100),
            })}
        />
        <Button
          title="Go to Home"
          onPress={() => this.props.navigation.navigate('Home')}
        />
        <Button
          title="Go back"
          onPress={() => this.props.navigation.goBack()}
        />
      </View>
    );
  }
}

配置標(biāo)題欄

一、設(shè)置不含參數(shù)的標(biāo)題欄

1珊搀、每個(gè)頁(yè)面組件可以有一個(gè)名為navigationOptions的靜態(tài)屬性冶忱,用于設(shè)置標(biāo)題欄的標(biāo)題使用的是title屬性

class HomeScreen extends React.Component {
 static navigationOptions = {
    title: 'Home',
  };

  /* render function, etc */
}
二、設(shè)置含參數(shù)的標(biāo)題欄

我們將navigationOptions作為一個(gè)函數(shù)境析,react會(huì)使用包含{ navigation, navigationOptions, screenProps }這些屬性的對(duì)象調(diào)用它囚枪,由于傳值只用到navigation,所以代碼如下:

class DetailsScreen extends React.Component {
  static navigationOptions = ({ navigation }) => {
    return {
      title: navigation.getParam('otherParam', 'A Nested Details Screen'),
    };
  };

 /* render function, etc */
}

對(duì)上面提到的三個(gè)屬性劳淆,解釋如下:

  • navigation - 頁(yè)面的 導(dǎo)航屬性 链沼,在頁(yè)面中的路由為navigation.state
  • screenProps - 從導(dǎo)航器組件上層傳遞的 props
  • navigationOptions - 如果未提供新值沛鸵,將使用的默認(rèn)或上一個(gè)選項(xiàng)(這里說(shuō)的默認(rèn)值就是指共享的navigationOptions)
三括勺、更新含參數(shù)的標(biāo)題欄

通常有必要從已加載的頁(yè)面組件本身更新當(dāng)前頁(yè)面的navigationOptions配置缆八。 我們可以使用this.props.navigation.setParams

  /* Inside of render() */
  <Button
    title="Update the title"
    onPress={() => this.props.navigation.setParams({otherParam: 'Updated!'})}
  />
四、調(diào)整標(biāo)題樣式

定制標(biāo)題樣式時(shí)有三個(gè)關(guān)鍵屬性:headerStyle疾捍、headerTintColor和headerTitleStyle奈辰。

  • headerStyle:一個(gè)應(yīng)用于 header 的最外層 View 的 樣式對(duì)象, 如果你設(shè)置 backgroundColor 乱豆,他就是header 的顏色奖恰。

  • headerTintColor:返回按鈕和標(biāo)題都使用這個(gè)屬性作為它們的顏色。 在下面的例子中宛裕,我們將 tint color 設(shè)置為白色(#fff)房官,所以返回按鈕和標(biāo)題欄標(biāo)題將變?yōu)榘咨?/p>

  • headerTitleStyle:如果我們想為標(biāo)題定制fontFamily,fontWeight和其他Text樣式屬性续滋,我們可以用它來(lái)完成。

class HomeScreen extends React.Component {
  static navigationOptions = {
    title: 'Home',
    headerStyle: {
      backgroundColor: '#f4511e',
    },
    headerTintColor: '#fff',
    headerTitleStyle: {
      fontWeight: 'bold',
    },
  };

 /* render function, etc */
}
五孵奶、跨頁(yè)面共享通用的navigationOptions

如果我們要統(tǒng)一配置標(biāo)題欄的樣式疲酌,我們只需把這些代碼移動(dòng)到創(chuàng)建導(dǎo)航器的代碼中,放在defaultNavigationOptions屬性下

class HomeScreen extends React.Component {
  static navigationOptions = {
    title: 'Home',
    /* No more header config here! */
  };

  /* render function, etc */
}

    /* other code... */

const RootStack = createStackNavigator(
  {
    Home: HomeScreen,
    Details: DetailsScreen,
  },
  {
    initialRouteName: 'Home',
    /* The header config from HomeScreen is now here */
    defaultNavigationOptions: {
      headerStyle: {
        backgroundColor: '#f4511e',
      },
      headerTintColor: '#fff',
      headerTitleStyle: {
        fontWeight: 'bold',
      },
    },
  }
);
六了袁、覆蓋共享的navigationOptions

如果在頁(yè)面組件上面也指定了navigationOptions朗恳,那么將會(huì)覆蓋父級(jí)的navigationOptions。

七载绿、使用自定義組件替換標(biāo)題
class LogoTitle extends React.Component {
  render() {
    return (
      <Image
        source={require('./spiro.png')}
        style={{ width: 30, height: 30 }}
      />
    );
  }
}

class HomeScreen extends React.Component {
  static navigationOptions = {
    // headerTitle instead of title
    headerTitle: <LogoTitle />,
   };

  /* render function, etc */
}

標(biāo)題欄按鈕

1粥诫、向標(biāo)題欄中添加一個(gè)按鈕
class HomeScreen extends React.Component {
  static navigationOptions = {
    headerTitle: <LogoTitle />,
    headerRight: (
      <Button
       onPress={() => alert('This is a button!')}
        title="Info"
        color="#fff"
      />
    ),
  };
}

在navigationOptions中this綁定的不是 HomeScreen 實(shí)例,所以你不能調(diào)用setState方法和其上的任何實(shí)例方法崭庸。

2怀浆、標(biāo)題欄和其所屬的頁(yè)面之間的交互

由于上面提到的,在navigationOptions中不能使用this怕享,所以使用getParamsetParam實(shí)現(xiàn)

class HomeScreen extends React.Component {
  static navigationOptions = ({ navigation }) => {
    return {
      headerTitle: <LogoTitle />,
      headerRight: (
        <Button
          onPress={navigation.getParam('increaseCount')}
          title="+1"
          color="#fff"
        />
      ),
    };
  };

  componentDidMount() {
    this.props.navigation.setParams({ increaseCount: this._increaseCount });
  }

  state = {
    count: 0,
  };

  _increaseCount = () => {
    this.setState({ count: this.state.count + 1 });
  };

  /* later in the render function we display the count */
}

下面分析一下這段代碼:
1执赡、首先按鈕的點(diǎn)擊事件我們應(yīng)該傳遞一個(gè)函數(shù) 或者null
所以在componentDidMount方法中將參數(shù)賦值為一個(gè)函數(shù)
此時(shí)再次點(diǎn)擊按鈕的時(shí)候就會(huì)調(diào)用這個(gè)函數(shù)了函筋。

2沙合、React Navigation不保證屏幕組件在標(biāo)題之前安裝,此時(shí)按鈕點(diǎn)擊事件相當(dāng)于null跌帐,不會(huì)造成異常首懈。

Tab Navigation

在iOS開(kāi)發(fā)中,最常見(jiàn)的UI框架是Tab中包含若干Navigation谨敛。相應(yīng)的路由配置如下:

import Main from './Component/Main.js';
import Home from './Component/Home.js';
import Find from './Component/Find.js';
import Message from './Component/Message.js';
import Mine from './Component/Mine.js';

//創(chuàng)建navigation
const MainStack = createStackNavigator({
    main:{
        screen:Main,
    }
})

const HomeStack = createStackNavigator({
    home:{
        screen:Home,
    },
})

const FindStack = createStackNavigator({
    find:{
        screen:Find,
    }
})

const MessageStack = createStackNavigator({
    home:{
        screen:Message,
    }
})

const MineStack = createStackNavigator({
    home:{
        screen:Mine,
    }
})

//配置Tab的路由
const TabNav = createBottomTabNavigator({
    mainStack:{
        screen:MainStack,
    },
    homeStack:{
        screen:HomeStack,
    },
    findStack:{
        screen:FindStack,
    },
    messageStack:{
        screen:MessageStack,
    },
    mineStack:{
        screen:MineStack,
    }
})

const AppContainer = createAppContainer(TabNav);

在實(shí)際開(kāi)發(fā)中究履,我們需要自定義Tab上面的樣式,類(lèi)似于createStackNavigator佣盒,我們可以用相同的方法配置navigationOptions挎袜。

在我們配置樣式時(shí),存在一個(gè)注意點(diǎn)。當(dāng)我們同時(shí)使用了createStackNavigatorcreateBottomTabNavigator時(shí)盯仪,在配置樣式時(shí):如果我們想設(shè)置Navigation的樣式紊搪,我們可以在createStackNavigator或者Navigator的頁(yè)面元素中(就是以導(dǎo)航控制器為容器的那些子控制器)設(shè)置。如果我們想配置Tab的樣式全景,我們可以在createBottomTabNavigator或者navigator(就是以Tab為容器的那些導(dǎo)航控制器)實(shí)例中設(shè)置耀石。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市爸黄,隨后出現(xiàn)的幾起案子滞伟,更是在濱河造成了極大的恐慌,老刑警劉巖炕贵,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件梆奈,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡称开,警方通過(guò)查閱死者的電腦和手機(jī)亩钟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)鳖轰,“玉大人清酥,你說(shuō)我怎么就攤上這事≡搪拢” “怎么了焰轻?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)昆雀。 經(jīng)常有香客問(wèn)我辱志,道長(zhǎng),這世上最難降的妖魔是什么狞膘? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任荸频,我火速辦了婚禮,結(jié)果婚禮上客冈,老公的妹妹穿的比我還像新娘旭从。我一直安慰自己,他們只是感情好场仲,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布和悦。 她就那樣靜靜地躺著,像睡著了一般渠缕。 火紅的嫁衣襯著肌膚如雪鸽素。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,046評(píng)論 1 285
  • 那天亦鳞,我揣著相機(jī)與錄音馍忽,去河邊找鬼棒坏。 笑死,一個(gè)胖子當(dāng)著我的面吹牛遭笋,可吹牛的內(nèi)容都是我干的坝冕。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼瓦呼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼喂窟!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起央串,我...
    開(kāi)封第一講書(shū)人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤磨澡,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后质和,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體稳摄,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年饲宿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了秩命。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡褒傅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出袄友,到底是詐尸還是另有隱情殿托,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布剧蚣,位于F島的核電站支竹,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏鸠按。R本人自食惡果不足惜礼搁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望目尖。 院中可真熱鬧馒吴,春花似錦、人聲如沸瑟曲。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)洞拨。三九已至扯罐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間烦衣,已是汗流浹背歹河。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工掩浙, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人秸歧。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓厨姚,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親寥茫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子遣蚀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容