> For the complete documentation index, see [llms.txt](https://developers-apps-in-toss.toss.im/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers-apps-in-toss.toss.im/documentation/api-and-sdk-zh/react-native/screen-navigation/navigation.md).

# 页面跳转

在 Granite 应用中，可以轻松处理页面切换、历史记录管理、参数传递等路由功能。内部则是 [React Navigation](https://reactnavigation.org/)基于其运行，因此可以直接用熟悉的 API 来使用。

{% hint style="info" %}
**WebView 路由**

在 WebView 环境中，会原封不动地遵循你在项目中配置的 Web 路由器（例如 React Router）规则，无需修改。
{% endhint %}

### 路由示例结构

路由示例共由 3 个页面（`page-a`, `page-b`, `page-c`）组成。

{% code collapsedlinecount="10" %}

```
root
├─── pages
│    ├─── page-a.tsx
│    ├─── page-b.tsx
│    └─── page-c.tsx
└─── src
     └─── ...
```

{% endcode %}

<details>

<summary>`page-a.tsx` 源代码</summary>

{% code collapsedlinecount="10" %}

```tsx
// page-a.tsx
import { StyleSheet, View, Text, Pressable } from 'react-native';
import { createRoute, useNavigation } from '@granite-js/react-native';

export const Route = createRoute('/page-a', {
  validateParams: (params) => params,
  component: PageA,
});

function PageA() {
  const navigation = useNavigation();

  const handlePress = () => {
    navigation.navigate('/page-b');
  };

  return (
    <View style={[styles.container, { backgroundColor: '#3182f6' }]}>
      <Text style={styles.text}>Page A</Text>
      <Pressable onPress={handlePress}>
        <Text style={styles.buttonLabel}>跳转到 B 页面</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    gap: 16,
    padding: 16,
  },
  text: {
    color: 'white',
    fontSize: 24,
  },
  buttonLabel: {
    color: 'white',
  },
});
```

{% endcode %}

</details>

<details>

<summary>`page-b.tsx` 源代码</summary>

{% code collapsedlinecount="10" %}

```tsx
// page-b.tsx
import { createRoute, useNavigation } from '@granite-js/react-native';
import { StyleSheet, View, Text, Pressable } from 'react-native';

export const Route = createRoute('/page-b', {
  validateParams: (params) => params,
  component: PageB,
});

function PageB() {
  const navigation = useNavigation();

  // 返回上一页的函数。
  const handlePressBackButton = () => {
    if (navigation.canGoBack()) {
      navigation.goBack();
    } else {
      console.warn('无法返回上一页。');
    }
  };

  const handlePressNextButton = () => {
    navigation.navigate('/page-c', {
      message: '你好！',
      date: new Date().getTime(),
    });
  };

  return (
    <View style={[styles.container, { backgroundColor: '#fe9800' }]}>
      <Text style={styles.text}>Page B</Text>
      <Pressable onPress={handlePressBackButton}>
        <Text style={styles.buttonLabel}>返回上一页</Text>
      </Pressable>
      <Pressable onPress={handlePressNextButton}>
        <Text style={styles.buttonLabel}>跳转到 C 页面</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    gap: 16,
    padding: 16,
  },
  text: {
    color: 'white',
    fontSize: 24,
  },
  buttonLabel: {
    color: 'white',
  },
});
```

{% endcode %}

</details>

<details>

<summary>`page-c.tsx` 源代码</summary>

{% code collapsedlinecount="10" %}

```tsx
// page-c.tsx
import { useNavigation, createRoute } from '@granite-js/react-native';
import { CommonActions } from '@granite-js/native/@react-navigation/native';
import { StyleSheet, View, Text, Pressable } from 'react-native';

export const Route = createRoute('/page-c', {
  validateParams: (params) => params as { message: string; date: number },
  component: PageC,
});

function PageC() {
  const navigation = useNavigation();
  const params = Route.useParams();

  const handlePressHomeButton = () => {
    navigation.dispatch((state) => {
      return CommonActions.reset({
        ...state,
        index: 0,
        routes: state.routes.filter((route) => route.name === '/page-a'),
      });
    });
  };

  return (
    <View style={[styles.container, { backgroundColor: '#f04452' }]}>
      <Text style={styles.text}>{params.message}</Text>
      <Text style={styles.text}>{params.date}</Text>
      <View style={styles.line} />
      <Text style={styles.text}>Page C</Text>
      <Pressable onPress={handlePressHomeButton}>
        <Text style={styles.buttonLabel}>回到首页</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    gap: 16,
    padding: 16,
  },
  text: {
    color: 'white',
    fontSize: 24,
  },
  buttonLabel: {
    color: 'white',
  },
});
```

{% endcode %}

</details>

### 页面 A：页面跳转

[`useNavigation`](https://reactnavigation.org/docs/use-navigation)用于处理页面之间的跳转。 [`navigate`](https://reactnavigation.org/docs/navigation-actions/#navigate) 可通过该方法同时传递要跳转的页面路径和所需数据。

{% code collapsedlinecount="10" %}

```tsx
// page-a.tsx
import { createRoute, useNavigation } from '@granite-js/react-native'; // [!code highlight]
import { StyleSheet, View, Text, Pressable } from 'react-native';

export const Route = createRoute('/page-a', {
  validateParams: (params) => params,
  component: PageA,
});

function PageA() {
  const navigation = useNavigation(); // [!code highlight]
  // [!code highlight:4]
  const handlePress = () => {
    navigation.navigate('/page-b');
  };

  return (
    <View style={[styles.container, { backgroundColor: '#3182f6' }]}>
      <Text style={styles.text}>Page A</Text>
      <Pressable onPress={handlePress}>
        <Text style={styles.buttonLabel}>跳转到 B 页面</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    gap: 16,
    padding: 16,
  },
  text: {
    color: 'white',
    fontSize: 24,
  },
  buttonLabel: {
    color: 'white',
  },
});
```

{% endcode %}

#### 关键点

* `useNavigation` 使用 Hook 取得 `navigation` 对象。
* `navigation.navigate('/page-b')`调用后会跳转到 'B' 页面。

### 页面 B：返回上一页

[`goBack`](https://reactnavigation.org/docs/navigation-actions/#goback) 方法可以返回上一页。不过，如果没有上一页记录，可能会发生错误，因此， [`canGoBack`](https://reactnavigation.org/docs/navigation-prop/#cangoback)要先进行确认。

{% code collapsedlinecount="10" %}

```tsx
// page-b.tsx
import { createRoute, useNavigation } from '@granite-js/react-native'; // [!code highlight]
import { StyleSheet, View, Text, Pressable } from 'react-native';

export const Route = createRoute('/page-b', {
  validateParams: (params) => params,
  component: PageB,
});

function PageB() {
  const navigation = useNavigation(); // [!code highlight]

  // 返回上一页的函数。 // [!code highlight:8]
  const handlePressBackButton = () => {
    if (navigation.canGoBack()) {
      navigation.goBack();
    } else {
      console.warn('无法返回上一页。');
    }
  };

  const handlePressNextButton = () => {
    navigation.navigate('/page-c', {
      message: '你好！',
      date: new Date().getTime(),
    });
  };

  return (
    <View style={[styles.container, { backgroundColor: '#fe9800' }]}>
      <Text style={styles.text}>Page B</Text>
      <Pressable onPress={handlePressBackButton}>
        <Text style={styles.buttonLabel}>返回上一页</Text>
      </Pressable>
      <Pressable onPress={handlePressNextButton}>
        <Text style={styles.buttonLabel}>跳转到 C 页面</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    gap: 16,
    padding: 16,
  },
  text: {
    color: 'white',
    fontSize: 24,
  },
  buttonLabel: {
    color: 'white',
  },
});
```

{% endcode %}

#### 关键点

* `canGoBack()`先用它确认是否有上一页，如果有， `goBack()`就会被调用。
* `navigate('/page-c', { message: '你好！', date: new Date().getTime() })`在传递数据的同时跳转到 'C' 页面。

### 页面 C：使用传入的数据

`Route.useParams` Hook 用于获取从其他页面传来的数据。

此时， `createRoute.validateParams` 如果设置该选项，就可以在进行类型校验（Type-Safe）的同时访问传入的数据。这样可以避免因错误的数据格式导致的错误。

{% code collapsedlinecount="10" %}

```tsx
// page-c.tsx
import { createRoute, useNavigation } from '@granite-js/react-native'; // [!code highlight]
import { CommonActions } from '@granite-js/native/@react-navigation/native';
import { StyleSheet, View, Text, Pressable } from 'react-native';

// [!code highlight:5]
export const Route = createRoute('/page-c', {
  validateParams: (params) => params as { message: string; date: number },
  component: PageC,
});

function PageC() {
  const navigation = useNavigation();
  const params = Route.useParams(); // [!code highlight:7]
  // 或者也可以像下面这样使用。
  // import { useParams } from '@granite-js/react-native';
  //
  // const params = useParams({
  //   from: '/page-b',
  // });

  const handlePressHomeButton = () => {
    navigation.dispatch((state) => {
      return CommonActions.reset({
        ...state,
        index: 0,
        routes: state.routes.filter((route) => route.name === '/page-a'),
      });
    });
  };

  return (
    <View style={[styles.container, { backgroundColor: '#f04452' }]}>
      <Text style={styles.text}>{params.message}</Text> // [!code highlight]
      <Text style={styles.text}>{params.date}</Text> // [!code highlight]
      <View style={styles.line} />
      <Text style={styles.text}>Page C</Text>
      <Pressable onPress={handlePressHomeButton}>
        <Text style={styles.buttonLabel}>回到首页</Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    gap: 16,
    padding: 16,
  },
  text: {
    color: 'white',
    fontSize: 24,
  },
  buttonLabel: {
    color: 'white',
  },
});
```

{% endcode %}

#### 关键点

* `Route.useParams` 使用 Hook 可以访问从 URL 传来的数据（参数）。
* `createRoute.validateParams` 设置该选项后，可以在进行类型校验（Type-Safe）的同时安全使用数据。

### 定义页面参数类型

每个页面都定义如下的 Route 组件。其中 `validateParams` 选项用于定义该页面接收的参数类型。

{% code collapsedlinecount="10" %}

```tsx
export const Route = createRoute('/page-c', {
  validateParams: (params) => params as { message: string; date: number }, // [!code highlight]
  component: PageC,
});
```

{% endcode %}

在上面的代码中， `validateParams`是 `消息`和 `date`和 message 这两个字段的参数定义为类型。

通过这样， `useNavigate`或 `useParams`在使用时，可以通过类型检查清楚地了解所需路径和应传递的数据。这样能提高代码的安全性和可读性。

***

#### 自动生成类型定义

在开发模式下， `pages/` 当目录中添加文件时，会自动生成类型定义，因此无需执行额外命令。

#### 生成的文件示例

自动生成的文件如下。由于是自动生成的文件，无需手动修改。

{% code collapsedlinecount="10" %}

```tsx
// src/router.gen.ts

/* eslint-disable */
// This file is auto-generated by @granite-js/react-native. DO NOT EDIT.
import { Route as _AboutRoute } from '../pages/about';
import { Route as _IndexRoute } from '../pages/';

declare module '@granite-js/react-native' {
  interface RegisterScreen {
    '/about': ReturnType<typeof _AboutRoute.useParams>;
    '/': ReturnType<typeof _IndexRoute.useParams>;
  }
}
```

{% endcode %}

#### 关键点

* 为各页面接收的参数类型 `createRoute.validateParams` 如果通过该选项预先定义， `navigate`和 `params` 在使用时就能进行类型检查，从而更安全地编写代码。
* 在开发模式下， `pages/` 当目录中添加文件时，类型定义会自动生成，因此无需单独执行命令。

这样使用 React Navigation，就可以轻松处理页面间跳转，并通过传递数据或操作记录等功能实现多样的 UX。此外，配合 TypeScript 使用，还能编写安全而稳健的代码。

### 重置路由状态

按“页面 A → 页面 B → 页面 C”的顺序跳转后，状态可以如下图所示表示。

页面 A、页面 B、页面 C 按顺序 `routes` 保留在记录中， `index` 值指向最后跳转到的页面 C 的位置 2。

`reset`使用 reset 可以初始化页面跳转记录。例如，如果在跳转到“页面 A → B → C”之后，想返回“页面 A”并删除 B 和 C 的记录， [`CommonActions.reset`](https://reactnavigation.org/docs/navigation-actions/#reset)。

{% code collapsedlinecount="10" %}

```tsx
navigation.dispatch(
  CommonActions.reset({
    index: 0,
    routes: [{ name: '/page-a' }],
  }),
);
```

{% endcode %}

#### 关键点

* `CommonActions.reset`就可以只保留特定页面的记录，并删除其余页面的记录。

### 参考资料

* [React Navigation 官方文档](https://reactnavigation.org/)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developers-apps-in-toss.toss.im/documentation/api-and-sdk-zh/react-native/screen-navigation/navigation.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
