React Native三端同构(一: 基础方案)

(一) 前言
React Native 三端(Web、iOS、Android)同构是指在使用 React Native封装组件 的代码下,让其在浏览器中运行出和在 React Native 环境下一样的页面。

对于使用 React Native 开发的页面,如果又单独为 Web 平台重复写一份代码代价是极大的,而 React Native 三端同构能以最小代价做到一份代码三端复用。并且也需要提供Web和App各自能独立使用的代码方案。

(二)问题

  1. 采用何种方案
  • 微软开源方案reactxp
    。这种方案提供ios/android/web/windows 桌面。但是因为提供的api少的问题,即使是skype团队维护,也不建议在无客户端情况下采用。
  • 社区方案taro。taro除开web,还可以使用编译成小程序,但是依旧绕不开,提供的api少的问题,所以在无小程序需求,依旧不建议使用
  • 社区方案react-native-web,react-native-web 对原项目没有侵入性,无需改动原来的代码,只需在项目中加入一些 webpack 构建配置即可构建出运行出和 React Native 应用一致效果的 Web 应用。就目前需求,建议使用此方案。
  1. 路由机制
  • 我们知道react-native主流路由react-navigation
    路由机制类似于栈,当我们每次push一个新路由,他会加载在路由栈内,直到页面退出,才从栈中移除。而web路由代表的react-router-dom,其实会只加载一个路由页面,switch都会默认只匹配一个路由。

  • 所以,针对两种不同路由机制,最好方案是,使用不同路由配置,这样尽量将组件封装成通用,以适配两端应用。

  1. 状态管理
    状态管理,可以选择redux或者mobx,两者代码几乎都能复用
  2. 判断平台
    在代码中,其实Platform.os 新增为web,提供web判断,所以,方便我们去处理, 但是webpack在process.env中我并没发现提供web环境区分的方案,所以,我们在webpack新增一个变量IS_WEB由打包命令加入(下一章webpack配置会写怎么加入命令),那么我们就可以在babel.config.js针对不同的环境,加载对应的配置文件。

(三) 创建react-native 项目工程

  1. 直接以cli方式新建 react-native init react_native_web_demo, 此时我们已经有个rn项目工程,

  2. 然后替换默认[email protected] 到 @babel/core@7

$ yarn remove babel-core
$ yarn add @babel/core --dev
  1. 初始化pod文件
$ cd ios && pod init
  1. 修改Podfile文件
 # Uncomment the next line if you're using Swift or would like to use dynamic frameworks
 # use_frameworks!

platform :ios, '9.0'

target 'react_native_web_demo' do
  # this is very important to have!
  rn_path = '../node_modules/react-native'
  pod 'yoga', path: "#{rn_path}/ReactCommon/yoga/yoga.podspec"
  pod 'React', path: rn_path, subspecs: [
    'Core',
    'RCTActionSheet',
    'RCTAnimation',
    'RCTGeolocation',
    'RCTImage',
    'RCTLinkingIOS',
    'RCTNetwork',
    'RCTSettings',
    'RCTText',
    'RCTVibration',
    'RCTWebSocket'
  ]
end

# very important to have, unless you removed React dependencies for Libraries
# and you rely on Cocoapods to manage it
post_install do |installer|
  installer.pods_project.targets.each do |target|
    if target.name == "React"
      target.remove_from_project
    end
  end
end

  1. package.json新增加script命令
"setup": "yarn install && cd ios && pod install && cd .. && react-native link",
"android": "react-native run-android",
"iPhoneX": "react-native run-ios --simulator 'iPhone X'",
"clear": "watchman watch-del-all && rm -rf $TMPDIR/react-* && rm -rf node_modules/ && yarn install && yarn start -- --reset-cache",
  1. 启动react-native项目工程,
$ yarn setup
$ yarn start
$ yarn iPhoneX
$ yarn android

这是一个初始化rn项目设置完成

(四) 新增web配置文件

  1. 新增react-native-web依赖
$ yarn add react-dom react-native-web react-art
  1. 新增webpack相关依赖
$ yarn add webpack-cli webpack-dev-server webpack html-webpack-plugin babel-loader url-loader --dev
  1. 根文件下新建public,增加index.html文件



  react-native-web
  
  
  
  
  
  
  
  
  
  
  
  
  
  


  
  1. 根文件下新建web-build,增加webpack.config.js文件
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const appDir = path.resolve(__dirname, '../');

module.exports = {
  entry: {
    bundle: path.resolve(appDir, 'index.web'),
  },
  output: {
    filename: 'bundle.web.js',
    path: path.resolve(appDir, 'dist'),
  },
  module: {
    rules: [{
      test: /\.(js|jsx)$/,
      include: [
        path.resolve(appDir, 'src'),
        path.resolve(appDir, 'react-native-web'),
      ],
      use: [{
        loader: 'babel-loader',
        options: {
          cacheDirectory: true,
          babelrc: false,
        },
      }],
    },
      {
        test: /\.(gif|jpe?g|png|svg)$/,
        use: {
          loader: 'url-loader',
          options: {
            name: '[name].[ext]',
          },
        },
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(appDir, 'public/index.html'),
    }),
  ],
  resolve: {
    extensions: ['.js', '.json', '.android.js', '.ios.js'],
    alias: {
      'react-native$': 'react-native-web',
    },
    modules: ['web_modules', 'node_modules'],
  },
};
  1. package.json新增加script命令
 "web": "NODE_ENV=development webpack-dev-server -d --config ./web-build/webpack.config.js --inline --hot --colors",
 "build": "NODE_ENV=production webpack -p --config ./web-build/webpack.config.js"
  1. 在根文件下新建index.web.js
import { AppRegistry } from 'react-native';
import { name as appName } from './app.json';
import App from './src/App';

AppRegistry.registerComponent(appName, () => App);

AppRegistry.runApplication(appName, {
  rootTag: document.getElementById('root')
});

最后,在根文件下新建src,将App.js 移动到src里面。这样目前就可以使用web开发命令了,
并修改App.js

const instructions = Platform.select({
  ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu',
  android:
    'Double tap R on your keyboard to reload,\n' +
    'Shake or press menu button for dev menu',
  web: 'This is web',
});

React Native三端同构(一: 基础方案)_第1张图片

(五) 结语

在第四步中,我们虽然有一个简单的web开发环境,但是就目前真正开发还有一段距离,比如

  • 路由处理
  • 样式处理
  • webpack配置优化
  • 页面结构分层
  • 代码规范eslint

你可能感兴趣的:(ReactNative,React,H5)