你醒了 阳光普照,鸟鸣。 在世界上,没有人与任何人交战,没有人挨饿,并且相同的代码可用于Web项目和本机应用程序。 太好了! 不幸的是,只有通用代码才能在地平线上看到,但是即使在今天,通往通用代码的道路仍然充满惊喜。

该材料是我们今天发布的翻译,是使用React Native开发通用应用程序的小而详尽的指南。
为什么这一切呢?
今天的缩写“ PWA”(
Progressive Web Apps ,渐进式Web应用程序)是众所周知的,这个由三个字母组成的首字母缩写似乎只是技术术语中的一条鲸鱼。 但是这种流行的技术仍然不是没有
缺陷 。 与此类应用程序相关的技术难题很多,在某些情况下,开发人员被迫同时创建本机和Web应用程序。
这是一篇比较PWA和本机应用程序
的好文章。
也许业务应该只专注于本机应用程序? 不,不值得。 这是一个大错误。 结果,单个通用应用程序的开发成为一个逻辑步骤。 这使您可以减少开发时间,减少创建和支持项目的成本。 正是这些通用应用程序的这些特性促使我进行了一个小实验。
这是电子商务领域中用于订购食物的通用应用示例。 实验之后,我为将来的项目和进一步的研究创建了一个模板。
Papu是一款专为Android,iOS和Web设计的食品订购应用程序应用程序构建块
这里我们使用React,因此我们需要将应用程序逻辑与用户界面分开。 最好使用某种系统来控制应用程序的状态,例如Redux或Mobx。 这样的举动立即使应用程序的逻辑通用。 它无需更改即可在不同平台上使用。
应用程序的可视部分是另一个对话。 为了构造应用程序接口,您需要具有一组通用的原语,基本构建块。 他们应该在Web和本地环境中工作。 不幸的是,网络语言和本机平台语言是两件事。
例如,一个标准的Web容器会像这样与您联系:
<div> ! - !</div>
和本地的-像这样:
<View>! - React Native</View>
一些聪明的人找到了摆脱这种情况的方法。 输出是专门的元素库。 我最喜欢的之一是很棒的
React Native Web库。 它不仅照顾了应用程序的基本原语,允许在网络上使用React Native组件(不是所有组件!),而且还提供了对各种React Native API的访问权限。 其中包括
Geolocation
,
Platform
,
Animated
,
AsyncStorage
等。 看一下可以在该库的
手册中找到的出色示例。
模式
我们找出了原始元素。 但是我们仍然需要为Web开发和本机开发连接环境。 我的项目使用
create-react-app (对于Web应用程序)和React Native
初始化脚本 (对于没有Expo的本机应用程序)。 首先,我使用以下命令创建了一个项目:
create-react-app rnw_web
。 然后他创建了第二个项目:
react-native init raw_native
。 然后,按照Victor Frankenstein的示例,我从这两个项目中提取了
package.json
文件并将其合并。 之后,在新项目的文件夹中,我输入了新的
yarn
文件。 这是有问题的
package
文件:
{ "name": "rnw_boilerplate", "version": "0.1.0", "private": true, "dependencies": { "react": "^16.5.1", "react-art": "^16.5.1", "react-dom": "^16.5.1", "react-native": "0.56.0", "react-native-web": "^0.9.0", "react-navigation": "^2.17.0", "react-router-dom": "^4.3.1", "react-router-modal": "^1.4.2" }, "devDependencies": { "babel-jest": "^23.4.0", "babel-preset-react-native": "^5", "jest": "^23.4.1", "react-scripts": "1.1.5", "react-test-renderer": "^16.3.1" }, "scripts": { "start": "node node_modules/react-native/local-cli/cli.js start", "test": "jest", "start-ios": "react-native run-ios", "start-web": "react-scripts start", "build": "react-scripts build", "test-web": "react-scripts test --env=jsdom", "eject-web": "react-scripts eject" } }
请注意,此版本的文件中没有导航功能。 接下来,您需要将所有源代码文件从Web应用程序和本机应用程序的文件夹复制到新的统一项目的文件夹中。
文件夹要复制到新项目现在,在新项目目录中的
src
文件夹中,创建两个文件:
App.js
和
App.native.js
。 多亏了
webpack,我们可以使用文件扩展名来告诉捆绑程序使用哪些文件。 分离
App
文件至关重要,因为我们将使用不同的方法来导航应用程序。
这是Web的
App.js
文件。
react-router
用于导航。
// App.js - WEB import React, { Component } from "react"; import { View } from "react-native"; import WebRoutesGenerator from "./NativeWebRouteWrapper/index"; import { ModalContainer } from "react-router-modal"; import HomeScreen from "./HomeScreen"; import TopNav from "./TopNav"; import SecondScreen from "./SecondScreen"; import UserScreen from "./UserScreen"; import DasModalScreen from "./DasModalScreen"; const routeMap = { Home: { component: HomeScreen, path: "/", exact: true }, Second: { component: SecondScreen, path: "/second" }, User: { component: UserScreen, path: "/user/:name?", exact: true }, DasModal: { component: DasModalScreen, path: "*/dasmodal", modal: true } }; class App extends Component { render() { return ( <View> <TopNav /> {WebRoutesGenerator({ routeMap })} <ModalContainer /> </View> ); } } export default App;
这是React Native应用程序的
App.js
在这里,
react-navigation
用于
react-navigation
。
// App.js - React Native import React, { Component } from "react"; import { createStackNavigator, createBottomTabNavigator } from "react-navigation"; import HomeScreen from "./HomeScreen"; import DasModalScreen from "./DasModalScreen"; import SecondScreen from "./SecondScreen"; import UserScreen from "./UserScreen"; const HomeStack = createStackNavigator({ Home: { screen: HomeScreen, navigationOptions: { title: "Home" } } }); const SecondStack = createStackNavigator({ Second: { screen: SecondScreen, navigationOptions: { title: "Second" } }, User: { screen: UserScreen, navigationOptions: { title: "User" } } }); const TabNav = createBottomTabNavigator({ Home: HomeStack, SecondStack: SecondStack }); const RootStack = createStackNavigator( { Main: TabNav, DasModal: DasModalScreen }, { mode: "modal", headerMode: "none" } ); class App extends Component { render() { return <RootStack />; } } export default App;
这就是我创建一个简单的应用程序模板并为进一步的工作准备平台的方式。 您可以通过查看
此存储库来尝试此模板。
现在,我们将使该模板复杂一些,添加一个路由/导航系统。
导航问题及其解决方案
除非由单个屏幕组成,否则应用程序需要某种导航系统。 现在(我们正在谈论2018年9月),只有这样一种通用工作系统,适用于Web和本机应用程序。 这是关于
React Router的 。 对于Web而言,此解决方案效果很好,但是对于React Native项目而言,一切都还不清楚。
在React Router Native中,屏幕之间没有过渡,不支持“后退”按钮(对于Android平台),没有模态屏幕,导航栏和其他功能。 其他导航工具(例如
React Navigation )具有这些功能。
我使用了这个特定的库,但是您可以选择其他东西。 因此,在我的项目中,React Router负责Web应用程序中的导航,React Navigation负责本机应用程序中的导航。 然而,这产生了新的问题。 事实是,这些系统中导航和参数传递的方法非常不同。
为了保留React Native Web的精神,在各处都使用了与本机应用程序类似的方法,我通过创建Web路由并将它们包装在HOC中来解决此问题。 这使我有机会创建类似于React Navigation的API。
这种方法使我可以在Web应用程序的屏幕之间切换,而无需为两种类型的应用程序创建单独的组件。
实现此机制的第一步是创建一个带有Web应用程序路由描述的对象:
import WebRoutesGenerator from "./NativeWebRouteWrapper"; // , React Router HOC const routeMap = { Home: { screen: HomeScreen, path: '/', exact: true }, Menu: { screen: MenuScreen, path: '/menu/sectionIndex?' } } // render <View> {WebRoutesGenerator({ routeMap })} </View>
实际上,这是React Navigation创建功能的副本,其中包含特定于React Router的功能。
接下来,使用助手功能,创建
react-router
路由并将其包装在HOC中。 这使您可以克隆
screen
组件并将
navigation
添加到其属性。 这种方法模仿了React Navigation的行为,
goBack()
,
goBack()
,
getParam()
。
模态屏幕
由于有了
createStackNavigator
,React Navigation使得应用程序的特定页面可以以模态屏幕的形式从下方弹出。 为了在Web应用程序中实现此目的,我不得不使用
React Router Modal库。 要使用模式屏幕,首先需要将适当的选项添加到
routeMap
对象:
const routeMap = { Modal: { screen: ModalScreen, path: '*/modal', modal: true
另外,必须将
react-router-modal
库中的
<ModalContainer />
组件添加到应用程序布局中。 相应的页面将显示在此处。
屏幕之间的导航
多亏了我们开发的HOC(暂时将此组件称为
NativeWebRouteWrapper
,而且,这是一个糟糕的名字),我们可以使用与React Navigation中几乎相同的功能集来组织应用程序的Web版本中页面之间的移动:
const { product, navigation } = this.props <Button onPress={navigation.navigate('ProductScreen', {id: product.id})} title={`Go to ${product.name}`} /> <Button onPress={navigation.goBack} title="Go Back" />
返回上一个屏幕。
在React Navigation中,您可以返回到导航堆栈中的
n
屏幕。 在React Router中类似不可用,没有导航堆栈。 为了解决这个问题,我们需要将我们自己设计的
pop
函数导入代码中。 打电话给她,我们将给她几个参数:
import pop from '/NativeWebRouteWrapper/pop' render() { const { navigation } = this.props return ( <Button onPress={pop({screen: 'FirstScreen', n: 2, navigation})} title="Go back two screens" /> ) }
我们描述以下参数:
screen
的名称(由应用程序的Web版本中的React Router使用)。n
是使用堆栈(使用React Navigation)返回的屏幕数。navigation
提供导航的对象。
工作成果
如果您想尝试此处介绍的开发通用应用程序的想法,那么我创建了两个模板。
首先是一个干净的通用环境,用于开发Web应用程序和本机应用程序。
第二个实质上是第一个模板,由于我的系统可以组织应用程序中的导航,因此已扩展了该模板。
这是基于上述考虑的papu演示应用程序。 它充满了错误和死胡同,但是您可以自己组装它,在浏览器和移动设备上运行它,并在实践中了解它们的工作原理。
总结
当然,React开发人员社区需要一个用于组织应用程序导航的通用库,因为这将简化我们所讨论的项目的开发。 如果React Navigation库可以在Web上运行,那就太好了(事实上,此功能已经
可用 ,但是使用它并非没有困难)。
亲爱的读者们! 您是否利用React来创建通用应用程序?
