当前位置: 首页 > Web前端 > HTML5

TS版react-native三端同构设计

时间:2023-04-05 11:09:59 HTML5

什么是三端同构?刚接触rn开发的同学可能不太了解,我简单介绍一下。三个终端是指Android、IOS、H5。rn本身就是一个跨平台的框架。为了让RN在不改动代码的情况下兼容H5,只需要引入一些库,配置一些细节即可。本模板使用当前react-native@0.6x、react-navigation@5.x新版本搭建ts开发环境。新版本相关库部分API与旧版本不兼容,请勿随意更改主版本!无论是刚入门RN的初学者,还是老版本RN的熟练用户,都可以轻松上手模板源码构建过程(从零开始)1.安装RN并配置开发环境根据官网,对客户端开发前端不熟悉的可以选择沙箱环境。不过还是建议一步步安装客户端环境,毕竟现在是跨平台时代。2.使用react-native生成typescript模板首先,新版RN不再使用react-native-cli,也就是说我们不需要全局安装任何包。只要你的npm版本是5.2+,就可以使用npx命令(npx介绍)。npxreact-nativeinitMyApp--templatereact-native-template-typescriptnpxgeneratesrnfortstemplate,安装完成后,这是一个官方可运行的RN项目,接下来我们将修改这个模板3.配置package.json中为了使用新版@react-navigationv5构建一个完全可用的RN开发项目和我们要做的三端同构,需要添加一些npm依赖包。"dependencies":{//...模板附带的包//..."@react-native-community/async-storage":"1.9.0",//等同于localStorage(可选)"@react-native-community/masked-view":"0.1.9",//路由所需的包(必填)"@react-navigation/stack":"5.2.10",//路由所需的包(必填)“react”:“16.11.0”,“react-dom”:“16.11.0”,“react-native”:“0.62.2”,“react-native-gesture-handler”:“1.6.0”,//路由所需的包,原生手势系统(必填)"react-native-reanimated":"^1.8.0",//路由所需的包(必填)"react-native-safe-area-context":"0.7.3",//路由所需的包(必填)"react-native-screens":"^2.3.0",//路由所需的包(必填)"react-native-webview":"8.0.0",//RN打开webView容器,原生调用(可选)"react-redux":"5.0.7","redux":"4.0.0","redux-thunk":"2.3.0"},"devDependencies":{//...模板自带的包//..."@babel/plugin-transform-runtime":"^7.9.0",//babel的插件包(必填)"@babel/preset-typescript":"^7.9.0",//babel编译ts(必填)"@react-navigation/core":"3.4.2",//rn路由在H5传输线路核心包(必填)"@react-navigation/web":"1.0.0-alpha.8",//H5中运行的rn路由核心包(必填)"babel-loader":"^8.1.0",//webpack加载器(必需)"file-loader":"3.0.1",//webpack加载器(必需)"html-webpack-plugin":"^4.2.0",//webpackplugin(必填)"react-native-web":"0.12.2",//rn组件映射到WEBdom(必填)"webpack":"4.42.1",//打包rn项目到h5(必填)"webpack-cli":"3.3.2",//将rn项目打包到h5(必填)"webpack-dev-server":"3.5.1"//将rn项目调试到h5(必填)},install该装的都不要错过,我建议Stud4.配置webpack和文件入口,首先创建一个index.html文件作为H5打包模板根目录,index.ts是RN原生打包的入口,以及新建一个index.web.ts作为H5打包入口,注意在webpack中添加resolve:{extensions:['.web.ts','.web.tsx','.ts','.tsx','.js','.jsx'],alias:{'react-native$':'react-native-web'}},extensions配置的目的是让我们的项目可以写两个不同后缀的文件xx从'./xx'导入XX.web.ts,xx.ts一个是给RN打包成native,一个是给webpack打包成H5,用于不同平台代码的定制化开发,在路由上用处极大。.web.ts必须配置在.ts前面,这样webpack才能先找到属于H5的文件并打包。另外,alias是将react-native整个库的组件映射到react-native-web。其实这个库的原理就是为RN的每个组件写好对应的dom,然后传入props。因为也可以自己扩展,所以有些原生组件是react-native-web中没有的,比如开头提到的webView。{test:/\.(js|jsx|ts|tsx)$/,使用:[{loader:'babel-loader',options:{cacheDirectory:false,presets:['module:metro-react-native-babel-preset','@babel/preset-typescript'],plugins:['@babel/plugin-transform-runtime']}}],exclude:/node_modules/}其次,配置babel-loader编译ts,特别是这里注意:不能用ts-loader编译!因为我们在tsconfig.json文件中配置的jsx被识别为react-native,用于编译到客户端,但实际上我们将其代理成一个dom元素,打包会产生冲突,导致loader编译错误。解决方法是直接使用babel-loader配置编译TS,生成sourcemap5。配置React-navigation,ReduxRedux状态管理和普通react一样,也可以使用其他库。毕竟状态管理不涉及渲染。主要讲解一下RN的路由库React-navigation,各个版本的API差异很大,V5版本将API拆分成多组@react-navigation/,路由配置选项有很多,我这里提供一个://router.tsimport'react-native-gesture-handler';从'react'导入React;从'react-redux'导入{connect};从'@react-native-community/async-storage'导入AsyncStorage;从'@react-navigation/native'导入{InitialState,useLinking,NavigationContainerRef,NavigationContainer,DefaultTheme,DarkTheme};从'@react-navigation/stack'导入{createStackNavigator,HeaderStyleInterpolators};从'./config'导入路线;类型RootDrawerParamList={[key:string]:any;};constStack=createStackNavigator();constHeaderNull=function():React.ReactNode{returnnull;};constMyApp=function(){constNAVIGATION_PERSISTENCE_KEY='导航状态';constcontainerRef=React.useRef(null);const[initialState,setInitialState]=React.useState<初始状态|未定义>();const[主题,setTheme]=React.useState(DefaultTheme);返回{try{awaitAsyncStorage.setItem(NAVIGATION_PERSISTENCE_KEY,JSON.stringify(state));}catch(e){console.log(e);}}}theme={theme}>{(Object.keys(routes)as(keyoftypeofroutes)[]).map((name)=>(HeaderNull()}}/>))};};constmapStateToProps=(state:any)=>state;exportdefaultconnect(mapStateToProps)(MyApp);简单的说,导入路由配置就可以了,但是需要把这个config提取出来,因为我们在这个目录下还有一个route.web.ts,同样需要引用,只是引用配置的库不一样.在H5中,我们使用@react-navigation/web://router.web.tsimport{connect}from'react-redux';import{createSwitchNavigator}from'@react-navigation/core';import{createBrowserApp}from'@react-navigation/web';从'导入路线。/配置';constMyNavigator=createSwitchNavigator(routes);constMyApp=createBrowserApp(MyNavigator);constmapStateToProps=状态=>状态;导出默认连接(mapStateToProps)(MyApp);这些页面都引用相同的组件。6.link使用的原生组件库项目初始配置package.json有两个native模块模块包,需要使用link进行关联操作,否则构建客户端npmi执行后报错:npxreact-nativelinkreact-native-gesture-handler这是react-navigation使用的原生手势系统。npxreact-nativelink@react-native-community/async-storage这个类似于浏览器的localStorage原生缓存。7.让模板启动~配置npm启动命令//package.json"scripts":{"android":"react-nativerun-android","ios":"react-nativerun-ios","start":"react-nativestart","web:dev":"webpack-dev-server--configwebpack.config.web.ts--inline--hot--colors","web":"webpack-p--configwebpack.config.web.ts"},nativeclient使用npmrunandroid或npxreact-nativerun-android(npmv5.2+)启动npmrunweb:dev启动webpack-dev-server调试,和普通移动开发一样,npmrunweb将生产环境代码打包成dist-H58。效果显示Native:H59。总结从上面的截图我们可以看出几点:UI风格基本可以一一还原路由动画,不如原来的好(好像看不到图。。。)H5首页红圈。这是因为我故意使用了一个react-native-web不支持的组件。该区域将在H5中标记为红色。在Native-3中,有一个客户端半屏webView容器,打开一个第三方H5,就是使用的原生RN组件。这在H5中显然是做不到的,所以在这种情况下,需要单独处理环境兼容性。(我这里没有兼容,可以看到打包H5时webpack抛出的警告。)其实总的来说还是可以的。在生产环境中,只推荐使用UI堆叠应用。H5硬件交互就别想了,或者去JSBridge桥接原生。不过在浏览器里用来调试RN开发的view也不错~如果对项目配置细节(路由、webpack、ts等)有疑惑,可以直接参考已经搭建好的模板:github.com/yukilzw/rn_web