最近学习了下跨平台开发,了解了下React Native和Flutter,前者是由Facebook提供,使用JavaScript语言开发,后者由Google提供,使用dart语言开发。这两个框架都可以实现跨平台的开发,并且都比单纯使用H5页面性能好。由于RN支持热更新,并且JS语法更大众化,个人更偏向使用RN开发。
接下来我们看下如何集成RN框架到现有项目中,以及RN的一些基本概念:
RN中的组件分为两种,一种是函数式组件,一种是类组件。起初函数式组件是没有state概念的,后来添加了Hooks API,使得我们可以添加state到函数式组件中。
以下是函数式组件的代码示例:
import React from 'react';
import { Text, View } from 'react-native';
const HelloWorldApp = () => {
return (
<View style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}}>
<Text>Hello, world!</Text>
</View>
);
}
export default HelloWorldApp;
类组件代码:
import React, { Component } from 'react';
import { Text, View } from 'react-native';
class HelloWorldApp extends Component {
render() {
return (
<View style={{
flex: 1,
justifyContent: "center",
alignItems: "center"
}}>
<Text>Hello, world!</Text>
</View>
);
}
}
export default HelloWorldApp;
RN中组件的概念可以理解为iOS中的视图,他的原理是我们使用JS写的组件会被RN框架转成相应的iOS视图。由于React Native 组件就是对原生视图的封装,因此使用 React Native 编写的应用外观、感觉和性能与其他任何原生应用一样。我们也可以构建自己的原生组件或者到社区中查找别人已开发好的组件。
React Native是在React之上运行的,React是web端的开源UI框架。接下来介绍React的几个核心概念:
component组件
这个在上文中已经提到,用来表示视图
JSX
JSX语法使得我们可以在JS中直接输出元素:<Text>Hello world!</Text>,我们可以通过这份文档来深刻了解JSX语法,实际上,它是React.createElement(component, props, ...children) 函数的语法糖。我们也可以在元素中使用变量,例如<Text>Hello {name}!</Text>,name为提前声明的一个变量。
props
props是"properties"的简写,我们可以使用这个特性来定制组件。例如给每只<Cat>不同的name:
import React from 'react';
import { Text, View } from 'react-native';
const Cat = (props) => {
return (
<View>
<Text>Hello, I am {props.name}!</Text>
</View>
);
}
const Cafe = () => {
return (
<View>
<Cat name="Maru" />
<Cat name="Jellylorum" />
<Cat name="Spot" />
</View>
);
}
export default Cafe;
或者给一个Image组件传递source属性:
<Image
source={{uri: "https://reactnative.dev/docs/assets/p_cat1.png"}}
style={{width: 200, height: 200}}
/>
在JSX中引用JS值时需要使用{}括起来
state
state是组件的私人数据,不能暴露给外部组件使用。它用于记录那些随时间或者用户交互而变化的数据。
import React, { useState } from "react";
import { Button, Text, View } from "react-native";
const Cat = (props) => {
const [isHungry, setIsHungry] = useState(true);
return (
<View>
<Text>
I am {props.name}, and I am {isHungry ? "hungry" : "full"}!
</Text>
<Button
onPress={() => {
setIsHungry(false);
}}
disabled={!isHungry}
title={isHungry ? "Pour me some milk, please!" : "Thank you!"}
/>
</View>
);
}
const Cafe = () => {
return (
<>
<Cat name="Munkustrap" />
<Cat name="Spot" />
</>
);
}
export default Cafe;
开发环境搭建
搭建RN环境需要的依赖有:Node、Watchman、Xcode 和 CocoaPods
JS代码的开发推荐使用VS Code这个编辑器
Node&Watchman的安装推荐使用Homebrew命令安装
brew install node
brew install watchman
Xcode&cocoapods 如果你是iOS开发者,这两个你应该很熟悉了。
当开发环境搭建好后,我们尝试将框架集成到现有原生应用中。
1、配置项目目录结构
首先创建一个空目录用于存放 React Native 项目,然后在其中创建一个/ios子目录,把你现有的 iOS 项目拷贝到/ios子目录中。
2、安装 JavaScript 依赖包
在项目根目录下创建一个名为package.json的空文本文件,然后填入以下内容:
{
"name": "MyReactNativeApp",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "yarn react-native start"
}
}
接下来我们使用 yarn 或 npm(两者都是 node 的包管理器)来安装 React 和 React Native 模块。请打开一个终端/命令提示行,进入到项目目录中(即包含有 package.json 文件的目录),然后运行下列命令来安装:
$ yarn add react-native
$ yarn add react@version_printed_above
所有 JavaScript 依赖模块都会被安装到项目根目录下的node_modules/目录中(这个目录我们原则上不复制、不移动、不修改、不上传,随用随装)。
把node_modules/目录记录到.gitignore文件中(即不上传到版本控制系统,只保留在本地)。
把React Native添加到你的应用中
首先配置pod文件
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
platform :ios, '10.0'
target 'SwiftTest' do
# Comment the next line if you don't want to use dynamic frameworks
config = use_native_modules!
use_react_native!(:path => config["reactNativePath"])
# Pods for SwiftTest
target 'SwiftTestTests' do
inherit! :search_paths
# Pods for testing
end
use_flipper!
post_install do |installer|
flipper_post_install(installer)
end
target 'SwiftTestUITests' do
# Pods for testing
end
end
可以用npx react-native init 项目名命令创建一个纯 RN 项目,然后去参考其 ios 目录中的 Podfile 文件
代码集成
1、创建一个index.js文件
index.js是 React Native 应用在 iOS 上的入口文件。而且它是不可或缺的!
2、添加React Native代码
import React from "react";
import { AppRegistry, StyleSheet, Text, View } from "react-native";
class RNHighScores extends React.Component {
render() {
var contents = this.props["scores"].map((score) => (
<Text key={score.name}>
{score.name}:{score.value}
{"\n"}
</Text>
));
return (
<View style={styles.container}>
<Text style={styles.highScoresTitle}>2048 High Scores!</Text>
<Text style={styles.scores}>{contents}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#FFFFFF",
},
highScoresTitle: {
fontSize: 20,
textAlign: "center",
margin: 10,
},
scores: {
textAlign: "center",
color: "#333333",
marginBottom: 5,
},
});
// 整体js模块的名称
AppRegistry.registerComponent("RNHighScores", () => RNHighScores);
3、在原生项目中添加代码,使用RCTRootView将JS组建导入
首先导入React库, import React
@IBAction func highScoreButtonTapped(sender : UIButton) {
NSLog("Hello")
let jsCodeLocation = URL(string: "http://localhost:8081/index.bundle?platform=ios")
let mockData:NSDictionary = ["scores":
[
["name":"Alex", "value":"42"],
["name":"Joel", "value":"10"]
]
]
let rootView = RCTRootView(
bundleURL: jsCodeLocation,
moduleName: "RNHighScores",
initialProperties: mockData as [NSObject : AnyObject],
launchOptions: nil
)
let vc = UIViewController()
vc.view = rootView
self.present(vc, animated: true, completion: nil)
}
当项目写好后,我们需要启动开发服务器(即 Metro,它负责实时监测 js 文件的变动并实时打包,输出给客户端运行),进入项目根目录,运行:
$ npm start
最后在Xcode中运行项目,就可以开始进行测试了。
参考链接:https://reactnative.dev/docs/getting-started
Demo: https://github.com/JianBinWu/ReactNativePractice