React Native
1. 开发环境 &&工作流程
将帮助您安装和构建您的第一个React Native应用程序。
如果您不熟悉移动开发,
最简单的入门方法是使用Expo CLI。Expo是围绕React Native构建的一组工具,尽管它具有许多功能,但现在对我们而言最相关的功能是,它可以让您在几分钟内编写React Native应用。您只需要使用最新版本的Node.js以及电话或仿真器。如果您想在安装任何工具之前直接在Web浏览器中试用React Native,可以尝试Snack。
expo init AwesomeProject && cd AwesomeProject && npm start
如果您已经熟悉移动开发,
则可能要使用React Native CLI。它需要Xcode或Android Studio才能开始。如果您已经安装了这些工具之一,则应该可以在几分钟内启动并运行。如果尚未安装,则应该花费大约一个小时来安装和配置它们。
brew install node && brew install watchman && sudo gem install cocoapods && npx react-native init AwesomeProject --version X.XX.X && cd AwesomeProject && npx react-native start
调试---关于Xcode手势和键盘快捷键
进入应用内开发者菜单 ---关于模拟器的键盘快捷键
您可以通过摇动设备或通过在iOS Simulator的“硬件”菜单中选择“摇动手势”来访问开发人员菜单。或者⌘D 打开。或者,对于Android,您可以运行命令adb shell input keyevent 82 以打开开发菜单(82是菜单键代码)。
编写可测试的代码
参考链接:
- React testing overview
- react-native-testing-library
- @testing-library/react-native`
- Jest docs
- Detox
- Appium
要开始测试,您首先需要编写可测试的代码。
考虑一下飞机的制造过程-在任何模型首次起飞以证明其所有复杂系统都能很好地协同工作之前,必须对各个零件进行测试以确保其安全性和正常运行。例如,机翼通过在极端载荷下弯曲来进行测试;发动机零件经过了耐用性测试;对挡风玻璃进行了模拟鸟类撞击测试。
软件是相似的。无需将您的整个程序编写在一个包含多行代码的大文件中,而是将您的代码编写在多个小模块中,与测试组装好的整体相比,您可以进行更彻底的测试。这样,编写可测试的代码与编写干净的模块化代码是交织在一起的。
为了使您的应用程序更具可测试性,请首先将应用程序的视图部分(即React组件)与业务逻辑和应用程序状态分开(无论您是否使用Redux,MobX或其他解决方案)。这样,您就可以保持业务逻辑测试(不应依赖于React组件)独立于组件本身,而组件的工作主要是渲染应用程序的UI!
从理论上讲,您可以将所有逻辑和数据提取移出组件。这样,您的组件将完全专用于渲染。您的状态将完全独立于您的组件。您的应用程序逻辑完全不需要任何React组件!
我们鼓励您在其他学习资源中进一步探讨可测试性编码的主题。
- 写作测试
结构测试 :您的测试应该简短,理想情况下只能测试一件事。让我们从用Jest编写的示例单元测试开始:
作为开发人员,我们希望代码能够正常运行并且不会崩溃。
对于测试,通常是相反的。将失败的测试视为一件好事!当测试失败时,通常意味着不正确。这使您有机会在问题影响用户之前解决问题。
语法:it(name, fn, timeout)
it('given a date in the past, colorForDueDate() returns red', () => {
expect(colorForDueDate('2000-10-20')).toBe('red');
});
通过传递给it函数的字符串来描述测试。请谨慎编写说明,以便清楚地测试了什么。尽力涵盖以下内容:
1, Given 给定 -一些前提
2, When 何时 -您要测试的功能执行的某些操作
3, Then 然后 -预期结果
-
单元测试
单元测试涵盖了代码的最小部分,例如单个函数或类。
单元测试的伟大之处在于它们可以快速编写和运行。因此,在工作时,您会快速获得有关测试是否通过的反馈。Jest甚至可以选择连续运行与您正在编辑的代码相关的测试:监视模式。
Jest 支持从功能级别到模块级别的模拟。 -
集成测试
在编写较大的软件系统时,需要单独进行交互。在单元测试中,如果您的单元依赖于另一个单元,您有时会嘲笑该依赖关系,将其替换为伪造的依赖关系。
很多时候我们无法分清楚集成测试与单元测试的区别。如果满足以下条件,则您的测试将属于“集成测试”:- 使用外部系统(例如气象服务API)
- 拨打网络至其他应用程序
- 是否进行任何类型的文件或数据库I / O
-
组件测试
React组件负责渲染您的应用,用户将直接与其输出进行交互。即使您的应用程序的业务逻辑具有很高的测试覆盖率并且是正确的,但是如果没有组件测试,您仍然可能会向用户交付损坏的UI。组件测试可以分为单元测试和集成测试,但是由于它们是React Native的核心部分,因此我们将分别进行介绍。
组件测试只是在Node.js环境中运行的JavaScript测试。他们没有考虑任何支持React Native组件的iOS,Android或其他平台代码。因此,他们不能给您100%的信心,一切都对用户有效。如果iOS或Android代码中有错误,他们将找不到它。
- 测试用户互动
除了呈现一些UI外,您的组件还处理诸如onChangeTextfor TextInput或onPressfor 事件Button。它们可能还包含其他函数和事件回调。考虑以下示例:
- 测试用户互动
function GroceryShoppingList() {
const [groceryItem, setGroceryItem] = useState('');
const [items, setItems] = useState([]);
const addNewItemToShoppingList = useCallback(() => {
setItems([groceryItem, ...items]);
setGroceryItem('');
}, [groceryItem, items]);
return (
<>
<TextInput
value={groceryItem}
placeholder="Enter grocery item"
onChangeText={(text) => setGroceryItem(text)}
/>
<Button
title="Add the item to list"
onPress={addNewItemToShoppingList}
/>
{items.map((item) => (
<Text key={item}>{item}</Text>
))}
</>
);
}
根据经验,最好使用用户可以看到或听到的东西:
- 使用呈现的文本或辅助功能助手进行断言
React类组件尤其易于测试其实现细节,例如内部状态,道具或事件处理程序。为了避免测试实现细节,最好将功能组件与Hooks一起使用,这会使对组件内部的依赖更加困难。
- 测试渲染输出
快照测试是Jest支持的一种高级测试。这是一个非常强大且低级的工具,因此在使用它时建议特别注意。
“组件快照”是由Jest中内置的自定义React序列化程序创建的类似于JSX的字符串。这个序列化器使Jest可以将React组件树转换为人类可读的字符串。换句话说,组件快照是在测试运行期间生成的组件渲染输出的文本表示。它可能看起来像这样:
<Text
style={
Object {
"fontSize": 20,
"textAlign": "center",
}
}>
Welcome to React Native!
</Text>
快照有几个弱点:
1,对于开发人员或审阅者来说,很难确定快照是有意更改还是有缺陷的证据。特别是大快照可能会很快变得难以理解,其附加值也会降低。
2,创建快照时,即使在渲染输出实际错误的情况下,也被认为是正确的。
3,当快照失败时,很容易使用--updateSnapshotjest选项更新快照,而没有采取适当的措施调查是否需要更改。因此,需要某些开发人员纪律。
我们建议您仅使用小型快照(请参阅no-large-snapshots
rule)。如果要测试两个React组件状态之间的_变化_,请使用snapshot-diff
。如有疑问,请按照上一段所述明确要求。
- 端到端测试
有多种E2E测试工具可用:在React Native社区中,Detox是一个流行的框架,因为它是为React Native应用程序量身定制的。在iOS和Android应用程序领域中,另一个受欢迎的库是Appium。
2. 设计 && 交互
-
样式
使用React Native,您可以使用JavaScript设置应用程序样式。所有核心组件均接受名为 style 。样式名称和值通常与CSS在网络上的工作方式匹配,除了名称使用驼峰式大小写(例如)backgroundColor而不是background-color。
style prop 可以是普通的旧JavaScript对象。 这就是我们通常用于示例代码的内容。您还可以传递样式数组-数组中的最后一个样式具有优先级,因此您可以使用它来继承样式。如: <Text style={[styles.red, styles.bigBlue]}>red, then bigBlue
自定义文字样式的方法有很多。查看文本组件参考以获取完整列表。
现在,您可以使文字漂亮。成为样式大师的下一步是学习如何控制组件大小。 -
高度和宽度
固定尺寸: React Native中的所有尺寸都是无单位的,并且代表与密度无关的像素。 <View style={{ 150, height: 150, backgroundColor: 'steelblue'}} />
弹性尺寸: flex 以组件样式使用,以使组件根据可用空间动态扩展和收缩。通常,您将使用flex: 1,告诉组件填充所有可用空间,并与同一父组件在其他组件之间平均共享。flex给定值越大,组件与其同级组件所占的空间比例就越高。
<View style={{flex: 1, backgroundColor: 'powderblue'}} />
<View style={{flex: 2, backgroundColor: 'skyblue'}} />
<View style={{flex: 3, backgroundColor: 'steelblue'}} />
-
使用Flexbox进行布局
组件可以使用Flexbox算法指定其子代的布局。Flexbox旨在在不同的屏幕尺寸上提供一致的布局。
您通常使用的组合flexDirection,alignItems以及justifyContent实现正确的布局。
除了一些例外,Flexbox在React Native中的工作方式与Web CSS中的工作方式相同。默认设置不同,flexDirection默认设置为column而不是row,并且flex参数仅支持单个数字。
以下用实例学习使用:
Flex
将定义您的商品如何沿主轴的可用空间“填充”。空间将根据每个元素的flex属性进行划分。
- Flex
- Flex Direction
- Layout Direction
- Justify Content
- Align Items
- Align Self
- Align Content
- Flex Wrap
- Flex Basis, Grow, and Shrink
- Width and Height
- Absolute & Relative Layout
- Going Deeper
Flex Direction
row从左到右对齐子级。如果启用了自动换行,则下一行将从容器左侧的第一项开始。
column(默认值)从上到下对齐子级。如果启用了环绕,则下一行将从容器顶部第一项的右侧开始。
row-reverse从右向左对齐子级。如果启用了换行,则下一行将从容器右侧的第一项开始。
column-reverse从下到上对齐子级。如果启用了换行,则下一行将从容器底部第一个项目的右侧开始。
<View style={{flex: 1, flexDirection: 'row'}}>
<View style={{ 50, height: 50, backgroundColor: 'powderblue'}} />
<View style={{ 50, height: 50, backgroundColor: 'skyblue'}} />
<View style={{ 50, height: 50, backgroundColor: 'steelblue'}} />
</View>
);
<Image source={require('./img/check.png')} />
- |
- 静态非图像资源
上述require
语法还可用于在项目中静态包含音频,视频或文档文件。最常见的文件类型的支持,包括.mp3
,.wav
,.mp4
,.mov
,.html
和.pdf
。有关完整列表,请参见捆绑程序默认值。
您可以通过在Metro配置中添加一个assetExts
resolver选项来添加对其他类型的支持。
需要注意的是,视频必须使用绝对定位而不是flexGrow
,因为当前没有为非图像资产传递尺寸信息。直接链接到Xcode或Android的Assets文件夹的视频不存在此限制。 - 混合应用程序资源中的图像
- 静态非图像资源
IOS:
<Image
source={{ uri: 'app_icon' }}
style={{ 40, height: 40 }}
/>
Android:
<Image
source={{ uri: 'asset:/app_icon.png' }}
style={{ 40, height: 40 }}
/>
- |
- 网络影像
您将在应用程序中显示的许多图像在编译时不可用,或者您希望动态加载一些图像以减小二进制大小。与静态资源不同,您将需要手动指定图像的尺寸。强烈建议您也使用https,以满足iOS上的App Transport Security要求。
- 网络影像
// GOOD
<Image source={{uri: 'https://reactjs.org/logo-og.png'}} style={{ 400, height: 400}} />
// BAD
<Image source={{uri: 'https://reactjs.org/logo-og.png'}} />
-
|
<Image
source={{
uri: 'https://reactjs.org/logo-og.png',
method: 'POST',
headers: {
Pragma: 'no-cache'
},
body: 'Your Body goes here'
}}
style={{ 400, height: 400 }}
/>
- |
- Uri 数据图像
有时,您可能会从REST API调用中获取编码的图像数据。您可以使用'data:'uri方案来使用这些图像。与网络资源相同,您将需要手动指定图像的尺寸。
建议仅将其用于非常小的动态图像,例如数据库列表中的图标。
- Uri 数据图像
<Image
style={{
51,
height: 51,
resizeMode: 'contain'
}}
source={{
uri:
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADMAAAAzCAYAAAA6oTAqAAAAEXRFWHRTb2Z0d2FyZQBwbmdjcnVzaEB1SfMAAABQSURBVGje7dSxCQBACARB+2/ab8BEeQNhFi6WSYzYLYudDQYGBgYGBgYGBgYGBgYGBgZmcvDqYGBgmhivGQYGBgYGBgYGBgYGBgYGBgbmQw+P/eMrC5UTVAAAAABJRU5ErkJggg=='
}}
/>
-
|
- 缓存控制(仅限iOS)
- 本地文件系统映像
- 最佳相机胶卷图像
- 为什么不自动调整所有大小?
- 源作为对象
- 嵌套背景图片
熟悉Web的开发人员通常要求的功能是background-image
。要处理此用例,您可以使用<ImageBackground>
具有与道具相同的道具的组件,<Image>
并向其中添加您想在其上分层的任何子级。
<ImageBackground>
在某些情况下,由于实施是基本的,因此您可能不想使用。请参阅<ImageBackground>
的文档以获取更多信息,并在需要时创建自己的自定义组件。
return (
<ImageBackground source={...} style={{ '100%', height: '100%'}}>
<Text>Inside</Text>
</ImageBackground>
);
3. 性能 && 链接安全
4. JavaScript Runtime
5. 基础
从高级iOS开发人员到React初学者,再到职业生涯中首次开始编程的人。这些文档是为所有学习者编写的,无论他们的经验水平或背景如何。
学习前,请确定已经熟悉 React? |
要使用React Native,您需要了解JavaScript基础。可以通过 入门 或者 复习来学习Javascript .
Expo Snack 可以在线的运行 reactnative 项目在浏览器;
5.1.功能组件和类组件
使用React,您可以使用类或函数来制作组件。最初,类组件是唯一可以具有状态的组件。但是自从引入React的Hooks API以来,可以向功能组件添加状态和更多内容。
由于Hooks是编写React组件的面向未来的方式,因此下面 我们使用功能组件示例编写了此简介:
import React from 'react';
import { Text, View } from 'react-native';
export default function HelloWorldApp() {
return (
<View style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}}>
<Text>Hello, world!</Text>
</View>
);
}
5.1.1.Core Components and Native Components
在Android和iOS开发中,视图是UI的基本组成部分:屏幕上的一个小矩形元素,可用于显示文本,图像或响应用户输入。甚至应用程序的最小视觉元素(例如一行文本或一个按钮)也都是各种视图。某些类型的视图可以包含其他视图。
- 本机组件
在Android开发中,您可以使用Kotlin或Java编写视图;在iOS开发中,您使用Swift或Objective-C。使用React Native,您可以使用React组件通过JavaScript调用这些视图。 - ``核心组件
React Native具有许多核心组件,从表单控件到活动指示器,应有尽有。您可以在I部分找到找到所有记录的文档。您将主要使用以下核心组件
由于React Native使用与React组件相同的API结构,因此您需要了解React组件API才能上手。
5.2.React 基础
- components
功能组件
import React from 'react';
import { Text } from 'react-native';
export default function Cat() {
return (
<Text>Hello, I am your cat!</Text>
);
}
类组件
import React, { Component } from 'react';
import { Text } from 'react-native';
export default class Cat extends Component {
render() {
return (
<Text>Hello, I am your cat!</Text>
);
}
}
定制组件
import React from 'react';
import { Text, TextInput, View } from 'react-native';
export default function Cat() {
return (
<View>
<Text>Hello, I am...</Text>
<TextInput
style={{
height: 40,
borderColor: 'gray',
borderWidth: 1
}}
defaultValue="Name me!"
/>
</View>
);
}
- JSX
React文档提供了有关JSX的全面指南 - props
props 是“属性”的缩写。props 可让您自定义React组件。
import React from 'react';
import { Text, View } from 'react-native';
function Cat(props) {
return (
<View>
<Text>Hello, I am {props.name}!</Text>
</View>
);
}
export default function Cafe() {
return (
<View>
<Cat name="Maru" />
<Cat name="Jellylorum" />
<Cat name="Spot" />
</View>
);
}
- state
虽然您可以将props作为用于配置组件呈现方式的参数,但状态就像组件的个人数据存储一样。状态对于处理随时间变化或来自用户交互的数据。
import React, { Component } from "react";
import { Button, Text, View } from "react-native";
export class Cat extends Component {
state = { isHungry: true };
render(props) {
return (
<View>
<Text>
I am {this.props.name}, and I am
{this.state.isHungry ? " hungry" : " full"}!
</Text>
<Button
onPress={() => {
this.setState({ isHungry: false });
}}
disabled={!this.state.isHungry}
title={
this.state.isHungry ? "Pour me some milk, please!" : "Thank you!"
}
/>
</View>
);
}
}
export default class Cafe extends Component {
render() {
return (
<>
<Cat name="Munkustrap" />
<Cat name="Spot" />
</>
);
}
}
- 处理文字输入
<TextInput > 通过键盘将文本输入到应用程序的基本组件。 - 使用ScrollView
<ScrollView>是一个通用的滚动容器,可以包含多个组件和视图。可滚动项不必是同质的,您可以垂直和水平滚动(通过设置horizontal属性)。 - 使用列表视图
<FlatList>用于渲染基本的平面列表。
<SectionList>呈现分段列表的高性能界面。 - 故障排除
GitHub中搜索问题 如果遇到此处未列出的问题,请尝试在GitHub中搜索问题。
您可以使用以下port参数将捆绑程序配置为使用8081以外的端口:
npx react-native start --port=8088 - 平台特定代码
在构建跨平台应用程序时,您将希望重复使用尽可能多的代码。可能会出现使代码有所不同的场景,例如,您可能想为Android和iOS实现单独的可视组件。
React Native提供了两种方法来组织代码并按平台将其分开:
使用Platform模块。
import { Platform, StyleSheet } from 'react-native';
const styles = StyleSheet.create({
height: Platform.OS === 'ios' ? 200 : 100
});
使用平台特定的文件扩展名。
当特定于平台的代码更加复杂时,应考虑将代码拆分为单独的文件。React Native将检测文件的扩展名为.ios.或,.android.并在需要时从其他组件加载相关平台文件。
BigButton.ios.js
BigButton.android.js
import BigButton from './BigButton';
6. Native Components and Modules
本机模块
本机模块通常以npm软件包的形式分发,除了在常规Javascript之上,它们将在每个平台上包含一些本机代码。要了解有关npm软件包的更多信息,您可能会发现本指南很有用。
为了设置本机模块的基本项目结构,我们将使用第三方工具create-react-native-module。您可以继续前进并深入研究该库的工作方式,对于我们的需求,我们只需要:
$ yarn global add create-react-native-module
$ create-react-native-module MyLibrary
$ cd MyLibrary
$ $ yarn install
完成此操作后,您可以转到您的主要react app文件夹(通过创建该文件夹npx react-native init MyApp)
- 将新创建的模块作为依赖项添加到package.json中
- 运行yarn install以将其从本地npm存储库中带出。
完成本地模块。
直接操纵
有时有必要直接对组件进行更改,而无需使用状态/属性来触发整个子树的重新渲染。例如,在浏览器中使用React时,有时需要直接修改DOM节点,移动应用程序中的视图也是如此。setNativeProps是React Native,等效于直接在DOM节点上设置属性。
频繁重新渲染会产生性能瓶颈时,请使用setNativeProps
- setNativeProps with TouchableOpacity
- Composite components and setNativeProps
- setNativeProps to clear TextInput value
- Avoiding conflicts with the render function
- setNativeProps & shouldComponentUpdate
- Other native methods
7,更多或问题
7.1,报错 Unable to load script.
错误内容:
Unable to load script.Make sure you're either running a metro server(run 'react-native start' ) or that your bundle 'index.android.bundle' is packaged correctly for release.
根目录执行:
mkdir -vp android/app/src/main/assets && cp index.js index.android.js && react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res && yarn android
或者另外的方法是:
修改 项目目录/android/app/build.gradle里,设置bundleInDebug等于true,使得开发时也会打包index.android.bundle。