導覽屬性參考
App 中的每個 screen
元件都會自動提供 navigation
屬性。此屬性包含各種方便的函式,用來發送導覽動作。它會以下列方式顯示
navigation
navigate
- 前往指定的畫面,此行為會依導航器而有所不同goBack
- 回到上一個畫面,此行為會在堆疊中使用時關閉當前畫面reset
- 使用指定的狀態取代導航器的導覽狀態setParams
- 將新參數併入路線的參數dispatch
- 傳送動作物件,以更新導覽狀態setOptions
- 更新畫面的選項isFocused
- 檢查畫面是否已開啟canGoBack
- 檢查是否可以從當前的畫面返回getState
- 取得導航器的導覽狀態getParent
- 取得父畫面(若有)的導覽物件addListener
- 訂閱畫面的事件removeListener
- 取消訂閱畫面的事件
重點是,將 navigation
屬性傳遞給 所有 元件並非必須;只有 screen
元件會自動接收這個屬性!React Navigation 在這裡不會施展任何魔法。例如,假設您要定義 MyBackButton
元件並將它呈現為畫面元件的子項,您將無法在上面存取 navigation
屬性。但是,如果您想在任何元件中存取 navigation
屬性,可以使用 useNavigation
勾子。
setParams
/setOptions
等只能在useEffect
/useLayoutEffect
/componentDidMount
/componentDidUpdate
等中呼叫。不能在 render 時或在建構函數中呼叫。
導覽器相關函式
navigation
屬性上有幾個額外的函式,依據目前的導覽器種類而定。
如果導覽器是堆疊導覽器,navigate
和 goBack
提供了幾個替代方案,您可以使用任何您偏好的方案。函式如下:
navigation
replace
- 以新的畫面取代目前的畫面push
- 將新的畫面推送到堆疊pop
- 回到堆疊popToTop
- 前往堆疊最上方
請參閱 堆疊導覽器說明 和 原生的堆疊導覽器說明,以取得這些方法的詳細資訊。
如果導覽器是索引標籤導覽器,則下列內容也可用:
navigation
jumpTo
- 前往索引標籤導覽器中的特定畫面
請參閱 底部索引標籤導覽器說明、Material Top Tab 導覽器說明 和 Material Bottom Tab 導覽器說明,以取得這些方法的詳細資訊。
如果導覽器是抽屜導覽器,則下列內容也可用:
navigation
jumpTo
- 前往抽屜導覽器中的特定畫面openDrawer
- 開啟抽屜closeDrawer
- 關閉抽屜toggleDrawer
- 切換狀態,例如從關閉變開啟,反之亦然
請參閱 抽屜導覽器說明,以取得這些方法的詳細資訊。
常見的 API 參考
您與 navigation
屬性互動的大部分時間將會涉及 navigate
、goBack
和 setParams
。
navigate
navigate
方法讓我們可以導覽至 App 中的其他畫面。傳入下列參數:
navigation.navigate(name, params)
name
- 已定義在某處的目的地畫面名稱params
- 傳遞給目標路由的參數。
function HomeScreen({ navigation: { navigate } }) {
return (
<View>
<Text>This is the home screen of the app</Text>
<Button
onPress={() =>
navigate('Profile', { names: ['Brent', 'Satya', 'Michaś'] })
}
title="Go to Brent's profile"
/>
</View>
);
}
在 原生堆疊導航器 中,使用螢幕名稱呼叫 navigate
將會產生不同的行為,具體取決於螢幕是否已經存在。如果螢幕已存在於堆疊的歷程中,它將返回到該螢幕並移除其後的任何螢幕。如果螢幕不存在,則它將推送一個新的螢幕。
例如,如果你有一個歷程堆疊 Home > Profile > Settings
,然後你呼叫 navigate(Profile)
,則最終的螢幕將會是 Home > Profile
,因為它會返回到 Profile
並移除 Settings
螢幕。
預設情況下,螢幕會透過其名稱進行識別。不過你也可以透過使用 getId
prop 來自訂,使其考慮參數。
例如,假設你為 Profile
螢幕指定了一個 getId
prop
<Tab.Screen
name={Profile}
component={ProfileScreen}
getId={({ params }) => params.userId}
/>
現在,如果你有一個歷程堆疊 Home > Profile (userId: bob) > Settings
,然後你呼叫 navigate(Profile, { userId: 'alice' })
,則最終的螢幕將會是 Home > Profile (userId: bob) > Settings > Profile (userId: alice)
,因為它將會新增一個新的 Profile
螢幕,原因是找不到相符的螢幕。
goBack
goBack
方法讓我們返回導航器中的前一螢幕。
預設情況下,goBack
將從其所呼叫的螢幕返回
function ProfileScreen({ navigation: { goBack } }) {
return (
<View>
<Button onPress={() => goBack()} title="Go back from ProfileScreen" />
</View>
);
}
從特定螢幕返回
考慮以下的導航堆疊歷程
navigation.navigate({ name: SCREEN, key: SCREEN_KEY_A });
navigation.navigate({ name: SCREEN, key: SCREEN_KEY_B });
navigation.navigate({ name: SCREEN, key: SCREEN_KEY_C });
navigation.navigate({ name: SCREEN, key: SCREEN_KEY_D });
現在你在螢幕 D 上,並且想要返回螢幕 A(彈出 D、C 和 B)。然後你可以使用 navigate
navigation.navigate({ key: SCREEN_KEY_A }); // will go to screen A FROM screen D
或者,由於螢幕 A 位於堆疊的最上面,因此你可以使用 navigation.popToTop()
。
reset
reset
方法讓我們替換導航狀態為一個新的狀態
navigation.reset({
index: 0,
routes: [{ name: 'Profile' }],
});
在 reset
中指定的狀態物件會以新的物件取代現有的 導航狀態,也就是說它會移除現有的螢幕並新增新的螢幕。如果你在變更狀態時想要保留現有的螢幕,則可以改用透過 CommonActions.reset
和 dispatch
進行。
將 navigator 的狀態物件視為內部物件,且在較小版本中可能有所變更。避免使用 navigation state 狀態物件中的屬性,但對於 index
和 routes
例外,除非你真的需要它。如果你在不依賴狀態物件結構的情況下,無法執行某些功能,請開啟問題。
setParams
setParams
方法讓我們更新目前畫面的參數(route.params
)。setParams
的運作方式就像 React 的 setState
- 會將所提供的參數物件與目前參數進行淺層合併。
function ProfileScreen({ navigation: { setParams } }) {
return (
<Button
onPress={() =>
setParams({
friends:
route.params.friends[0] === 'Brent'
? ['Wojciech', 'Szymon', 'Jakub']
: ['Brent', 'Satya', 'Michaś'],
title:
route.params.title === "Brent's Profile"
? "Lucy's Profile"
: "Brent's Profile",
})
}
title="Swap title and friends"
/>
);
}
setOptions
setOptions
方法讓我們從元件內設定畫面選項。如果我們需要使用元件的 props、狀態或內容來設定畫面,這項功能會很有用。
function ProfileScreen({ navigation, route }) {
const [value, onChangeText] = React.useState(route.params.title);
React.useEffect(() => {
navigation.setOptions({
title: value === '' ? 'No title' : value,
});
}, [navigation, value]);
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<TextInput
style={{ height: 40, borderColor: 'gray', borderWidth: 1 }}
onChangeText={onChangeText}
value={value}
/>
<Button title="Go back" onPress={() => navigation.goBack()} />
</View>
);
}
於此處指定的任何選項均會與定義畫面時指定的選項進行淺層合併。
在使用 navigation.setOptions
時,我們建議在畫面的 options
道具中指定一個佔位符,並使用 navigation.setOptions
更新它。如此一來,可確保更新選項的延遲對使用者而言不會很明顯。這也讓它能用於延遲載入畫面。
你也可以使用 React.useLayoutEffect
來減少更新選項時的延遲。不過,如果你支援網頁並使用伺服器端渲染,我們不建議這樣做。
navigation.setOptions
的目的是提供一種方式,讓你在必要時更新既有選項。它並非畫面中 options
道具的替代方案。請確定僅在絕對必要的時後,才慎重地使用 navigation.setOptions
。
導覽事件
畫面可以使用 addListener
方法在 navigation
道具上新增監聽器。例如,要監聽 focus
事件
function Profile({ navigation }) {
React.useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
// do something
});
return unsubscribe;
}, [navigation]);
return <ProfileContent />;
}
參閱 導覽事件,以瞭解有關可用事件和 API 使用方式的更多詳細資訊。
isFocused
此方法讓我們檢查畫面目前是否處於焦點中。如果畫面處於焦點中,則傳回 true
,否則傳回 false
。
const isFocused = navigation.isFocused();
當值變更時此方法不會重新渲染畫面,主要用於回呼。你可能想要使用 useIsFocused 而不是直接使用此方法,它會回傳一個布林值 prop 來指示畫面是否已聚焦。
進階 API 參考
dispatch
函式較少用到,但當你無法利用現有方法(如 navigate
、goBack
等)時,它是一個很好的逃生艙口。我們建議避免經常使用 dispatch
方法,除非絕對必要。
dispatch
dispatch
方法讓我們可以傳送一個導覽動作物件,它決定如何更新 導覽狀態。所有導覽函式(如 navigate
)都會在背後使用 dispatch
。
請注意,如果你要調度動作,你應該使用此程式庫提供的動作產生器,而不是直接撰寫動作物件。
請查看 導覽動作文件 以取得可用動作的完整清單。
import { CommonActions } from '@react-navigation/native';
navigation.dispatch(
CommonActions.navigate({
name: 'Profile',
params: {},
})
);
在調度動作物件時,你還可以指定幾個額外屬性
source
- 路線的鍵應該視為動作的來源。例如,replace
動作會用提供的鍵取代路線。預設情況下,它會使用調度動作的路線鍵。你可以明確傳遞undefined
來覆寫此行為。target
- 動作應套用的 導覽狀態 的鍵。預設情況下,如果導航器未處理動作,動作會冒泡到其他導航器。如果指定target
,如果具有相同鍵的導航器未處理動作,動作不會冒泡。
範例
import { CommonActions } from '@react-navigation/native';
navigation.dispatch({
...CommonActions.navigate('Profile'),
source: 'someRoutekey',
target: 'someStatekey',
});
自訂動作產生器
也可以將動作產生器函式傳遞給 dispatch
。該函式會收到目前狀態,並需要回傳要使用的導覽動作物件
import { CommonActions } from '@react-navigation/native';
navigation.dispatch((state) => {
// Add the home route to the start of the stack
const routes = [{ name: 'Home' }, ...state.routes];
return CommonActions.reset({
...state,
routes,
index: routes.length - 1,
});
});
你可以使用此功能來建立自己的協助程式,並在你的應用程式中使用。以下是一個範例,用於在最後一個畫面之前插入一個畫面
import { CommonActions } from '@react-navigation/native';
const insertBeforeLast = (routeName, params) => (state) => {
const routes = [
...state.routes.slice(0, -1),
{ name: routeName, params },
state.routes[state.routes.length - 1],
];
return CommonActions.reset({
...state,
routes,
index: routes.length - 1,
});
};
然後像這樣使用
navigation.dispatch(insertBeforeLast('Home'));
canGoBack
此方法會回傳一個布林值,表示目前導航器或任何父導航器中是否有任何導覽歷程記錄可用。你可以使用此方法來檢查是否可以呼叫 navigation.goBack()
if (navigation.canGoBack()) {
navigation.goBack();
}
不建議使用此方法來呈現內容,因為這不會觸發重新呈現。這只能在呼叫、事件監聽器等內部使用。
getParent
此方法會傳回嵌套目前瀏覽器之父瀏覽器裡面的瀏覽器 prop。例如,如果你有一個堆疊瀏覽器和一個分頁瀏覽器,嵌套在堆疊瀏覽器內,那麼你可以使用分頁瀏覽器中的畫面中的 getParent
來取得從堆疊瀏覽器傳遞過來的瀏覽器 prop。
它接受一個 ID 選擇性參數,用來參考特定父瀏覽器。例如,你的畫面嵌套在多層之下,在某處 Drawer 瀏覽器的 id
prop 為 "LeftDrawer"
,你可以直接參考它而不用多次呼叫 getParent
要對瀏覽器使用 ID,首先傳遞一個獨特的 id
prop
<Drawer.Navigator id="LeftDrawer">{/* .. */}</Drawer.Navigator>
然後在使用 getParent
時,修改為
// Avoid this
const drawerNavigation = navigation.getParent().getParent();
// ...
drawerNavigation?.openDrawer();
你能這樣做
// Do this
const drawerNavigation = navigation.getParent('LeftDrawer');
// ...
drawerNavigation?.openDrawer();
這樣的作法可以讓元件不需要了解瀏覽器的巢狀結構。因此,非常建議在使用 getParent
時使用一個 id
。
如果沒有相符的父瀏覽器,這個方法會傳回 undefined
。使用這個方法時請務必隨時檢查是否有 undefined
。
getState
將 navigator 的狀態物件視為內部物件,且在較小版本中可能有所變更。避免使用 navigation state 狀態物件中的屬性,但對於 index
和 routes
例外,除非你真的需要它。如果你在不依賴狀態物件結構的情況下,無法執行某些功能,請開啟問題。
此方法傳回包含畫面的瀏覽器狀態物件。取得瀏覽器狀態在非常少見的情況下可能會有用。你很有可能不需要使用此方法。如果你真的要使用,請確定你有一個很好的理由。
如果你需要狀態來呈現內容,你應該使用 useNavigationState
而非此方法。