React Navigation 在 Web 上的应用
React Navigation 内置了对 Web 平台的支持。这使你可以在 React Native 应用以及 Web 上使用相同的导航逻辑。这些导航器需要在 Web 上使用 React Native for Web 才能工作。
前提条件
虽然 Web 支持开箱即用,但仍有一些事项需要配置以确保在 Web 上获得良好的体验
-
配置链接允许 React Navigation 与浏览器的 URL 栏集成。这对于 Web 应用为每个屏幕设置正确的 URL 至关重要。
-
你可能熟悉使用
navigation.navigate
在屏幕之间导航。但在支持 Web 时,重要的是要避免使用它。相反,使用Link
或Button
组件在屏幕之间导航。这确保了渲染一个锚标记,从而在 Web 上提供预期的行为。 -
目前,React Navigation 在完全客户端渲染的应用中效果最佳。但是,也提供了最基本的服务端渲染支持。因此,你可以选择性地服务端渲染你的应用。
在 React Navigation 4 中,需要安装一个名为 @react-navigation/web
的单独包才能使用 Web 集成。在最近版本的 React Navigation 中,不再需要此包。如果你已安装它,请确保卸载它以避免冲突。
懒加载屏幕
默认情况下,屏幕组件捆绑在主 bundle 中。如果你有很多屏幕,这可能会导致 bundle 尺寸过大。在 Web 上保持 bundle 尺寸较小对于更快的加载时间非常重要。
为了减小 bundle 尺寸,你可以将 dynamic import()
与 React.lazy
结合使用来懒加载屏幕
- 静态
- 动态
import { Suspense, lazy } from 'react';
const MyStack = createNativeStackNavigator({
screenLayout: ({ children }) => (
<Suspense fallback={<Loading />}>{children}</Suspense>
),
screens: {
Home: {
component: lazy(() => import('./HomeScreen')),
},
Profile: {
component: lazy(() => import('./ProfileScreen')),
},
},
});
import { Suspense, lazy } from 'react';
const HomeScreen = lazy(() => import('./HomeScreen'));
const ProfileScreen = lazy(() => import('./ProfileScreen'));
function MyStack() {
return (
<Stack.Navigator
screenLayout={({ children }) => (
<Suspense fallback={<Loading />}>{children}</Suspense>
)}
>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Profile" component={ProfileScreen} />
</Stack.Navigator>
);
}
确保在包含导航器配置的组件外部使用 React.lazy
。否则,它将在每次渲染时返回一个新组件,导致每次组件重新渲染时屏幕都会被卸载并重新挂载。
这将把屏幕组件拆分成单独的代码块(取决于你的 bundler),这些代码块会在屏幕渲染时按需加载。这可以显著减小初始 bundle 尺寸。
此外,你可以使用 screenLayout
将你的屏幕包裹在 <Suspense>
边界中。suspense fallback 可用于显示加载指示器,并在屏幕组件加载时显示。
Web 特有行为
与原生平台相比,某些导航器在 Web 上具有不同的行为
-
原生栈导航器使用平台的原生组件来处理原生平台上的动画和手势。但是,Web 上不支持动画和手势。
-
栈导航器使用
react-native-gesture-handler
来处理原生平台上的滑动 gestures。但是,Web 上不支持手势。此外,Web 上默认禁用屏幕过渡动画。你可以在导航器的选项中设置
animationEnabled: true
来启用它们。 -
抽屉导航器使用
react-native-gesture-handler
来处理滑动 gestures,并使用react-native-reanimated
来处理原生平台上的动画。但是,Web 上不支持手势,动画使用 CSS 过渡来处理。
此外,导航器在 Web 上尽可能渲染超链接,例如在抽屉侧边栏、标签栏、栈导航器的返回按钮等中。
由于 react-native-gesture-handler
和 react-native-reanimated
未在 Web 上使用,因此除非你的组件需要它们,否则请避免在自己的代码中导入它们以减小 bundle 尺寸。你可以为特定于原生平台的代码使用 .native.js
或 .native.ts
扩展名。
配置托管服务提供商
React Navigation 专为单页应用程序 (SPA) 设计。这通常意味着 index.html
文件需要为所有路由提供服务。
在开发过程中,诸如 Webpack 或 Metro 之类的 bundler 会自动处理此问题。但是,在部署站点时,你可能需要配置重定向以确保为所有路由提供 index.html
文件,以避免 404 错误。
以下是一些流行托管服务提供商的说明
Netlify
要在 Netlify 上处理重定向,请在项目根目录的 netlify.toml
文件中添加以下内容
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
Vercel
要在 Vercel 上处理重定向,请在项目根目录的 vercel.json
文件中添加以下内容
{
"rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
}
GitHub Pages
GitHub Pages 不支持 SPA 的此类重定向配置。有几种方法可以解决这个问题
- 将你的
index.html
重命名为404.html
。这将为所有路由提供404.html
文件。但是,这将导致所有路由都返回 404 状态代码。因此,这对 SEO 来说并不理想。 - 编写一个脚本,将
index.html
文件复制到构建输出中的所有路由。例如,如果你的应用具有路由/
、/about
和/contact
,你可以将index.html
文件复制到about.html
和contact.html
。