React Navigation5.x第七章 導航的嵌套

嵌套導航的意思就是說你新建了一個導航器,在這個導航器的導航頁中又包含了另一個導航器。比如:

function Home() {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Feed" component={Feed} />
      <Tab.Screen name="Messages" component={Messages} />
    </Tab.Navigator>
  );
}

function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen name="Home" component={Home} />
        <Stack.Screen name="Profile" component={Profile} />
        <Stack.Screen name="Settings" component={Settings} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

在上述的例子中,Home組件包含了一個tab導航器。同時,這個Home組件也是堆棧導航器中的一個導航頁。這樣看來這個tab導航器就是嵌套在了堆棧導航器中。

導航器的嵌套其實跟我們通常使用的組件的嵌套類似,一般情況下,我們通常會嵌套多個導航器

如何嵌套導航器

當我們將導航器嵌套起來的時候,有幾點需要特別注意:

每個導航器保管它自己的導航歷史

比如,當你在一個被嵌套的堆棧導航器上點擊返回按鈕的時候,它會返回到本導航器(就是被嵌套的堆棧導航器)導航歷史中的上一頁,而不是返回到上級導航器中。

導航的action會優先由當前導航器處理如果當前導航器不能處理則通過冒泡的方式由上一級導航器處理

比如,你在一個被嵌套的頁面中調用navigation.goBack(),那麼只有當你在該導航器的首頁的時候你纔會返回到父導航器中。其他的action比如navigate工作原理相同。也就是說,只有當嵌套的導航器不能處理這個action的時候,父導航器纔會視圖去處理它。在上面的例子中,當你在Profile頁面中調用navigate('Settings')的時候,被嵌套的堆棧導航器將會處理它,但是如果你調用navigate('Home'),那麼tab導航器會處理它。

導航器的一些特定方法在子導航器中同樣可用

比如,在drawer導航器中嵌套了一個stack 導航器,那麼drewer導航器的openDrawer、closeDrawer方法在被嵌套的stack導航器的navigation屬性中依然是可用的。但是如果stack導航器沒有嵌套在drawer導航器中,那麼這些方法是不可訪問的。

同樣,如果你在stack導航器中嵌套了一個tab導航器,那麼tab導航器頁面中的navigation屬性會新得到push和replace這兩個方法。

被嵌套的導航器不會響應父級導航器的事件

比如,如果你stack導航器被嵌套在了tab導航器中,那麼stack導航器的頁面不會響應由父tab導航器觸發的事件,比如我們使用navigation.addListener綁定的tabPress事件。爲了能夠響應父級導航器的事件,你可以使用navigation.dangerouslyGetParent().addListener來監聽父級導航器的事件。

父級導航器的UI先於子導航器被渲染

比如,當你在drawer導航器中嵌套了一個stack導航器,你會看到抽屜的效果先被渲染出來,接着纔是渲染stack導航器的頭部,但是如果你將drawer導航器嵌套在了stack導航器中,那麼則會先渲染stack導航器的頭部再渲染抽屜效果。這是一個很關鍵的知識點。

在你的app開發中,你可以根據你的需求來選用下面這些模式:

  • 在drawer導航器的每個頁面嵌套stack導航器----即先渲染抽屜效果再渲染stack導航器的頭部
  • stack導航器的首頁嵌套tab導航器----當你通過push跳轉頁面的時候,新的頁面會覆蓋掉標籤欄。
  • tab導航器的每個頁面都嵌套stack導航器----tab導航器的標籤欄仍然可見。常見的就是點擊tab將stack置頂。

在嵌套的導航器中跳轉頁面

我們來看一下下面這段代碼

function Root() {
  return (
    <Stack.Navigator>
      <Stack.Screen name="Profile" component={Profile} />
      <Stack.Screen name="Settings" component={Settings} />
    </Stack.Navigator>
  );
}

function App() {
  return (
    <NavigationContainer>
      <Drawer.Navigator>
        <Drawer.Screen name="Home" component={Home} />
        <Drawer.Screen name="Root" component={Root} />
      </Drawer.Navigator>
    </NavigationContainer>
  );
}

現在你想從你的Home頁面中跳轉到Root頁面

navigation.navigate('Root');

這是有效的,Root組件的首頁Profile會顯示出來,但是,有時候你可能希望顯示自己指定的頁面。爲了實現這個,你可以在參數中攜帶頁面的名字。

navigation.navigate('Root',{screen:'Settings'});

現在,Setting 頁面就會被顯示出來,當然你也可以用下面的方式傳遞參數:

navigation.navigate('Root', {
  screen: 'Settings',
  params: { user: 'jane' },
});

如果導航器液晶被渲染出來了,跳轉到另一個頁面會push一個新的頁面到stack導航器中。

你也可以使用類似的方法跳轉到深度嵌套的頁面中。需要注意的是第二個參數(也就是你要跳轉的頁面)只是一個參數,就像下面所示:

navigation.navigate('Root', {
  screen: 'Settings',
  params: {
    screen: 'Sound',
    params: {
      screen: 'Media',
    },
  },
});

在上面的例子中,你會跳轉到Media頁面,這個頁面位於Setting頁面所嵌套的導航器的Sound頁面所嵌套的導航器中。

 

這種導航器的嵌套方法看起來與先前版本的似乎有很大不同,先前版本所有的配置是靜態的,所以,React Navigation只能通過遞歸方式靜態的查找所有導航器的列表以及他們的頁面。但是現在有了動態配置,React Navigation並不知道那個頁面是可用的,以及它在哪裏直到導航器包含這個頁面。通常,頁面不會渲染它的內容除非你跳轉到該頁面上,所以尚未渲染的導航器的配置文件是不可用的。所以你必須指定你要跳轉的頁面的層級結構。這也是你爲什麼應該儘量少嵌套導航器,這樣可以使你的代碼更爲簡潔。

嵌套操作的最佳實踐

我們建議儘量少嵌套導航器。因爲嵌套導航器有很多不利的方面

代碼變得更爲繁瑣

其會造成一個很深的嵌套層級結構,這可能會造成內存和性能問題

同種類型的導航器相互嵌套會導致邏輯混亂

推薦用嵌套導航器的方法來實現你的UI佈局 而不是來出來你的代碼邏輯,如果你先給你的公司穿件一系列的頁面,你可以將其歸類爲幾個對象或者數組,而不是用導航器來分類

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章