我正在开发一个 React Native 移动应用程序,使用 Expo Router 进行导航。
该应用程序的大部分功能都是作为我也构建的网站的网络包装器。不过,我正在本机实现一些功能,其中之一就是导航。
为了处理本机应用程序和 Web 应用程序之间的通信,每当本机导航事件发生时,我都会使用
postMessage
向 Web 应用程序发送消息。
我的应用程序包括 4 个底部选项卡,导航的文件夹结构如下所示:
- app
- (tabs)
- _layout.tsx
- tab1.tsx
- tab2.tsx
- tab3.tsx
- tab4.tsx
WebView
组件。我想根据所选选项卡(tab1、tab2 或 tab3)导航到
WebView
中加载的 Web 应用程序的不同页面。我想在 tab4 中显示一个带有一些 React Native 组件的 View
。
问题:
每当我在 tab1、tab2 或 tab3 之间切换时,都会创建 WebView 的新实例。这会导致网站在我第一次选择选项卡时重新加载。我需要一种方法来跨这些选项卡共享 WebView 的单个实例,以便在切换选项卡时不会重新加载。
这是初始(选项卡)
_layout.tsx
;
import { theme } from "@modules/core/theme";
import { NavHeader } from "@modules/navigation/components";
import { Tabs } from "expo-router";
import React from "react";
import { Platform, Text } from "react-native";
const TabLayout = () => {
return (
<Tabs
screenOptions={{
tabBarActiveTintColor: "blue",
tabBarStyle: Platform.select({
ios: {
position: "absolute",
backgroundColor: theme.colors.backgroundDark,
},
default: {
backgroundColor: theme.colors.backgroundDark,
},
}),
header: () => <NavHeader />,
}}
>
<Tabs.Screen
name="tab1"
options={{
tabBarLabel: ({ focused }) => <Text>tab1</Text>,
}}
/>
<Tabs.Screen
name="tab2"
options={{
tabBarLabel: ({ focused }) => <Text>tab2</Text>,
}}
/>
<Tabs.Screen
name="tab3"
options={{
tabBarLabel: ({ focused }) => <Text>tab3</Text>,
}}
/>
<Tabs.Screen
name="tab4"
options={{
tabBarLabel: ({ focused }) => <Text>tab4</Text>,
}}
/>
</Tabs>
);
};
export default TabLayout;
这是每个选项卡内的初始代码。
tab1.tsx
:
import WebView from "react-native-webview";
const Tab1Route = () => {
return <WebView source={{ uri: "https://www.mywebsite.com/tab1" }} />;
};
export default Tab1Route;
tab2.tsx
:
import WebView from "react-native-webview";
const Tab2Route = () => {
return <WebView source={{ uri: "https://www.mywebsite.com/tab2" }} />;
};
export default Tab2Route;
tab3.tsx
:
import WebView from "react-native-webview";
const Tab3Route = () => {
return <WebView source={{ uri: "https://www.mywebsite.com/tab3" }} />;
};
export default Tab3Route;
tab4.tsx
:
import { Text, View } from "react-native";
const Tab4Route = () => {
return (
<View>
<Text>Tab4 screen</Text>
</View>
);
};
export default Tab4Route;
我尝试过的:
渲染
WebView
文件中的 (tabs)/_layout.tsx
以在选项卡之间共享。我将 Tabs
组件包裹在 View
中,并将 Webview
放在选项卡顶部。然而,这导致了一个奇怪的 UI 问题:标题和选项卡之间的内容垂直分为两半。上半部分显示 WebView
,而下半部分是空白的,直到我导航到 tab4(具有本机视图的那个),此时它会显示该 tab4 的正确内容。
Context API:将应用程序包装在
Provider
中,并为每个选项卡中的 ref
组件共享相同的 WebView
。但这没有用。当我第一次打开任何选项卡时,仍然会创建一个新实例。
使用
Portal
在组件树中的更高级别渲染 WebView
组件,并有条件地在每个选项卡中显示它。但是,这也会导致在切换选项卡时创建一个新实例。我使用了 react-native-portals 。
我需要一种方法来确保 tab1、tab2 和 tab3 使用相同的 WebView 实例,以便在这些选项卡之间切换时网站不会重新加载。
有人有使用 Expo Router 在 React Native 中实现此目的的解决方案吗?
共享单个 WebView 实例的步骤:
创建集中式 WebView 组件
创建一个共享 WebViewManager 组件,用于保存 WebView 实例并管理其状态。
使用全局状态管理解决方案
使用状态管理库(如 zustand 或 context)来管理 WebView 的状态及其应加载的 URL。
将共享WebView嵌入到更高级别的组件中 使用 Expo Router 的选项卡导航时,在共享布局或包装器中渲染 WebView 组件。