mirror of
https://github.com/zhigang1992/react-navigation.git
synced 2026-04-26 05:25:30 +08:00
feat: add a hook to update document title
This commit is contained in:
@@ -277,6 +277,10 @@ export default function App() {
|
||||
},
|
||||
}}
|
||||
fallback={<Text>Loading…</Text>}
|
||||
documentTitle={{
|
||||
format: (options, route) =>
|
||||
`${options?.title ?? route?.name} - React Navigation Example`,
|
||||
}}
|
||||
>
|
||||
<Drawer.Navigator drawerType={isLargeScreen ? 'permanent' : undefined}>
|
||||
<Drawer.Screen
|
||||
|
||||
@@ -9,13 +9,15 @@ import DefaultTheme from './theming/DefaultTheme';
|
||||
import LinkingContext from './LinkingContext';
|
||||
import useThenable from './useThenable';
|
||||
import useLinking from './useLinking';
|
||||
import useDocumentTitle from './useDocumentTitle';
|
||||
import useBackButton from './useBackButton';
|
||||
import type { Theme, LinkingOptions } from './types';
|
||||
import type { Theme, LinkingOptions, DocumentTitleOptions } from './types';
|
||||
|
||||
type Props = NavigationContainerProps & {
|
||||
theme?: Theme;
|
||||
linking?: LinkingOptions;
|
||||
fallback?: React.ReactNode;
|
||||
documentTitle?: DocumentTitleOptions;
|
||||
onReady?: () => void;
|
||||
};
|
||||
|
||||
@@ -29,11 +31,19 @@ type Props = NavigationContainerProps & {
|
||||
* @param props.theme Theme object for the navigators.
|
||||
* @param props.linking Options for deep linking. Deep link handling is enabled when this prop is provided, unless `linking.enabled` is `false`.
|
||||
* @param props.fallback Fallback component to render until we have finished getting initial state when linking is enabled. Defaults to `null`.
|
||||
* @param props.documentTitle Options to configure the document title on Web. Updating document title is handled by default unless `documentTitle.enabled` is `false`.
|
||||
* @param props.children Child elements to render the content.
|
||||
* @param props.ref Ref object which refers to the navigation object containing helper methods.
|
||||
*/
|
||||
const NavigationContainer = React.forwardRef(function NavigationContainer(
|
||||
{ theme = DefaultTheme, linking, fallback = null, onReady, ...rest }: Props,
|
||||
{
|
||||
theme = DefaultTheme,
|
||||
linking,
|
||||
fallback = null,
|
||||
documentTitle,
|
||||
onReady,
|
||||
...rest
|
||||
}: Props,
|
||||
ref?: React.Ref<NavigationContainerRef | null>
|
||||
) {
|
||||
const isLinkingEnabled = linking ? linking.enabled !== false : false;
|
||||
@@ -41,6 +51,7 @@ const NavigationContainer = React.forwardRef(function NavigationContainer(
|
||||
const refContainer = React.useRef<NavigationContainerRef>(null);
|
||||
|
||||
useBackButton(refContainer);
|
||||
useDocumentTitle(refContainer, documentTitle);
|
||||
|
||||
const { getInitialState } = useLinking(refContainer, {
|
||||
enabled: isLinkingEnabled,
|
||||
|
||||
@@ -2,6 +2,7 @@ import type {
|
||||
getStateFromPath as getStateFromPathDefault,
|
||||
getPathFromState as getPathFromStateDefault,
|
||||
PathConfigMap,
|
||||
Route,
|
||||
} from '@react-navigation/core';
|
||||
|
||||
export type Theme = {
|
||||
@@ -52,6 +53,14 @@ export type LinkingOptions = {
|
||||
getPathFromState?: typeof getPathFromStateDefault;
|
||||
};
|
||||
|
||||
export type DocumentTitleOptions = {
|
||||
enabled?: boolean;
|
||||
format?: (
|
||||
options: Record<string, any> | undefined,
|
||||
route: Route<string> | undefined
|
||||
) => string;
|
||||
};
|
||||
|
||||
export type ServerContainerRef = {
|
||||
getCurrentOptions(): Record<string, any> | undefined;
|
||||
};
|
||||
|
||||
3
packages/native/src/useDocumentTitle.native.tsx
Normal file
3
packages/native/src/useDocumentTitle.native.tsx
Normal file
@@ -0,0 +1,3 @@
|
||||
export default function useDocumentTitle() {
|
||||
// Noop for React Native
|
||||
}
|
||||
37
packages/native/src/useDocumentTitle.tsx
Normal file
37
packages/native/src/useDocumentTitle.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import * as React from 'react';
|
||||
import type { NavigationContainerRef } from '@react-navigation/core';
|
||||
import type { DocumentTitleOptions } from './types';
|
||||
|
||||
/**
|
||||
* Set the document title for the active screen
|
||||
*/
|
||||
export default function useDocumentTitle(
|
||||
ref: React.RefObject<NavigationContainerRef>,
|
||||
{
|
||||
enabled = true,
|
||||
format = (options, route) => options?.title ?? route?.name,
|
||||
}: DocumentTitleOptions = {}
|
||||
) {
|
||||
React.useEffect(() => {
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const navigation = ref.current;
|
||||
|
||||
if (navigation) {
|
||||
const title = format(
|
||||
navigation.getCurrentOptions(),
|
||||
navigation.getCurrentRoute()
|
||||
);
|
||||
|
||||
document.title = title;
|
||||
}
|
||||
|
||||
return navigation?.addListener('options', (e) => {
|
||||
const title = format(e.data.options, navigation?.getCurrentRoute());
|
||||
|
||||
document.title = title;
|
||||
});
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user