Galio-快速移动应用开发-一-

59 阅读1小时+

Galio 快速移动应用开发(一)

原文:zh.annas-archive.org/md5/f91209cf76a6d03c176d458f709fab87

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

本书是 Galio 移动应用程序开发的权威指南,向您展示如何为自己的想法设置 React Native 项目。通过基本概念的逐步解释和实际示例,本书帮助您了解 React Native 的基础知识以及 Galio 的工作原理。

本书适合对象

本书适合希望学习新技能或构建个人移动应用程序的开发人员。任何试图改变工作的人以及初学者和中级 Web 开发人员也会发现本书很有用。需要基本的 CSS、HTML 和 JavaScript 的理解才能充分利用本书。

本书涵盖内容

第一章中,“React Native 和 Galio 简介”,您将了解 React Native 的强大之处。将简单介绍 React Native 是什么,以及您将发现 Galio 的作用以及它如何节省您的时间和压力。

第二章中,“React Native 基础”,您将了解 React Native 的基本概念,如 JSX 和这个框架提供的基本组件。您还将了解有关应用程序的正确目录结构以及如何充分利用它的更多信息。

第三章中,“正确的心态”,涉及任何用户在使用 React 时应该如何看待。这将帮助您养成一些开发移动应用程序和软件的良好习惯。它还作为基础知识和实际创建您的第一个跨平台移动应用程序之间的过渡。

第四章中,“你的第一个跨平台应用程序”,您将学习如何通过实际示例创建您的第一个跨平台应用程序。本章旨在作为打包、如何使用npm以及为什么需要 Galio 的介绍。

第五章中,“为什么选择 Galio?”,我们将介绍 Galio 的优势,它如何帮助您,以及如何与社区联系和帮助可以使您受益。这将激励您成为开源社区的积极成员,并更多了解 React Native。

第六章移动 UI 构建基础,帮助你理解构建应用基本但美观 UI 的基础知识。你可能已经厌倦了丑陋的应用,如果有机会,你会想要创造出美丽的东西。这一章就是关于你如何做到这一点的。

第七章探索我们应用的状态,你将看到组件是如何并排运行的,并理解如何、为什么以及在哪里使用 Galio 组件。这样做将帮助你培养自己的批判性思维方式。

第八章创建你自己的自定义组件,将教你如何基于 Galio 构建你自己的组件。你将发现如何将那些已经存在的美丽组件组合成你在应用中需要的组件。

第九章调试和寻求帮助,将教你如何调试你自己的应用,并在需要时寻求帮助。

第十章构建引导屏幕,你将开始创建 React Native 应用;我选择了引导屏幕,因为通常这是你打开应用时看到的第一个屏幕。

第十一章让我们构建-秒表应用,你将学会如何结合你的第一个屏幕,并使用 React Navigation 来连接它与秒表屏幕。这个屏幕会更加困难一些,因为它有一个真实的使用案例,但这将使事情更有回报。

第十二章接下来做什么?,在这里你将学到更多关于 React Native、Galio,以及如何转变自己成为一个出色和成功的移动开发者。

为了充分利用本书

我假设你已经具备 HTML、CSS 和 JavaScript 的初学者水平知识。有一些 React 的经验肯定是一个优势,但并非必需。你需要一台安装了最新软件的 Windows/Mac 电脑。

如果您使用的是本书的数字版本,我们建议您自己输入代码或从书的 GitHub 存储库中访问代码(链接在下一节中提供)。这样做将有助于避免与复制和粘贴代码相关的任何潜在错误。

阅读完本书后,我希望你尝试重新完成书中的所有挑战,而不查看任何代码,同时为每个练习增添自己的个人风格。

下载示例代码文件

您可以从 GitHub 上的github.com/PacktPublishing/Lightning-Fast-Mobile-App-Development-with-Galio下载本书的示例代码文件。如果代码有更新,将在 GitHub 存储库中更新。

我们还提供了来自我们丰富书籍和视频目录的其他代码包,可在github.com/PacktPublishing/上找到。去看看吧!

下载彩色图像

我们还提供了一个 PDF 文件,其中包含本书中使用的屏幕截图和图表的彩色图像。您可以在这里下载:static.packtcdn.com/downloads/9781801073165_ColorImages.pdf

使用的约定

本书中使用了许多文本约定。

文本中的代码:表示文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 句柄。例如:"现在,对于第二行,让我们进入我们的styles.row2对象并添加填充。"

代码块设置如下:

const styles = theme => StyleSheet.create({
  container: {
    flex: 1,	
    backgroundColor: theme.COLORS.FACEBOOK
  }
});

任何命令行输入或输出都以以下方式编写:

npm i galio-framework

粗体:表示一个新术语、重要单词或屏幕上看到的单词。例如,菜单或对话框中的单词以粗体显示。例如:"在记录下您的用户名和密码后,您应该收到以下响应:成功。您现在以 YOUR-USERNAME 登录。"

提示或重要说明

显示如下。

第一章:介绍 React Native 和 Galio

让我们首先了解本书的内容以及它如何帮助您学习如何使用 React Native 和 Galio。通过阅读本书,您将了解如何在 macOS 和 Windows 上安装 React Native 以及所有必要的工具。然后,您将了解如何创建一个 Expo 项目以及为什么我们使用 Expo,模板工作流之间的区别以及它们如何方便,以及如何在物理设备和模拟器上启动新项目。事情应该非常容易跟随,所以您可能会发现这种体验是有益的。

了解跨平台移动编程的世界并不容易,但肯定是可行的。购买这本书是您迈出的第一步,第二步正在进行中,因为您正在阅读本书,了解 React Native 的工作原理以及 Galio 如何帮助您更快地构建应用。本书的主要目的是让您熟悉 React Native 的工作原理,如何在项目中使用它,以及 Galio 如何方便并可能节省大量时间。

我能理解一开始这可能不是一项容易的任务,但我强烈建议您尽可能多地查看每个部分。如果有一些东西一开始可能不太容易理解,您可以在 Stack Overflow 或不同的 subreddits 等地方提问。我们将在本书的后面深入了解寻求帮助的地方。

起初,大多数程序员,包括我自己在内,都认为跨平台移动编程框架可能比本地框架慢得多。这只是一种想法,因为我们将看到 React Native 是创建移动应用的一种非常好的方式,因为它们与本地应用相比并不慢。

很快您就会明白,这本书与 Galio 紧密相连,我认为 Galio 是最好看的 UI 库之一。Galio 将帮助我们更快地构建 React Native 应用,并且比我们自己能做的更有风格。

您还将学习许多开发自己 UI 的方法,以及在开发应用程序时如何开始跳出思维定式。这很重要,因为这可能是成功应用和失败应用之间的区别。

学习设计和编程的基本规则只是成为一个完整的前端开发人员过程中的第一步。学会如何打破这些规则将进一步发展你的技能。

有时,会有提示出现在最需要的地方,遵循这些提示将有利于任何试图进入程序员思维的人。

在本书的结尾,你会找到练习和许多关于如何为你的移动应用程序开发更复杂的 UI 的提示。所有这些都有一个很好的目的,那就是在拥有一个良好的基础的同时发展编程风格。

我坚信在读完本书之后,任何人都应该能够创建至少一个基本的跨平台移动应用程序,这将作为个人项目的一个很好的 MVP。学习和体验本书中所写的所有内容不仅对你作为学习使用 React Native 和 Galio 的人很重要,对你作为一个程序员也很重要。

本章将涵盖以下主题:

  • 为什么选择 React Native?

  • Galio - 最好的 UI 替代品

  • 配置你的 React Native 环境

  • 创建你的第一个 React Native 项目

为什么选择 React Native?

所以,你可能会想,“为什么选择 React Native?”。市面上有很多跨平台框架,比如 Flutter、Xamarin 和 Cordava 等,所以我们需要了解为什么 React Native 是移动应用程序开发的一个很好的选择。

你需要明白,没有绝对正确的选择。这只是基于当前市场环境和个人欣赏。

编程框架就像画家的画笔。画家有多种画笔,每一种都有不同的用途。你需要尽可能多地了解你正在使用的工具,因为画家对画笔了解得越多,他们就能越好地绘画并将他们的愿景变为现实。

你需要学会如何使用 React Native 快速轻松地开发跨平台应用程序。所以,让我们更深入地了解为什么 React Native 是开发应用程序的一个很好的选择。

你只需要学习一次

首先,React Native 是基于 React 的,这意味着你只需要学习一次,就可以在任何地方开发。这是扩展你技能的一个非常好的方式。通过学习 React Native,你将准备好为你的网站编写 React 代码。

这应该让您很容易理解为什么这是一个如此好的选择。想象一下,您已经创建了一个应用程序。您的应用程序很酷 - 人们开始从 App Store 或 Google Play 下载它 - 但更有帮助的是一个落地页。因为您已经学会了 React Native,利用您的 React 技能将变得轻而易举。

更大的人才储备

在早期的编程时代,当您有一个应用程序想法并想要开发它时,您必须寻找具有一些 C#或 Java 技能的后端开发人员,具有 Objective-C 技能的 iOS 开发人员,必须了解 Java 的 Android 开发人员,甚至可能还需要一些网页前端开发人员来开发应用程序的网站。

这需要大量的努力和相当大的预算。在项目结束时,您的想法可能在今天的市场上行不通,而您将浪费大量的时间和金钱。

现在,所有这些特定的工作都可以由 JavaScript 工程师来处理 - 我们有多种替代方案来使用与原生框架一样好的 JavaScript 编写的框架,而 JavaScript 是目前最常用的语言之一。市场上甚至有更多的 JavaScript 开发人员,并且从一个框架转移到另一个框架比以往任何时候都更容易。通过雇佣 JavaScript 开发人员,预算减少了一半,应用程序开发速度更快,即使他们有不同的工作,他们也可以互相帮助。

JavaScript 开发人员可以轻松更换团队。后端开发人员可以帮助前端开发人员,甚至移动应用团队。他们可以随时提供帮助,无论您在哪里需要更多的人手来加快开发速度。当您的开发人员因辞职或疾病而缺席时,这一点尤为重要。

拥有更多可供选择的人才对于任何应用程序开发来说都是一个巨大的优势。

React 的流行

你可能会认为 React 的流行与 React Native 无关,但实际上,就编写代码和方法论而言,React 和 React Native 是密切相关的。我的建议是始终关注 Google 趋势,因为它可以帮助我们了解一个框架是否受欢迎:

图 1.1 - Google 趋势显示了 React 目前的流行程度

图 1.1 - Google 趋势显示了 React 目前的流行程度

React 使开发人员能够轻松构建出色的 Web UI,但基于组件的方法也使应用程序更容易维护。React Native 将所有这些优势带到了移动应用程序开发领域。

那么,这给我们展示了什么?有一个相当庞大的 React 搜索社区,而 React Native 拥有一个最大且最活跃的社区之一。对于您可能遇到的几乎每一个小问题,都有人已经在 GitHub 上撰写了文章或为其提出了问题。GitHub 上的社区也非常庞大,这将会很有帮助,因为您可以与更多开发人员联系,寻求关于您可能在应用程序中使用的任何库的帮助,并为您可能拥有的任何开源想法获得更多帮助,这可能会对许多开发人员有所帮助。

我建议每个人都参与开源项目,因为这将有助于发展您的技能,并扩展您作为程序员的思维方式。社区是如此乐于助人和友好,以至于您可能会发现很难转向任何其他框架,因为这似乎是大多数需求的最佳选择。

性能

React Native 在性能方面接近原生应用,但您必须以正确的方式使用它。从技术上讲,您有一个运行缓慢的 JavaScript 线程,与 Android 的 Kotlin 或 iOS 的 Swift 等本地代码相比,速度相当慢。

React Native 的闪光点在于它在 JavaScript 线程和本地线程之间创建了一个桥梁。它旨在将诸如渲染之类的最昂贵和强大的任务移动到本地端。这是异步使用的,因此 JavaScript 线程不必等待本地计算。

假设用户按下按钮-React Native 将把这个转化为 JavaScript 可以处理的事件。之后,通过在本地平台(如 iOS 或 Android)和 JavaScript 代码库之间发送消息,React Native 桥将本地事件转换为 React 组件可以理解和响应的事件。

这里有一些挑战,比如默认组件-这些是 React Native 提供的内置元素-在两个平台上看起来或响应起来并不相同,因为有很多特定于平台的事件。不过不用担心,因为这种桥接架构允许我们使用来自平台、SDK 和 JavaScript 库的所有现有本地视图。

语言

JavaScript 是作为客户端语言创建的。它被设计用来使网站具有交互性。如果你想象一个基本的网站布局,你有你的 HTML,描述基本内容和网站结构,然后你有你的 CSS,为 HTML 添加样式并使其美观。这是一个不做太多事情的静态网站,所以我们需要一种编程语言,可以为我们的网站添加功能并使其生动起来。这就是 JavaScript 进入游戏的地方。

时间过去了,人们意识到他们可以用 JavaScript 做更多的事情。JavaScript 最流行的用途是客户端,但自从 Node.js 出现在编程场景中以来,这种语言已经发展得如此之多,以至于这不再是情况。JavaScript 现在是一种多用途的编程语言,意味着你可以用它来构建几乎任何东西。你甚至可以使用 TypeScript 或 Flow 来获得类型化的 JavaScript。代码编辑器内的支持也变得更好了。

说了这么多,React Native 使用 JavaScript 作为其主要编程语言。随着我们的学习,我们会发现 React Native 也可以使用原生代码来运行得更快,做更好的计算

Stack Overflow(程序员最大的社区之一)每年都会进行一项调查,试图更多地了解开发者和使用他们平台的人。你可以问任何开发者关于他们的平台,几乎任何人都会告诉你他们至少浏览过一次。他们 2020 年的研究显示,几乎 70%的用户是使用 JavaScript 的专业开发者。

作为一种多才多艺的语言,学习它用于 React Native 或其他框架只会帮助你扩展作为程序员的领域。React Native 使用它是一个很大的优势,因为它显示了这样做可以让你在不同技术之间轻松移动。

你可以通过访问insights.stackoverflow.com/survey/2020了解更多关于 Stack Overflow 关于 2020 年调查的统计数据。

得出结论

阅读了关于 React Native 的所有内容之后,我们需要明白,尽管 React Native 并不像原生应用那样快速,但它几乎可以和原生应用一样快。而且,考虑到这种语言对开发者有如此多的机会,以及社区如此强大友好,我们可能会将 React Native 视为跨平台移动应用开发的最佳框架之一。

为了选择适合你需求的库,你需要考虑对你来说最重要的是什么。我希望你对 React Native 有了一些了解,并且对这个框架是一个好选择有信心。

接下来,我们将更多地了解 UI 库是什么,以及 Galio 是如何像一个伟大的助手一样帮助我们编写代码的。

Galio - 最佳 UI 替代品

所以,你已经学会了一些关于 React Native 的工作原理,现在你想知道 Galio 如何帮助你。首先,Galio 到底是什么?

简而言之,Galio 是一个 React Native UI 库,因此它是一组资源,旨在帮助开发人员更快、更容易地编写代码。问题是... React Native 没有那么多组件。我们将在本书的后面回到组件的具体含义,但现在,只需将它们视为拼图块。

React Native 有一定数量的拼图块,每个拼图块尽可能简单。Galio 作为这些拼图块的包装器,添加了一些颜色和功能。有时,甚至可以找到通过将更基本的拼图块组合成一个非常大的拼图块的不同拼图块,出于特定原因。

现在,让我们来看看为什么 Galio 可能是你在跨平台移动开发旅程中最好的 UI 库。

节省时间

好吧,比喻太多了。事实是,React Native 只有基本外观的组件,这使开发人员需要构建自己的组件。这是耗时的,因为你总是需要为你的新应用构建新组件。

这就是 Galio 派上用场的地方!它拥有许多已经美丽的组件,减轻了一直创建自己的痛苦。

此外,所有组件都更容易定制,仍然适合整个设计布局,而不会给开发人员施加太大压力,让他们考虑如何做以及从哪里开始。从 Galio 定制组件的过程很简单,通常围绕着使用 props,这使整个过程更加可读。

我知道像“组件”和“props”这样的词对你来说完全或可能有些陌生,但重要的是它们可以节省你大量的时间。我们很快就会了解更多关于这些关键词,但我们需要了解一些关于所有这些技术在整体方案中意味着什么。

使用 Galio 构建应用通常更多地取决于您选择创建布局的方式,而不是实际编程 UI。它是通过直接放置每个组件在前一个组件下面的方式来创建移动屏幕。这使我们能够更高效,尽可能少地浪费时间编写代码并思考最终屏幕的样子。

以下图表显示了您可以使用我们讨论的拼图块创建的基本程序结构:

图 1.2 - 添加更多组件如何帮助构建移动屏幕的表示

图 1.2 - 添加更多组件如何帮助构建移动屏幕的表示

这是一种很好的思考方式,因为它让您了解了一些最佳的原子设计原则。它还创建了一个更有组织的代码库,您可以将其扩展为更复杂和更完整的应用程序。

这真的很美

Galio 已经预先设计了一个设计系统,这意味着所有组件都将遵循相同的设计原则,因此组件之间永远不会有任何差异。

一致的设计是使应用完整的关键。一致的设计将帮助用户更好地理解您的应用流程,您希望在应用中引入的所有符号以及如何使用它。这一切都与您的按钮、文本和设计保持一致有关。

起初您可能不喜欢颜色,这没关系,因为您可以借助<GalioProvider>轻松更改它们。我们稍后会在本书中讨论这一点。

现在,我们已经了解了为什么 React Native 是一个如此好的选择,以及为什么 Galio 是一个很好的 UI 库,让我们开始构建应用。下一步是了解如何配置一个良好的环境,以便我们可以开始构建跨平台移动应用。

配置您的 React Native 环境

有两件事我们需要了解:ExpoReact Native CLI

它们都很容易安装,我们将介绍它们,以确保我们覆盖所有可能的情况。我建议不要跳过这部分,因为它将帮助您在开始开发移动项目时做出一个好选择。

在 macOS 上安装东西要比在 Windows 上容易得多,因为 macOS 是基于 UNIX 的系统,所以终端更加强大。但不用担心 - 我们也会解决 Windows 上的这个问题。

在我们继续之前,我们必须考虑一些要求。这些将帮助我们为 Expo 和 React Native CLI 以及一般的 JavaScript 编程创建一个良好的环境。

无论是哪个系统,我们都需要安装以下技术:

  • Homebrew - 仅限 macOS

  • Chocolatey - 仅限 Windows

  • Node.js

  • 文本编辑器

  • Android Studio

  • Xcode - 仅限 macOS

我们将从安装 Node.js 开始,这是我们在浏览器之外运行 JavaScript 所需的最重要的技术之一。Node.js 是建立在 Chrome 的 V8 JavaScript 引擎上的,这意味着您可以运行在最新 Chrome 版本(Web 浏览器)上运行的任何 JavaScript 代码。

安装 Node.js 的推荐方式取决于您的操作系统。对于 macOS 用户,最好的方式是使用 Homebrew,而对于 Windows 用户,您将使用 Chocolatey。Homebrew 和 Chocolatey 是包管理器,可以让您更轻松,更快速地安装不同的软件包,如 Node.js,都可以通过命令行或终端进行。您也可以通过官方网站nodejs.org安装它,但是在本书中我们将使用 Homebrew 或 Chocolatey。

Homebrew

对于 macOS,我们有 Homebrew,它很容易安装。您可以在他们的官方网站brew.sh上找到更多信息。

要安装它,您应该打开终端并输入以下命令:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"

在输入命令后,按Enter。将会出现有关即将安装的所有内容的更多信息;只需再次按Enter,您就准备好了。

Chocolatey

对于 Windows,我们有 Chocolatey,它比 Homebrew 更复杂,但是按照这里的步骤,您应该已经准备好了。您可以通过访问它们的官方网站chocolatey.org了解更多关于 Chocolatey 的信息。

首先,我们需要以管理员权限使用 PowerShell。要访问它,您只需在键盘上按Windows 标志+X。一个新菜单将出现在屏幕的左下角。在这里,选择Windows Powershell(管理员)。一个新窗口将打开。

首先,您需要验证Get-ExecutionPolicy是否不受限制,因此在 PowerShell 中写入以下内容:

Get-ExecutionPolicy

如果返回Restricted,那么您需要运行以下命令:

Set-ExecutionPolicyAllSigned

现在,您已经准备好运行以下命令:

Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))

现在,等待几分钟让一切都安装好。如果在安装过程中没有遇到任何错误,只需输入choco即可返回 Chocolatey 版本。如果返回了版本号,那么你就已经准备好了。

现在我们需要做的就是安装 Node.js,这样我们就可以学习 Expo 和 React Native CLI 了。安装了 Homebrew 或 Chocolatey 后,只需输入以下命令,Node.js 就会开始安装:

  • 在 macOS 上使用以下命令:
brew install node
  • 在 Windows 上使用以下命令:
choco install -y nodejs

恭喜!我们现在已经准备好继续前进了!有了这个,我们已经安装了 Node.js。在设置环境之前,让我们讨论一下文本编辑器-我保证不会花太长时间。

我敢打赌你现在在想,“等等,他说我们可以在 Word 文档中写代码吗?”其实不是。Microsoft Word 不是一个纯文本编辑器,但你可以使用诸如 Notepad 之类的东西来写代码。仅仅因为我们可以使用 Notepad 并不意味着我们会使用它;它看起来并不太专业,对吧?

我们将使用的文本编辑器将具有一些很酷的功能,比如代码语法的颜色方案,以及将帮助我们更快更漂亮地编写代码的不同附加组件。

有许多不同的免费文本编辑器,包括 Sublime、Atom、Visual Studio Code、Notepad++和 Brackets。它们都同样优秀,我建议你至少下载两三个来试试。我个人偏好 Visual Studio Code,并且在本书中将一直使用它。如果你不喜欢某个文本编辑器的外观,你不需要使用相同的文本编辑器,因为你可以使用上述任何一个编辑器来跟随本书。

你可以从code.visualstudio.com/下载 Visual Studio Code(或简称 VSCode)。

现在我们已经解决了一些必需品,是时候继续学习 Expo 和 React Native CLI 了。它们都可以用来实现相同的结果-它们只是创建 React Native 应用的不同方式,我们将尽量理解它们。了解它们的一切将帮助我们选择适合我们和我们的应用的正确方式。

React Native CLI

React Native CLI 是创建 React Native 项目的官方和首选方法。通常比 Expo 更难配置,需要更多时间,但是很值得。毕竟,您需要模拟器来测试您的应用在不同手机上的情况。我建议不要跳过这一部分。

macOS

拥有 macOS 的一个好处是您可以模拟 iPhone,并查看您的项目在不同的 Apple 技术上的外观。这是在 Windows 上无法做到的,但 Android 可以在两者上运行,因此 macOS 在能够模拟所有类型的平台方面具有优势。

我们应该开始并安装所有必要的依赖项;打开终端并写入以下内容:

brew install watchman

Watchman 是 Facebook 开发的一个工具,用于监视文件系统内的更改。它还提供更好的性能。

现在,您需要安装 Xcode。前往 Mac App Store,搜索 Xcode,然后点击安装。这也将安装 iOS 模拟器和构建 iOS 应用所需的其他工具。您的 Xcode 版本至少需要是 9.4 才能与 React Native 一起使用。

现在,我们需要安装 Xcode 命令行工具包。一旦 Xcode 下载和安装完成,打开它,然后转到首选项(在导航栏的 Xcode 菜单下; 或者,只需按Cmd + ,)。应该会打开一个新窗口。转到位置,通过从下拉菜单中选择最新版本来安装命令行工具:

![图 1.3 - Xcode 中的首选项窗口

]

图 1.3 - Xcode 中的首选项窗口

现在,转到组件选项卡,并安装您希望使用的最新模拟器。

重要提示

苹果支持的每个 iOS 版本都有一个模拟器。您应该尝试安装最近的两个主要版本,因为您的应用用户可能始终使用较早的 iOS 版本。

现在,您只需要通过在终端中写入以下内容来安装 CocoaPods:

sudo gem install cocoapods

这是一个 Ruby gem,用于管理 Xcode 项目的依赖关系。

有了这些,您就可以在 macOS 上创建您的第一个项目了!我们马上就会做到!

Windows

众所周知,我们无法在 Windows 上安装任何 iOS 模拟器,所以我们不妨只安装 Android 模拟器。

我们已经安装了 Node.js,现在剩下的就是通过转到我们的管理员 PowerShell(我们在安装 Node.js 和 Chocolatey 时解释了如何打开它)来安装 JDK。一旦打开它,写入以下内容:

choco install -y openjdk8

如果您已经安装了 JDK,请确保至少是 v8。

现在,是时候安装我们的 Android 开发环境了,这可能有点乏味。然而,这是值得的,因为我们将能够在虚拟 Android 模拟器上运行我们的 React Native 应用程序。

前往developer.android.com/studio下载 Android Studio。安装完成后,启动 Android Studio。打开后,选择您喜欢的主题和适合您计算机的所有首选项。在某个时候,SDK 组件设置页面将出现。确保已选择了Android SDKAndroid SDK 平台Android 虚拟设备复选框。

安装完成后,是时候继续了。Android Studio 默认安装最新的 Android SDK。然而,使用本地 Android 代码构建 React Native 应用程序需要Android 10 (Q) SDK。要安装它,打开 Android Studio,点击窗口右下角的配置,然后选择SDK Manager

图 1.4 – Android Studio 和按钮的位置

图 1.4 – Android Studio 和按钮的位置

现在,选择SDK 平台选项卡,并在右下角的复选框中选中显示包详细信息。查找并展开 Android 10 (Q),并确保以下内容已被选中:

  • Android SDK 平台 29

  • Intel x86 Atom_64 系统映像或 Google APIs Intel x86 Atom 系统映像

接下来,您应该选择SDK Tools选项卡,并选中显示包详细信息旁边的复选框。查找Android SDK 构建工具,并选择29.0.2

点击应用并下载所有必要的文件。

现在,是时候配置ANDROID_HOME环境变量,以便我们可以使用本地代码。打开控制面板,点击用户帐户,然后再次点击用户帐户。在左侧,您会找到更改我的环境变量;点击它。现在,点击**新建…**并写入以下内容:

  • 变量名ANDROID_HOME

  • 变量值C:\Users\{name}\AppData\Local\Android\Sdk,其中{name}是您的 PC 用户名:

图 1.5 – Windows 显示我的用户变量

图 1.5 – Windows 显示我的用户变量

检查环境变量是否已加载,转到 PowerShell 环境并输入以下内容:

Get-ChildItem -Path Env:\

您应该看到一个列表,其中ANDROID_HOME应该是其中的一部分。

之后,我们需要将platform-tools添加到Path中。我们可以通过转到控制面板,点击用户帐户,然后再次点击用户帐户来实现这一点。点击更改我的环境变量,然后查找Path。选择Path并点击编辑。一个新窗口将出现,我们可以点击新建。现在,使用与之前相同的变量值,但这次进入Sdk文件夹 - 更确切地说是platform-tools文件夹:

C:\Users\{name}\AppData\Local\Android\Sdk\platform-tools

我们现在已经准备好在 Windows 上开始开发 React Native 应用程序了!

Expo

Expo 是初学者开始 React Native 项目的最简单方式。它内置了一套为 React Native 构建的大量工具,但我们现在对此不感兴趣。我们只对 Expo 可以在几分钟内让您上手并且不需要您安装模拟器感兴趣,因此您可以在几分钟内玩转您的应用程序。

他们还推出了一个名为 Snack(snack.expo.io/)的东西,如果您希望直接在浏览器中尝试不同的代码想法,这将非常有帮助!这很酷,因为即使只是想快速草拟一些东西,您甚至都不需要启动一个项目。

让我们安装它,看看这是否像我所说的那样简单。打开终端或命令行并输入以下内容:

npm install -g expo-cli

Expo 现在已经准备就绪!很简单,对吧?

准备进一步前进了吗?

现在我们已经安装了所有必要的技术,我们准备创建自己的 React Native 项目并创建一些很棒的应用程序!

但首先,让我们了解 React Native CLI 和 Expo 之间的区别。之前,我告诉过您不要跳过 React Native CLI 部分,即使它比 Expo 大得多。这是因为我们需要安装 Xcode 或 Android Studio,以便直接从我们的 PC 上控制我们的应用程序。

我们还没有使用 React Native CLI 或 Expo 创建项目,因为它们都是以不同的方式创建的。但是,我们已经安装了它们的要求。使用 React Native CLI 创建项目会让开发人员完全从 0 开始创建应用程序。您对应用程序拥有完全的控制权,没有任何东西能够限制您的想象力。您甚至可以使用本地代码 - Kotlin/Java 用于 Android 或 Swift/Objective-C 用于 iOS - 并创建自己完全本地的组件。不过,这都是非常高级的,我们并不需要它。

Expo 内置了许多工具,适合那些想要创建快速强大的应用程序,而不必费心考虑应用程序如何运行并与特定平台连接的所有细节的人。

因此,我们将使用 Expo 来创建本书中的项目。

创建您的第一个 React Native 项目

我们准备好了!让我们打开一个终端,直接开始吧!

一旦终端打开,只需移动到您的Desktop文件夹或任何您希望在其中创建项目的文件夹。您可以使用cd命令在文件夹之间移动。因此,只需输入cd Desktop,我们就到达了Desktop目录,准备创建我们的 Expo 项目。

我们可以通过以下方式使用 Expo 创建一个新的 React Native 项目:

expo init MyFirstProject

按下Enter键后,Expo 告诉我们可以在多种模板之间进行选择。最大的两个类别是托管工作流程原始工作流程

图 1.6 - 初始化项目后您将看到的表示

图 1.6 - 初始化项目后您将看到的表示

我们将在几秒钟内解释这两者是什么。现在,在托管工作流程下选择空白。等待几秒钟,您将在终端中看到以下消息:

Your project is ready!

现在,我们准备开始了。在终端中输入以下命令;这将把我们移动到我们项目的文件夹中:

cd MyFirstProject

既然我们在这里,让我们了解每种类型的模板是如何工作的,这样我们就可以开始玩我们的第一个 React Native 应用程序了。

托管工作流程

托管工作流程试图处理几乎所有你必须做的复杂操作。这通常适用于完全的初学者,他们不想用 Xcode 或 Android Studio 复杂化事情,这也正是我们开始创建这种类型工作流程的原因。你可以通过 app.json 更改应用的所有信息,比如它的图标或启动画面,并且可以直接、轻松地访问不同的服务,比如推送通知。

然而,这种工作流程也有一些局限性。假设你想使用 Expo SDK 没有通过其 API 提供的特定设备功能。这意味着你需要运行 ejectexpo-cli 将会做所有的工作并将你转移到裸工作流程

裸工作流程

裸工作流程为开发者提供了对应用的完全控制。然而,这也伴随着需要处理关于应用的每一个细节的复杂性。现在,轻松配置 app.json 的能力已经消失,你只剩下安装了 Expo SDK 并且没有进行预配置。

这使你可以使用本地代码并以任何你想要的方式管理你的依赖。你可能会想,“嗯...这不就是使用 React Native CLI 一样吗?”。嗯,其实不是,因为你可以立即访问 Expo SDK 和 Expo 框架,这本身对于开发者来说是一个巨大的优势,因为它仍然简化了你的开发过程。

打开我们的项目文件

现在我们已经了解了每个模板的作用以及为什么选择了托管工作流程,让我们看看代码是什么样子的。

还记得我们讨论过文本编辑器吗?继续打开你选择的文本编辑器。我会使用 VSCode,因为我更喜欢它的设计。

点击文件 | 打开文件夹,然后搜索项目文件夹。我的在桌面文件夹中。打开它让我们看到项目中所有的文件和文件夹。

我很确定你对每个文件的目的感到困惑。我们马上会看一下这个,但现在,花几分钟四处看看,看看你是否可以自己找到一些东西。

提示

调查你找到和创建的任何代码片段是确保你正在学习你所阅读或编码的内容的最佳方式。最优秀的程序员总是那些运用他们的演绎能力的人。

为预览准备我们的物理设备

现在是时候准备我们的手机,这样它就可以预览我们的应用了,因为向朋友展示我们的新技能总是很酷的。

所以,让我们去应用商店或 Google Play 搜索 Expo。安装它,你就准备好了。这个应用程序允许我们在手机上测试我们的应用,所以让我们试一试吧!

去你的终端,如果你还没有在项目文件夹中,就前往那里。输入以下命令:

npm start

之后,按下Enter。一个新窗口应该会在你的默认浏览器中打开。一个服务器已经创建,你的应用现在可以在你的物理设备上或者模拟器上预览了。在侧边栏上,有一个 QR 码,上面有一个链接和一些按钮。这是什么,我们怎样利用它呢?

图 1.7 - 屏幕上显示的所有按钮的预览

图 1.7 - 屏幕上显示的所有按钮的预览

现在,你可以打开你的智能手机,扫描 QR 码或者将 QR 码上方的链接粘贴到浏览器中。一个消息会出现,询问你是否愿意用 Expo 打开链接。按下,你就成功了 - 你的第一个 React Native 应用在你的物理设备上了。

相当酷,对吧?

让我们看看如果我们按下在 Android 设备/模拟器上运行或者在 iOS 模拟器上运行会发生什么。一个消息会出现在右上角,告诉你 Expo 正在尝试打开模拟器。取决于你在哪个操作系统上启动了你的项目,以及你安装了哪个模拟器,选择适当的按钮。

对于 Android 模拟器,你需要先打开 Android Studio。然后,你必须去右上角,那里写着配置,选择AVD Manager。现在,一个新窗口会出现,显示所有可用的虚拟设备。如果你没有看到任何设备,去左下角点击创建虚拟设备

在这一点上,你会看到一个 Android 设备列表。我选择了 Pixel 3a,但如果你的 CPU 不是很强大,你可以选择一个旧的设备。之后,点击下一步;你将被要求选择一个系统镜像。找到推荐旁边的x86 镜像选项卡,并选择不需要下载的镜像,名为Q。如果所有镜像都需要下载,那么你需要回到 Android Studio 安装部分,重复该过程。选择镜像后,点击下一步,并命名 AVD;它可以被称为任何东西,所以要有创意。点击完成;你应该在AVD 管理器列表中看到你的设备。在同一行的右边,你会找到一个看起来像播放符号的小绿色按钮。点击它。

一个新的 Android 模拟器将打开,所以让我们回到浏览器标签,我们的 Expo 服务器正在运行,然后点击在 Android 设备/模拟器上运行。如果你看一下终端,你会看到一些文字出现了。我们只需要等待一会儿,Expo 客户端就会被下载并安装到我们的模拟器上。它应该会显示类似这样的内容:

Downloading the Expo client app [================================================================] 100% 0.0s
Installing Expo client on device
Opening exp://192.168.1.111:19000 on Pixel_3a_API_30_x86

现在,你的 Android 模拟器应该显示你的第一个 React Native 应用的预览。感觉如何?你经历了很多,但最终,能够正确初始化一个项目是相当有回报的:

图 1.8 - Android 模拟器显示一个全新的 React Native 项目

图 1.8 - Android 模拟器显示一个全新的 React Native 项目

在我们继续之前,我认为我们应该学习如何在终端/命令行中关闭一个项目。回到终端窗口,点击它,使其聚焦。现在,如果你按下Ctrl + C,服务器应该停止,你应该能够再次使用终端窗口。

总结

本章以对 React Native 和 Galio 的简要介绍开始,然后我们了解了为什么这些库对你的下一个个人跨平台移动应用项目很有好处的主要焦点。在充分理解为什么学习这些库将帮助它们成为未来的重要资产之后,我们开始设置我们的 React Native 环境,并学习关于测试和利用我们即将创建的移动应用的一切。

我们接着创建并测试了我们的第一个 React Native 应用!对于一个新手来说,进入这个美丽的编程世界确实是一次很棒的旅程,相信我,这一切都是值得的。你在这里学到的一切将作为接下来要学习的基础。这一切都很令人兴奋,不是吗?在下一章中,是时候学习 React Native 代码编写的基础知识,并创建更酷的应用了。

第二章:React Native 基础知识

我们首先学习了为什么 React Native 和 Galio 形成了最佳组合,可以帮助我们开始构建我们的第一个跨平台移动应用程序。在设置环境并配置必要文件后,我们使用 Expo 创建了我们的第一个 React Native 项目,并学习了不同的测试应用程序的方法,包括物理和数字化测试。

我相信在学习如何之前先了解为什么有助于建立更好、更健壮的知识基础。经过了解为什么,现在是时候学习 React Native 的工作原理以及如何使用它来创建我们的应用程序了。

这就是为什么我们将从我们的 React Native 项目的文件结构开始这一章,以便我们了解这些文件和文件夹是如何连接的。然后我们将详细介绍App.js文件,并解释这对我们作为应用程序的主要入口点是如何工作的。

一旦我们了解了文件结构,就是时候学习JSX是什么以及如何使用它了——这是任何 React 应用程序的骨架。我们将经常将 JSX 与 HTML 进行比较,因此您必须事先了解一些 HTML。如果您对 Web 开发了解不多,也不用担心——我们也会介绍一些 HTML 概念,但自己学习一些可能会对您有所帮助。理解 JSX 的概念是我们将处理组件概念的地方,这是我们在第一章中几乎没有涉及的概念。到本章结束时,这应该是完全理解的。

一旦我们了解了 JSX 的主要概念以及它与 React 和 React Native 的关系,我们将进行我们的第一个组件导入。我们将学习 npm/yarn 是什么以及如何使用它来导入和上传组件或库到网络上。这是令人兴奋的,因为您将看到拥有一个庞大的社区支持一个框架的重要性,以及您如何参与并结交新朋友。

现在是时候学习 React Native 的核心组件了。我们将了解它们的用途和上下文,并讨论改进它们或完全更改它们的不同方法。核心组件是我们在网上找到的所有组件的基础组件。这意味着几乎每个组件都继承自核心组件,这使得了解和理解它们非常重要。

在本章结束时,你将学会如何构建一个组件。你还将学会如何在我们的应用程序或未来的应用程序中使用它,以及如何组织文件,这样你就永远不会迷失在寻找你的组件中。

我相信在本章结束时,你将能够开始构建非常简单的应用程序,这些应用程序可以作为构建更大、更复杂项目的基石。理解这些概念并不仅限于阅读本书 - 它会更进一步,你会看到我一直鼓励你查看我们使用的项目/框架的官方文档,因为文档应该始终是程序员应该感到舒适阅读的东西。学会阅读文档是一个你会通过阅读和对你热衷的项目尽可能感兴趣来发展的技能。

本章将涵盖以下主题:

  • 使用App.js - 主入口点

  • 理解 JSX 的概念

  • 导入你的第一个组件

  • 核心组件

  • 理解和创建一个组件

技术要求

你可以通过访问 GitHub 上的github.com/PacktPublishing/Lightning-Fast-Mobile-App-Development-with-Galio来查看本章的代码。你会发现一个名为Chapter 02的文件夹,其中包含我们在本章中编写的所有代码。要使用该项目,请按照README.md文件中的说明进行操作。

使用 App.js - 主入口点

就像我们所知道的,React Native 是一个用于构建 iOS 和 Android 应用程序的开源框架。它使用 React 来描述 UI,同时通过我们可用的方法访问平台的功能。

理解我们的文件夹结构很重要,因为在开发初期我们不应该触碰一些文件。让我们来看看我们新创建的项目结构。

提示

不要忘记你可以使用任何你喜欢的文本编辑器;我只是使用 VSCode 是因为我喜欢它的外观,并且它有很多我使用的插件,但这并不意味着你不能用任何你感觉舒适的文本编辑器打开项目。当然,这意味着你将无法使用code.命令,因为那只能用于 VSCode。

首先,让我们打开我们的终端并导航到我们的文件夹。现在,如果我们到达文件夹后写code.,它将打开 Visual Studio Code。

一旦我们的文本编辑器打开,我们将在项目目录中看到以下输出:

图 2.1 – 打开文本编辑器后的项目目录

图 2.1 – 打开文本编辑器后的项目目录

正如我们所看到的,这里有几个文件夹和文件,它们都旨在在你完成应用程序后帮助捆绑项目。我们将在接下来的几节中查看这些文件夹中的每一个。

.expo 和.expo-shared 文件夹

我们将从带有点的文件夹开始:.expo.expo-shared。点在那里是为了显示一个隐藏文件。这是一个你在打开文件浏览器时无法直接看到的文件;只有在你明确选择查看它时才能看到。这些文件是隐藏的,因为你不需要触碰它们。它们是在你第一次使用expo start命令时创建的配置文件。

资产文件夹

接下来的文件夹是assets文件夹。在里面,你会找到几个.png图像,这些图像是 Expo 用于启动屏幕的 – 应用程序加载时出现的屏幕 – 以及应用程序在设备上安装时使用的图标。

node_modules 文件夹

现在,你会看到一个名为node_modules的文件夹。如果你打开这个文件夹,你会看到很多很多的文件夹。所有这些文件夹都是我们用来使这个应用程序工作的包和依赖项。你安装或从互联网引入的所有东西都会直接放入这个文件夹。这个文件夹会随着你为应用程序使用的外部包的数量而变得越来越大。

一旦我们通过这些文件夹,我们会发现一些具有一些有趣特征的文件。

文件内部

首先,我们可以看到.gitignore,它可以帮助我们在 GitHub 上上传时节省空间。如果你打开这个文件,你会看到里面已经写了一些文字。一旦你上传项目到 GitHub,你在里面看到的所有东西都会被忽略。你会发现.expo在那里,因为那些文件夹只对程序员有用,不打算共享。你可以通过使用任何你不想转移到在线或者你不打算更改的文件名来编辑这个文件。

重要提示

GitHub 是一个像互联网托管公司一样为开源软件程序提供服务的平台,同时还使用 Git 为程序员提供版本控制。开发人员使用 Git 来跟踪他们项目中的变化,并与他们的团队协调。

现在,我们会忽略App.js,因为我们将在本节末尾解释这个文件。所以,让我们直接转到app.json文件。这个文件就像是你的应用程序的配置文件 - 基本上,所有与代码无关的东西都会在那里找到。比如,例如,我们想要更改启动画面的图片。除了进入这个文件并编辑启动图片的路径之外,我们没有其他办法。从这里,你可以改变几乎与你的应用程序相关的一切,比如图标或其方向。你会发现自己经常去那里,为最终发布版本配置你的应用程序。

我们不关心babel.config.js,但我相信你对那个文件也会感到好奇。Babel 是一个几乎每个人都在使用的 JavaScript 编译器,用于获得对 JavaScript 最新标准的访问权限。编辑这个文件并不是必要的,但如果你想了解更多关于编译器的信息,我建议搜索更多关于 Babel 的信息。

最后两个文件是package-lock.jsonpackage.json。当你在项目中使用 npm 安装依赖时,第一个文件总是会被创建。我已经告诉过你,我们将在本章学习 npm,但现在不是时候。现在,我希望你熟悉项目目录中的所有文件。通过命令行创建应用程序时,Expo 自动使用 npm 从互联网上获取了许多你在项目中会使用的文件。这些文件存储在node_modules文件夹中。你可以在package.json中找到更多关于你正在使用的所有直接依赖项的信息。

现在我们终于到了所有文件的末尾,我们应该开始讨论App.js。所以,让我们打开那个文件,看看它。

App.js 文件

打开App.js文件后,你会看到以下内容:

图 2.2 - App.js 文件中的代码

图 2.2 - App.js 文件中的代码

你可以立即看到**打开 App.js 开始工作你的应用程序!**文本。我相信你记得,在上一章中,当我们测试我们的应用程序时,这就是出现在屏幕中央的文本。这意味着通过更改文本,我们也应该在我们的应用程序中看到变化。

我们现在不会这样做,因为我们的重点是理解文件和代码,然后根据自己的喜好进行更改。

我相当肯定,在看到这个文件后,你已经连接了其中的内容,并意识到这是我们应用的入口点。入口点是连接所有文件并启动应用程序的主文件。我们使用 Expo 的主要函数是App()函数。整个应用程序将存在于该函数内。

当你打开应用程序时看到居中的文本,原因是文本位于App()函数内。在这里,我们将开始构建我们的应用程序。为了实现这一点,我们必须理解 JSX 是什么,以及如何在我们的应用程序中使用它。我假设你已经能够阅读一些 JavaScript,并且理解诸如函数和对象之类的概念;我们不会在本书中涉及这个主题。我们将在下一节中掌握 JSX。

理解 JSX 的概念

我们终于到了这里,现在准备好审查 JSX 并学习如何在我们的应用程序中使用它。React 非常依赖于 JSX,因为这是构建应用程序布局的主要方式。

首先,我们来看一个包含一些 JSX 代码的变量:

const text = <Text>Hi, this is a message</Text>;

这种看起来很奇怪的语法看起来有点熟悉,对吧?它看起来像HTML。我相当肯定你至少见过一次 HTML 代码是什么样子。如果你还没有,那就打开你最喜欢的浏览器,然后转到reactnative.dev之类的网站。一旦你到达那里,右键单击网站的任何位置,然后左键单击检查

一旦你做到了,你会看到大量的 HTML 代码。随机点击其中任何一个 HTML 元素都会带你到网站上的特定元素。所以,你可以看到,HTML 是一种描述事物应该如何看起来的语言,或者更准确地说,它语义地定义了每个元素对于浏览器来说是什么。

不过,我们在 React/React Native 中不使用 HTML。相反,我们使用一种叫做JavaScript XMLJSX)的东西。

JSX 是 JavaScript 的扩展,允许我们在 JavaScript 中编写 HTML 元素。事实上,React Native 甚至不使用 JSX 的 HTML 部分。它只是使用它的语法,因为这样更容易观察和阅读。它也是基于 React 的,所以很明显它在编写代码方面会非常相似。

我觉得仅仅通过阅读前面的 JSX 代码,我们就可以很容易地理解那里发生了什么。它应该是一个带有消息“嗨,这是一条消息”的文本。

我们都知道在 HTML 中“text”不是要使用的正确标记,因为它不存在。我们在这里称之为text,因为这是一个 React Native 组件

太好了!所以,现在终于是时候涉及组件了。

发现组件

组件只是 JavaScript 函数。因此,我们可以这样写:

function Element(props) {
     return <Text>Welcome to your first component</Text>;
}

这个函数被称为组件,因为它返回一个 JSX 元素。我们稍后会讨论props,但它们非常重要,因为任何组件都可以在其函数内部接收一个 props 参数。

定义一个组件很容易,但它的使用非常重要。这使我们能够创建尽可能多的组件,它们可以是我们喜欢的任何样子。这是因为它清除了我们的代码,并使事情更容易组织。

让我们看看我们在App.js文件中找到的代码。试着观察App()函数的样子。它唯一要做的就是返回一大堆 JSX 元素。在这种情况下,我们甚至可以将这个函数称为一个组件,并且我们可以将其视为一个 JSX 标记。

Expo 正在使用此组件来启动您的应用程序,这意味着您的 React Native 应用程序只是一个封装了您将要编写的所有其他组件的大组件。

我所说的通过将此组件用作 JSX 标记是,如果出于某种原因,我们想将此组件带到应用程序的不同部分中,我们可以轻松地转到需要它的文件并在堆栈中写入<App />。然后,App()函数中的所有内容都将被呈现。

让我们尝试在我们唯一的App.js文件中使用一个已经存在的组件。我们知道<Text>是一个已经定义的组件,因为当我们第一次测试我们的应用程序时,我们看到它起作用了。

您应该已经打开了项目和终端。让我们继续在终端中写入expo start,这样服务器就会开始启动。

一个新的窗口将在您的浏览器中打开,就像在上一章中一样。点击**Run on…**并选择您想要使用的模拟器(或者如果对您来说更容易,可以使用您的物理设备)。我们已经讨论了如何运行应用程序,所以如果有什么东西似乎有点难以理解,请回到第一章React Native 和 Galio 简介,以刷新您的记忆。

现在应用程序在您的设备上运行良好,我们看到的是我们已经看到的基本屏幕。让我们通过删除<Text>标签之间的文本并用其他内容替换来稍微改变一下。在那里写上你的名字;我也会这样做。

所以,现在,我们有以下行:

<Text>Open up App.js to start working on your app!</Text>

此时,它应该看起来像这样(但是用您的名字代替我的):

<Text>Alin Gheorghe</Text>

在那之后,转到行的末尾并按Enter。将创建一个新行,所以让我们添加一些内容,使这个起始应用程序感觉更像是个人的东西,是我们自己的东西。

我们应该添加一些描述我们年龄和家乡的文本。您的App()函数现在应该看起来像这样:

图 2.3-您最近修改的代码

图 2.3-您最近修改的代码

现在保存您修改过的文件(通常通过按下Ctrl + Scmd + S),您会突然观察到一些很酷的东西。一旦您这样做了,代码会自动在您的模拟器/物理设备上更改。

这太棒了,对吧?通常,您需要重新启动服务器,但我们只需要保存我们一直在编辑的文件。这被称为热重载,是 React Native 自带的一个很棒的功能。

由于我们在我们的App函数中添加了一个新的Text组件,您可能已经猜到我们需要从某个地方获取这个组件。您不能在文件中使用组件而没有先导入它。所以,让我们学习如何做到这一点。

导入您的第一个组件

现在,是时候让我们更多地了解导入组件了。导入很棒,因为我们可以从任何地方获取组件并在我们的应用程序中使用它们。我的意思是-您可以从互联网的任何地方获取组件。

首先,让我们看看我们一直在App.js文件中使用的Text组件是如何进入的。

如果我们查看App()函数上面,我们会看到代码的第一行都是不同组件的导入。让我们看看它们是否那么复杂:

图 2.4-在 App.js 文件中显示的导入

图 2.4-在 App.js 文件中显示的导入

这很容易阅读和理解这里到底发生了什么。让我们以第一行为例。我们从名为expo-status-bar导入StatusBar

为什么我们要这样做?在我们的App()函数中,您会看到我们使用了一个名为StatusBar的组件。

为了能够使用特定组件,我们需要从软件包或项目内的定义路径中导入它。

我们可以看到来自React的导入,但我们在代码中找不到 React 组件;为什么呢?这主要是因为我们需要 React 来能够在创建所有这些组件和编写 JSX 时使用 React 框架。

在下面,我们可以看到有三个来自名为react-native的软件包的不同导入。我们可以看到StyleSheetTextView。React Native 内置了许多基本但非常重要的本地代码实现,供我们在 React 应用程序中使用。

我们将在下一节更详细地查看这些核心组件,但您必须了解这样一个事实,即这些组件被导入然后在我们的主函数中使用。

您可以在网上找到软件包,因此您可以通过使用npm轻松将它们导入到您的文件中。这已经与您的 Node.js 配置一起安装好了,所以现在就可以使用了。我们可以在npmjs.com上搜索软件包,并使用npm i package-name命令轻松安装其中任何一个。

现在,我们将专注于我们从react-native中收到的组件。我们将在接下来的章节中安装更多组件,但首先,我们需要学习如何使用我们已经拥有的东西,以及如何在此基础上构建。

让我们从导入一些最重要的组件并在我们的应用程序中使用它们开始。因此,让我们转到我们的App.js文件中的第三行。在我们导入StyleSheetTextView的大括号之间,我们将添加ImageTextInputButton组件。

现在,我们的行将如下所示:

import { StyleSheet, Text, View, Image, TextInput, Button } from 'react-native';

让我们试着理解每个组件的目的以及我们如何在应用程序中使用它们。

核心组件

在我们继续之前,我们需要了解所有基本组件。这将帮助我们意识到如何混合它们,以便我们可以创建更大更复杂的组件。这也将使我们在规划应用程序时更容易。在第四章您的第一个跨平台应用程序中,我们将创建一个功能齐全的应用程序,让我们为之自豪,让我们的朋友仰慕。以下列表显示了核心组件:

  • 视图

所以,让我们开始讨论 React Native 中最重要的组件:View。这个组件是所有组件的基础。View组件非常重要,因为没有它,你无法构建 UI。作为其他组件的容器,如果你想以特定的方式进行样式设置或布局排列,这是你最好的选择。

让我们看一个基本的例子:

<View>
      <Text>Hi! Welcome!</Text>
</View>
  • Text

我们已经使用了这个组件,它非常直接了当。我们可以使用这个组件在屏幕上显示文本。

让我们看一个基本的例子:

<Text>This is a text</Text>
  • Image

这很酷,因为它允许我们显示一张图片并按照我们想要的方式进行样式设置。

让我们看一个基本的例子:

<Image source={{uri: 'https://via.placeholder.com/300'}} />
  • StyleSheet

我们可以通过再次查看我们的App.js文件找到这个组件的使用示例。它创建了一个类似于 CSS 但具有更少样式规则的样式表。一旦你理解了它,就会发现它真的很容易使用,一旦我们到达我们的第一个实际挑战,我们将创建和设计我们自己的第一个屏幕时,我们将进一步进行样式设置。

让我们看一个基本的例子:

const styles = StyleSheet.create({
       logo: {
           backgroundColor: '#fff',
}
});
  • TextInput

这是一个用于使用键盘将文本输入到应用程序中的组件。它包含了您希望从输入中获得的所有必要方法,比如onSubmitEditingonFocus。别担心 - 当我们需要时,我们会使用所有这些方法。

让我们看一个基本的例子:

<TextInput placeholder='email' />
  • Button

这个组件渲染一个处理触摸的基本按钮。

让我们看一个基本的例子:

<Button title='Press me' />

我相当肯定你已经注意到一些这些组件在它们的标签内有另一个单词。例如,对于我们的Image组件,我们有单词“source”,它获取我们提供的链接以知道要显示哪个图像。那个词叫做prop,我们将在下一章中更多地了解它们。

在继续之前,让我们在我们的应用程序中使用这里的ButtonTextInput的示例。我们这样做是为了练习,并且在使用这些组件后,习惯于在我们的设备上看到的东西。

让我们去编写一些代码,在我们的Text组件下面显示我们的年龄和家乡,使用我们为TextInputButton的示例。现在,主要函数将如下所示:

图 2.5 - 导入和使用新组件后的新代码

图 2.5 - 导入和使用新组件后的新代码

现在,让我们刷新并查看我们的模拟器/物理设备。我们会看到两个新的东西:一个输入框,如果按下,会打开一个键盘,您可以在其中写东西,以及一个蓝色的按钮,上面写着大写字母的文本。

我们还没有使用Image组件,因为它需要样式才能工作。它需要告诉图像应该是什么大小。我们将在下一章更详细地讨论样式。

在这一点上,我们已经稍微详细地讨论了所有这些组件,并解释了每个组件的目的是什么。这些都是核心组件,因为它们涉及硬件功能,并且它们需要本地代码来运行。通过本地代码,我们指的是为 iOS 或 Android 编写的 Swift 或 Java 代码。开发人员正在构建和设计从这些组件继承的组件。

接下来,我们将学习如何创建组件以及如何组织我们的文件,以便我们永远不会忘记从哪里导入。

理解并创建您自己的组件

我们离我们的目标越来越近:创建一个跨平台的移动应用程序。为了使这成为现实,我们需要学习如何创建组件。

首先,让我们在项目的主目录中创建一个新文件夹,并将其命名为components。在这里,我们将创建一个名为PersonalInformation.js的新文件。

这个文件夹将作为所有我们组件的安全空间,一个我们可以随时导入我们组件的地方,就像我们通常会在网上找到的任何包一样。

因此,我们已经讨论了组件是如何创建的 - 它们是返回一堆 JSX 代码的 JavaScript 函数。但是,我还没有告诉你这些组件被称为功能组件,并且那里有不同类型的组件。

让我们通过在新创建的文件中编写所有必要的代码来构建我们的第一个功能组件。我们将创建一个组件,其主要目的是在屏幕上显示我们已经编写的个人信息。

我们将首先编写我们需要的导入。因此,对于这个组件,我们知道我们需要一个Text组件。让我们继续导入。在文件开头写入以下内容:

import React from 'react';
import { Text } from 'react-native'; 

我们已经导入了 React,因为正如我在本章前面提到的,如果我们想要创建组件并使用 JSX,我们需要它。因为这是最重要和基本的导入,我们将把它放在我们代码的开头。之后,我们从 React Native 导入了Text组件。

创建函数

让我们继续编写我们的功能组件,就像我们之前学到的那样:

function PersonalInformation(props) {
     return <Text>some text</Text>;
}

之前,我们提到我们需要它来显示我们之前所做的相同信息(我们的姓名,年龄和家乡),但我还没有写过类似的东西。那是因为我们遇到了我们的第一个问题。

假设我们尝试写这样的东西:

function PersonalInformation(props) {
      return (
           <Text>Alin Gheorghe</Text>
           <Text>24, Bucharest</Text>
);
}

在这里,我们会看到一堆红线在我们的代码下面。那是因为 JSX 不允许两个标签挨在一起,如果它们没有封装在一个更大的标签中。这就是View派上用场的地方。所以,让我们也导入它。我们的第二行代码现在会是这样的:

import { Text, View } from 'react-native';

因为我们现在有了View组件,我们可以在其中编写我们的函数,同时封装我们的Text组件,就像这样:

function PersonalInformation(props) {
      return (
           <View>
                <Text>Alin Gheorghe</Text>
                <Text>24, Bucharest</Text>
           </View>
);
}

有了这个,我们成功地创建了我们的第一个组件。但为什么我们要写相同的东西呢?我们已经在我们的主App.js文件中有了这些信息。我们这样做是为了理解为什么组件是如此酷。

导出和导入我们的组件

在我们转到主文件之前,我们必须能够导入它。在我们导出它之前,我们不能这样做。有道理,对吧?让我们继续在文件顶部添加以下行:

export default PersonalInformation;

现在,你的代码应该是这样的:

图 2.6 - 我们在 PersonalInformation.js 文件中编写的代码

图 2.6 - 我们在 PersonalInformation.js 文件中编写的代码

如果一切看起来正确,保存文件并转到App.js,这样我们就可以看看组件最有用的特性:可重用性可读性

现在我们在App.js中,让我们删除我们自定义组件中已经有的东西 - 我说的是显示我们个人信息的Text组件。删除这些之后,我们可以导入我们的新组件。如果你迄今为止一直跟着做,那么导入这个应该很容易 - 你只需要在最后一个导入的下面添加另一行。在那里,你将导入你的组件,就像这样:

import PersonalInformation from './components/PersonalInformation';

现在,让我们使用这个组件来代替之前已经移除的Text组件。这就像写<PersonalInformation />一样简单。

现在,你的代码应该是这样的:

图 2.7 - 在所有修改后我们的代码

图 2.7 - 在所有修改后我们的代码

现在,让我们保存并查看我们的应用程序。正如你所看到的,没有什么改变,但我们已经清理了我们的代码,因为我们只需要写一行代码就可以得到两行输出,这样更容易理解。它更简单易读,因为我们立即知道Personal Information组件将输出个人信息,而且,当我们寻找代码的特定部分时,很容易找到我们感兴趣的内容。

因此,如果我们想继续并从我们的主屏幕更改一些东西 - 比如说我们想改变我们的年龄,因为我们现在大了 1 岁 - 你可以很容易地看到你的个人信息在一个叫做PersonalInformation组件中,它是从一个叫做components的文件夹中导入的。现在,你只需要进入那个文件夹,找到那个特定的文件,并修改文本。这很容易理解,对吧?

让我们再创建一个,这样我们就可以看到如何进一步简化和清理这个过程。

创建 Bio 组件

现在,让我们从App.js中删除TextInputButton组件。我们现在不使用它们,而且它们似乎与我们的个人信息无关。

在从主函数中删除它们之后,进入我们的components文件夹并创建一个名为Bio.js的新文件。这是相当不言自明的,但我觉得个人资料应该在顶部有一个简短的传记,只有你的名字和年龄。

我们已经知道我们想要导入一个Text组件并创建我们的功能组件。我不会重复创建新组件的过程;相反,我会在Text组件内写一些个人的东西。

重要提示

不要忘记现在不需要View组件,因为我们这里只使用了Text组件。我们只有一个 JSX 元素的事实意味着我们的组件可以轻松地返回它,而不需要一个封装它的父组件。

新组件应该是这样的:

图 2.8 – 我们的新 Bio 组件

图 2.8 – 我们的新 Bio 组件

让我们保存并将其导入到我们的主文件App.js中。就像之前一样,我们在最后一个导入的下面创建一行新的,并写入以下内容:

import Bio from './components/Bio';

现在,让我们在我们的应用程序中使用它 - 我把它放在我们的<PersonalInformation />组件下面。保存并刷新。现在你应该能够在设备上看到你的年龄和家乡下面的个人简介了。

这很棒,但我们要继续为每个组件都添加一个新行吗?想象一下有 30 个自定义组件。那将变成一个可怕的噩梦,让人难以忍受。

为我们的组件创建主文件

我们可以通过进入PersonalInformation.js文件并从文件的最后一行删除default关键字来轻松解决这个问题。对Bio.js做同样的事情。你们两个文件的最后一行应该是这样的:

export Component;

当然,您将使用实际的函数名称,应该是PersonalInformationBio,而不是Component

因为我们已经这样做了,我们可以在我们的components文件夹中创建一个名为index.js的新文件。我们将在这里创建所有组件的列表,这将允许我们从一行中导入这些自定义组件。

在我们新创建的文件index.js中,我们将导入我们的组件,然后导出它们。这听起来很容易,有点多余,但这很有用,因为这将使事情变得更清晰,更容易阅读和遵循。

在我们的索引文件中写完所有内容后,代码内部应该是这样的:

图 2.9 - index.js 文件中包含的所有代码

图 2.9 - index.js 文件中包含的所有代码

现在我们有了存储所有新创建的自定义组件的文件,让我们进入我们的App.js文件,并按照应该编写的方式重写我们的导入。

重构我们的主要代码

在这里,我们必须删除我们的前两个自定义组件导入,并编写以下代码:

import { PersonalInformation, Bio } from './components';

这是我们正在做的唯一改变。很容易,对吧?看起来更好,更有组织。

现在,让我们删除未使用的组件,如TextImage,并保存我们的文件。在进行所有这些修改后,您的App.js文件将如下所示:

图 2.10 - 本章的最终代码

图 2.10 - 本章的最终代码

耶!我们已经完成了为我们的应用程序创建两个新组件,同时以一种任何程序员都会为我们感到自豪的方式组织代码。我不相信作业,但我相信锻炼的力量。现在轮到你了。创建尽可能多的组件。不要止步于简单的基于文本的组件;尝试并使用更多 React Native 提供的核心组件。不要害怕出错 - 这是学习的最佳方式:反复试验。

总结

在本章中,我们开始学习有关 Expo 基本文件结构的知识,以及所有这些文件是如何连接的,App.js是我们应用程序的主要入口点,以及在启动时调用了哪个函数。之后,我们深入了解了 JSX 的主要概念,解释并将 JSX 与其他标记语言进行了比较,并理解 JSX 更像是 JavaScript 的扩展。

我们把理论放在一边,开始导入我们的第一个组件,同时讨论 npm 以及在创建更复杂的应用程序时我们将如何使用它。我们导入了 React Native 的核心组件并对它们进行了解释。使用它们感觉很舒适,而且相当容易,所以我们想,为什么不创建一个组件呢?创建了一个组件后,我们学到了更多关于文件结构以及如何将所有组件索引到单个文件中,这帮助我们进一步清理了我们的代码。

在下一章中,我们将学习 React/React Native 开发者的正确思维方式,并了解如何以 React 的方式思考。这将极大地帮助我们,因为当我们开始一个新项目时,它将节省我们的时间。如果从一开始规划正确,我们在构建项目时就不会遇到任何问题。

第三章:正确的思维方式

我认为我们一起学到了很多东西,希望您会对继续学习过程感到兴奋。在上一章中,我们更多地了解了 React Native 项目的工作原理以及每个文件或文件夹的作用。之后,我们开始学习JavaScript XMLJSX)以及如何使用它,并且实际上导入了我们的第一个组件。了解您每次创建新项目时要使用的核心组件,使我们开始理解并创建自己的组件。

本章将主要关注 React 架构以及在花费一些时间与框架一起后它如何让我们以一种特定的方式思考。首先,我们将从人们启动 React 应用程序的主要思想开始,或者在我们的情况下,启动 React Native 应用程序,然后我们将轻松过渡到 React 的更高级概念,如 props。

通过掌握 props 的概念,我们将能够为我们的应用程序添加更高级别的复杂性。这将使我们能够创建更酷的组件,释放 React 的更多功能。您会发现自己在几乎每个创建的组件中都在使用 props。

之后,是时候学习如何渲染列表以及如何使用它们来更改组件内的信息。听起来很不错,对吧?我们将能够根据我们想要在组件内进行的任何计算或我们需要展示的项目数量来显示不同的信息。

完成本章将教会您作为 React 开发人员的思考方式。这将为您节省大量时间,特别是在您首次启动任何项目时,了解如何正确地构建文件和代码非常重要。

我们将意识到程序员是如何以一种方式重复使用他们的代码,以至于您会一直对您的家人说:“写一次,到处使用!”

本章将涵盖以下主题:

  • 以 React 思考

  • 始终首先构建静态版本

  • Props 以及如何使用它们

技术要求

你可以通过访问 GitHub 上的github.com/PacktPublishing/Lightning-Fast-Mobile-App-Development-with-Galio来查看本章的代码。您会发现一个名为Chapter 03的文件夹,其中包含本章中编写的所有代码。为了使用该项目,请按照README.md文件中的说明进行操作。

以 React 思考

让我们不要忘记 Facebook 为他们自己的项目创建了 React,并且它实际上在几乎任何类型的网站(或使用 React Native 的移动应用程序)中都有大规模的可扩展功能。如果 Facebook 可以在他们的平台上使用它,我们肯定可以在我们的应用程序中使用它。

为了充分利用这个框架,我们需要开始思考 React。当我开始我的编程之旅时,框架的概念对我来说似乎有点陌生。我不明白它被称为框架,是因为它带有特定的工作流程。嗯,这不是它被称为框架的唯一原因——它还因为它带有大量的功能和方法来使我们的工作更容易。

让我们想象一下,我们和朋友们一起合作开发一个应用想法,我们打算只是为了好玩而将其称为PiggyBank。这个想法是,我们需要始终跟踪我们用信用卡进行的所有交易。因此,基本上意味着我们将在我们的应用程序中的某个地方有一张卡来跟踪我们所有的交易。

我在 Adobe XD 中设计了下面的卡片,我认为这将帮助我们更好地可视化事物:

图 3.1 - 显示我们交易的卡组件

图 3.1 - 显示我们交易的卡组件

因此,我们的朋友设计了这个很酷的卡片,并要求我们在移动应用程序中实现它。很简单,对吧?我们已经看到如何通过使用 JSX 代码从上到下编写所有内容;除此之外,这张卡上有很多文本,这使得事情对我们来说更容易。你甚至可能认为我们不需要任何自定义组件,或者我们可能只需要一个。

嗯,这并不完全正确。这是我们的 React 知识发光的时刻,它帮助我们将一切划分为组件,使代码更容易、更清晰。但问题仍然存在...你如何知道在哪里画矩形,我们如何划分组件?React 推荐的一种技术是单一责任原则SRP)。

提示

SRP 是一个编程原则,它规定我们编写的程序中的每个类都应该对程序功能的一个部分负责。这是SOLID的一部分,它是软件工程师创建更易于维护、灵活和可理解的代码的五个设计原则的首字母缩写。

使用这个原则,我们现在应该能够将卡分成组件。让我们拿这张卡,并为我们遇到的每个组件在上面画一个矩形,如下所示:

图 3.2 - 绘制矩形以划分组件

图 3.2 - 绘制矩形以划分组件

因此,我们提取了以下组件:

  • TransactionCard红色)- 包含整个卡和所有元素

  • TransactionCardHeader绿色)- 代表卡的上半部分,即名称和总花费的部分

  • TransactionCardList黄色)- 包含项目列表

  • TransactionItem粉色)- 显示交易和价格的单个项目

正如你所看到的,我们成功地将这张卡分成了四个不同的组件,它们将不得不以某种方式相互交流,并最终具有显示有关我们交易的信息的这一目的。

它们每个都只有一个单一的目的,这样就可以检查我们一直在谈论的 SRP。让我们编写它,暂时不要样式 - 我们将在下一章中进行。始终先构建静态版本。

首先,我们需要明白,我们可以开始开发一个应用程序的最简单方法是构建静态页面,然后分离一切并构建逻辑。为此,我们将基本上复制我们在图像中看到的一切,甚至文本 - 这就是为什么我们称其为静态版本。

让我们从打开终端,转到我们项目的文件夹,并输入以下命令来创建一个新项目:

expo init TransactionCard

我选择了TransactionCard作为我的项目名称,但不要忘记你可以随意命名它。接下来,我们将选择空白的托管工作流模板,并等待它开始初始化我们的项目。一旦完成,让我们打开我们的集成开发环境IDE)/文本编辑器,并查看项目。

我将打开App.js并删除StatusBar导入(对于这个练习来说并不重要),以及我们App函数中View组件内的所有内容。

让我们决定我们需要哪些类型的组件。很容易看到,这张卡只需要一个View组件和一个Text组件。幸运的是,我们已经在文件中导入了它们,所以让我们使用它们来构建卡的静态版本。

我们将从我们的设计开始,尝试将一切划分为容器。正如我们所看到的,这张卡片有两部分:上半部分是带有一般信息的标题,下半部分则充满了我们最近的所有交易。

所以,让我们写一下那些部分的代码,但首先,我们将专注于我们卡片的上半部分,如下所示:

图 3.3 - 我们卡片的上半部分

图 3.3 - 我们卡片的上半部分

我们在这里看到了很多View组件,但为什么呢?正如我们在上一章中讨论的那样,View组件通常用于布局设计和将元素分组在一起。所以,我们将这两部分放在其中,然后为标题编写代码。如果我们保存并打开我们的模拟器,我们应该能够看到我们刚刚写的文本。

重要提示

不要忘记,如果你使用的是安卓模拟器,你首先需要打开安卓工作室,然后转到安卓虚拟设备AVD)管理器。运行你的模拟器,然后从 Expo 仪表板启动应用程序。

现在让我们考虑一下我们的交易。我们有两段文本 - 左边是我们购买商品的公司名称,右边是交易的价格。我们该如何做呢?到目前为止,我们看到的元素总是以从上到下的列式样式对齐在屏幕上。

嗯,我们需要为此进行样式设置,但这里的重要一点是,我们需要理解这两个组件在某种程度上是相互连接的,所以我们必须将这些元素放在同一个View组件中。

现在让我们这样做,准备好我们的组件来写所有这些交易。首先,试着自己做一下,然后看看你是否得到了和我一样的代码。

我将为每一行创建一个不同的View组件,然后在其中添加文本,就像这样:

图 3.4 - 静态代码的其余部分

图 3.4 - 静态代码的其余部分

让我们打开我们的应用程序,看看一切的样子。现在,它只是一堆文本,以列的形式显示我们设计中的所有信息。不过,它看起来并不像一张卡片,但我们肯定可以看到与我们的设计相似之处,即以相同的顺序包含相同的信息。因此,我们现在创建了我们卡片的最基本版本。

下一步是最终将这棵大树分解成更小的组件。通过这样做,我们将使代码更易于阅读和理解,同时也更模块化,这基本上意味着我们可以在不同的卡片或其他需要时使用相同的组件。

分解我们的代码

所以,记得我们已经将设计分成了四个不同的组件吗?让我们创建一个components文件夹,并为每个组件创建四个不同的文件,如下所示:

图 3.5 – 我们的文件夹中所有文件的创建

图 3.5 – 我们的文件夹中所有文件的创建

现在,是时候开始编写每一个了。所以,我们知道大卡片——或者第一个组件——应该能够分成两部分,ListHeader组件。让我们将App.js中的所有代码复制到TransactionCard中,因为这是主要组件。所有的代码,我指的是只有在第一个View组件内的代码。

创建完我们的函数后,我们将所有的代码粘贴到其中。让我们导出组件并查看它,如下所示:

图 3.6 – 以箭头函数形式编写的 TransactionCard 组件

图 3.6 – 以箭头函数形式编写的 TransactionCard 组件

我们将这个组件写成箭头函数,因为这样写起来更容易——至少在我看来是这样的——但老实说,如果你愿意,你甚至可以将其写成类。作为一个经验法则,通常只有在涉及状态时才使用class,但状态是我们需要在后面的章节中更深入地讨论的东西。

所以,我们在这里有所有的代码,并且我们已经导出了我们的函数。一切顺利——现在,下一步是更深入地划分我们的组件。让我们将组件的头部部分移到它特定的文件中。

在我们将代码复制到TransactionCardHeader组件后,让我们将该组件导入到TransactionCard组件中,并在其中使用它,而不是复制的代码。我们应该对我们卡片的第二部分做同样的事情,也就是TransactionCardList组件。让我们这样做,看看一切是什么样子。这是结果:

s

图 3.7 – 我们新创建的 TransactionCard 组件

图 3.7 – 我们新创建的 TransactionCard 组件

好的 - 这看起来干净多了。如果我们将这个组件导入到我们的App.js文件中,一切应该看起来和我们在开始对代码进行所有这些更改之前一样。

提示

不要忘记我们总是需要运行import React from 'react';,这样我们才能使用我们所有的组件。组件需要知道它是一个组件,而不仅仅是文件中的随机写入。这个导入帮助我们的代码识别哪些对象是 React 对象,以及如何渲染一切。

一切都正常,对吧?如果你遇到任何问题,在继续之前停顿 2 秒钟,检查我们到目前为止所做的一切;也许你拼错了什么,或者在你的文件中忘记了一些导出。

如果一切正常,让我们进入我们的TransactionItem组件。嗯,顾名思义,这是一个单独的项目,那是什么意思?正如我们在TransactionCardList组件中所看到的,我们确实有几个不同的项目。我们要为每一个创建一个不同的组件吗?

实际上不是 - 我们实际上要创建一个单一的组件,根据接收的任何信息来改变显示的信息。听起来很酷,对吧?嗯,这个输入被称为 prop,每个组件在渲染时默认会得到一组 props,但它也可以接收我们创建的自定义 props。让我们深入了解 props,并学习如何在我们的卡片上下文中使用它们。

Props 及如何使用它们

那么,props 到底是什么?到目前为止,我们只使用普通标签来标识我们的组件,比如TransactionCardHeader。然而,正如我们之前展示不同组件时所看到的,这些组件也可以有props,用于从更大的组件(父组件)传递信息到更小的组件(子组件)。

让我们进入TransactionCardList并查看我们的代码。据我们所见,就组件的使用而言,有很多重复的代码。因此,我们可以看到这种模式从我们主要的<View />标签中出现:

图 3.8 - TransactionCardList 组件准备分解为更小的组件

图 3.8 - TransactionCardList 组件准备分解为更小的组件

这个模式很容易看出来——我们有四个完全相同的代码片段,但里面写着不同的信息。基本上我们有四个View组件的实例,里面有两个Text组件。看到这种重复,我们可以清楚地意识到我们可以为这种特定情况编写一个外部组件。

让我们从在TransactionItem组件内编写一个静态组件开始,看看我们如何在列表中实现它。

随便写一个这种模式的片段;我们只需要一个——否则,我们会有点违背单个项目的目的。代码应该是这样的:

图 3.9 – TransactionItem 的静态版本

图 3.9 – TransactionItem 的静态版本

现在,让我们使用这个组件来代替我们在列表中使用的所有模式片段。导入文件并用四到五个TransactionItem的实例替换所有内容后,我们可以看到数据现在在所有地方都是Starbucks$ 10.12。像疯狂重复一样并不是一个伟大的移动应用程序设计,对吧?

那么,我们如何改变这种情况?我们如何让组件显示不同的信息?通过使用 props。让我改变TransactionItem组件,并看看 props 需要如何实现。代码应该是这样的:

图 3.10 – 将 props 实现到我们的组件中

图 3.10 – 将 props 实现到我们的组件中

现在,你的TransactionCardList组件包含多个TransactionItem的实例。如果你现在保存,除了$符号外,这些组件上什么都不显示。为什么呢?

这一切发生是因为我们的组件在这些变量中没有存储任何东西。为了实际在屏幕上显示一些信息,我们需要从TransactionCardListTransactionItem组件发送一些信息。让我们进入其中,并使用我们新更新的组件来在手机上显示正确的信息。

TransactionCardList组件中,找到我们的组件,并为每个组件添加以下 props,就像这样:

<TransactionItem name={"Starbucks"} price={10.12} />

在我们为所有组件添加了 props 之后,下一步是保存。我们将看到我们的模拟器会自动刷新——恭喜!我们成功地从一个组件向我们的组件发送了信息。

提示

从一个组件发送到另一个组件的所有信息都将正式地放在花括号内,就像我们通过为价格 prop 编写数字所看到的那样。即使字符串仍然可以放在花括号内,但它们对于发送信息并不是强制的,所以你甚至可以写name="Mircea"

现在,让我们试着稍微了解一下我们的代码。那么,我们的应用程序内部到底发生了什么?

当应用程序首次运行时,它直接转到App.js并开始首先在那里编写的所有组件。对于这一点,那将是我们的TransactionCard组件。

React 看到我们的组件实际上有两个不同的组件在其中,并开始渲染下一个组件。现在,其中一个组件实际上是我们的TransactionCardList组件,其中包含所有我们的TransactionItem组件。

因为第一个组件包含另一个组件,我们将第一个称为,第二个称为第一个的。所以,如果TransactionItemTransactionCardList,试着想一想TransactionCardTransactionCardHeader的什么。准备好了吗?TransactionCardTransactionCardHeader,因为它包含了另一个组件。

现在,当 React 到达TransactionCardList时,它将通过props向每个TransactionItem组件发送一些信息。被发送的信息是一个看起来像这样的 JavaScript 对象:{name: 'Starbucks', price=10.12}

这就是为什么我们可以在TransactionItem中将 props 作为函数的参数使用,然后通过点来访问我们对象的键,就像这样:props.name。你一定想知道 React 如何知道如何处理所有这些过程,因为一个更复杂的应用程序可能有数百个组件嵌套在一起,同时在第一次渲染时向彼此发送 props。

问题是,React 首先渲染表面上的所有内容,当所有信息从一个父组件发送到子组件时,它才会渲染该信息。

现在,为了使我们的组件更加可用和可重用,我们必须使列表中的项目数量更加可变。对于更大的应用程序,我们必须问自己这样的问题:"如果用户进行的交易数量比五个更多或更少会怎么样?"; "如果我将来需要更多的卡片,但设计相同,我该如何重用这个卡片组件?"

使用 map 函数动态更改组件的数量。

首先,让我们看看如何输出尽可能多的TransactionItem组件。我们将进入TransactionCardList组件,并在函数外创建一个名为transactions的对象常量数组。这个变量将包含所有项目所需的信息。让我们看看这是什么样子,如下所示:

图 3.11 - transactions 变量

图 3.11 - transactions 变量

一旦我们拥有了包含所有所需信息的这个变量,我们就可以对数组进行映射,并为每个项目输出一个不同的组件。如果你对 JavaScript 不太熟悉,这可能听起来有点混乱,但相信我,这其实非常简单。让我们删除<View />组件内的所有内容,并用map函数替换,如下所示:

图 3.12 - 在 TransactionCardList 组件内部使用的 map 函数

图 3.12 - 在 TransactionCardList 组件内部使用的 map 函数

好了,这可能看起来有点奇怪。别担心,其实很简单。所以,我们在transactions数组上使用了map函数。这个map函数遍历数组的每个元素,并使用其参数内的函数来输出某些东西。这个东西就是你要做的,利用这个很酷的函数。

重要提示

在 JSX 内部使用的所有外部代码必须放在花括号之间,以便 React 能够理解我们正在进行的操作可能会导致其他元素被输出以进行渲染。

基本上,由于map函数,我们正在取数组的第一个项目 - {name: "Starbucks", price: 10.12} - 输出一个TransactionItem组件,并将我们数组中的值作为 props 传递。但我们还看到了key prop,我们都知道我们在组件内部并没有使用 key prop。每个子元素都需要一个 key,以便 React 可以跟踪它们并避免过度重新渲染。这是我们在使用这样的列表时需要理解的 React 规则之一。

但我们说过我们会更进一步,对吧?如果需要,我们需要多次使用这个卡片组件。看到transactions只是一个随机变量坐在我们的TransactionCardList组件中,也许我们可以将其作为一个prop发送?

让我们在我们函数的参数中添加props关键字,并从transactions.map更改为props.transactions.map。如果我们现在保存,我们会得到一个错误 - 我们的组件期望一个名为transactions的属性进来,但没有任何东西发送它。

我们必须从我们的父组件 - 即TransactionCard发送这个。但尽管如此,这并不真正改变我们仍然无法正确使用这张卡片的事实,所以也许我们需要将这个属性添加到我们的TransactionCard组件甚至。

让我们复制我们的transactions变量并将其移动到我们的App.js文件中。之后,让我们将transactions属性添加到我们的TransactionCard组件中,就像这样:<TransactionCard transactions={transactions} />.

现在,我们需要去我们的TransactionCard组件,并使其能够接受这个属性,并将其进一步发送到我们的TransactionCardList组件。我们的组件现在需要看起来像这样:

图 3.13 - 我们新创建的 TransactionCard 组件的版本

图 3.13 - 我们新创建的 TransactionCard 组件的版本

所以,我们一直从App.js文件发送这些信息,一直到我们的TransactionItem组件,最终显示这些信息。这对我们有什么帮助?嗯,现在,我们可以有多个具有不同交易的此卡片实例,或者甚至可以根据我们现在在App.js文件中声明的常量来增加或减少交易的数量。我们可以完全使用不同的变量;我们可以有一个名为biggerTransactions的不同数组,并将其传递给另一个组件。也许这个组件将显示你做过的最大交易。

这里重要的是,我们现在根本不需要触碰我们的卡片组件,而且我们仍然可以在显示不同信息的同时使用它。这比为我们需要的每一条信息创建不同的文件要容易得多,或者也许有一天你需要改变特定的信息,你开始浏览每个文件寻找那个特定的东西。现在你不必这样做 - 只需进入你的主文件并从那里更改所有信息。

让我们做一些作业。你会在我们的 GitHub 存储库的第三章文件夹中找到答案。一直在我们的卡上使用相同的名称可能会变得无聊。通过允许自己使用同一张卡组件的多个实例,但用于不同的用户,可以使这变得更容易。完成后,去检查代码并将其与我的进行比较。看看你是否做了同样的事情!

总结

在本章中,我们更深入地了解了 React Native。我们学到了许多关于道具和 SRP 等新概念。我们应该能够开始思考使用基于道具的 React 方法论,甚至稍后使用状态。但理解所有这些对你成为真正的 React Native 开发人员是一个很大的进步。

关于道具的处理方式以及我们如何利用 React 的组件这一特殊功能来使代码更具可重用性和更清晰,你应该感到更加舒适。代码永远不会太干净,但同时要记住,有时候并不需要多层道具。也许你的组件只需要一层,或者根本不需要道具。只有在觉得这可能会让你的工作更容易时才使用这个功能。

我们还第一次创建了一个列表,并学会了列表的每个项目都需要一个键,有时甚至可以是我们数组的索引,但总会向我们的每个项目发送一个唯一的键。

在本章结束时,我们完成了一点作业,并对下一章充满了希望,届时我们将终于创建我们的第一个小应用程序来展示给朋友们看。

第四章:你的第一个跨平台应用

我们开始学习如何建立 React Native 开发环境。之后,我们继续学习 JSX、组件和属性。我们已经学到了很多,应该对未来有足够的信心。但如果你仍然觉得有些东西缺失,那么你是对的。我们还没有进行样式设计,也还没有构建一个真正的屏幕。

本章将围绕我之前想到的一个应用点子展开,该应用不断跟踪你的游戏历史。我们不会开始讨论服务器和数据库,因为它们超出了我们的学习范围,特别是因为我们有更重要的事情要学习。我们将从详细介绍我们应用的所有信息开始,同时使用我们在前几章学到的一切。

之后,我们将开始创建应用的静态版本,以便你了解在创建应用之前你的大脑需要如何思考。在前几章学到的所有原则将帮助我们更容易地理解我们的第一个真正的任务,所以如果有任何你仍然不确定的地方,回到前几章,看看你觉得哪些地方可以改进。

下一步是学习样式设计。我们将深入了解样式设计以及它在 React Native 中的工作原理。我们将了解 flex 是什么,以及如何在应用中使用它,同时找出我们可以使用的技巧,使开发更容易。

在为应用添加样式之后,我们将重构我们的代码,同时保持我们迄今为止构建的一切。这就是 Galio 将会发挥作用的地方,帮助我们意识到拥有已构建的组件是多么有用。我们将学习如何使用最重要的组件之一来构建布局,而不必担心为我们的容器创建不同的样式。

之后,我们将在手机上安装应用。这是一个单屏应用,所以我们只会用手机进行测试。我们还将学习一些基本技巧,以确保我们的应用在所有屏幕尺寸上运行顺畅。

一切看起来都很简单和容易,对吧?让我们直接开始构建我们的应用。本章将涵盖以下主题:

  • 构建我们的第一个应用

  • 创建你的第一个屏幕

  • 让我们为它添加样式!

  • 超级英雄,Galio

  • 让我们在手机上安装它

技术要求

您可以通过访问 GitHub github.com/PacktPublishing/Lightning-Fast-Mobile-App-Development-with-Galio 查看本章的代码。您会发现一个名为Chapter 04的文件夹,其中包含本章中编写的所有代码。要使用该项目,请按照README.md文件中的说明进行操作。

构建我们的第一个应用程序

让我们开始讨论我们应用程序的主要思想以及我们将如何开始构建它。我们将称此应用程序为 MGA,这是 My Gaming History 的缩写。相当聪明,对吧?它只会有一个屏幕,并且将作为用户登录后的欢迎屏幕。我们假装用户已经登录到我们的应用程序中,因此我们只会编写主屏幕,而不会考虑授权,这是一个更高级的概念。

通过清楚地了解我们的屏幕需要看起来像什么,并描述我们组件的目的,我们正在为我们的开发建立一条清晰的道路。最后,如果我们没有做好所有这些准备工作,我们在编程过程中会遇到困难,我们不希望发生这种情况。

我们应该从设计开始,确定其主要目的,以及如何开始将屏幕分成组件:

图 4.1 - 我的游戏历史主屏幕

图 4.1 - 我的游戏历史主屏幕

看起来不错,对吧?好吧,应该是的,因为这一次,我们将完全实现屏幕上的所有内容,甚至包括颜色和元素定位。毕竟,这是我们第一个完全创建的屏幕。

让我们试着考虑如何将所有内容分成更小的部分,这是 UI 创建中最重要的步骤之一。请记住,这是强制性的,因为如果我们只是试图在脑海中编写所有内容,而没有任何策略,我们将会遇到一些问题。

我们将使用方块来轻松识别屏幕上的每个元素,让我们来看一下:

图 4.2 - 组件划分

图 4.2 - 组件划分

我在这里将整个屏幕分成了几个部分,并进行了颜色编码,以便您更好地看到它们:

  • 主页(红色):我们的容器组件,也称为我们的屏幕。

  • 欢迎页(蓝色):这将包含有关用户的所有基本信息,例如他们的姓名、级别和个人资料图片。

  • MostPlayedGame蓝色):这将是一个容器,将接收关于最常玩的游戏以及图片的信息。

  • LastPlayedGameList蓝色):这包含一个项目列表。

  • PlayedGameItem绿色):这是显示最常玩的游戏和每个游戏所花费的时间的单个项目。

正如我们所看到的,我们在三个不同的组件中使用了相同的颜色。为什么呢?因为这三个组件在我们的主要更大的名为Home的组件中同样重要。它们都位于我们的组件树中的同一级别。即使Home组件是一个屏幕,它的定义方式与组件相同,当我们开始编码时,你会明白我的意思。

现在我们已经分割了我们的组件,准备继续并开始编写我们的应用程序。

创建你的第一个屏幕

一旦开发计划完成,我们知道每个组件需要放在哪里,以及我们的应用程序将会是什么样子,我们就可以创建一个新项目了。这个项目将为我们成为 React-Native 开发者的创造之路奠定第一块基石。

让我们开始创建一个新项目:

  1. 进入你喜欢的目录中的终端,并运行以下命令:
expo init mga
  1. 选择托管工作流的空白模板,并打开项目文件夹。

  2. 正如我们之前提到的,我们将有五个不同的组件,其中一个将是屏幕本身。所以,让我们创建两个不同的目录,分别叫做screenscomponents。这样在有多个不同的屏幕时,更容易组织起来。

在开始编码时,始终在脑海中有一个基本结构是一个好的经验法则,因为你永远不知道何时可能想要为你的应用程序添加更多内容。

  1. 在我们的screens文件夹中,让我们创建一个名为Home.js的文件。这将是我们的主屏幕,所以我们将开始编写组件的最基本代码。这只是一个功能组件的样板。还记得它们是如何创建的吗?我们在第二章中做过,React Native 的基础。现在,试着自己做一遍,一旦你成功做到了,就回到这里来:图 4.3 - 基本的主屏幕,除了一个视图组件外没有任何内容要渲染

图 4.3 - 基本的主屏幕,除了一个视图组件外没有任何内容要渲染

  1. 完成后,我们必须转到我们的主文件App.js

在这里,我们将从主文件中删除所有不必要的内容。我们不需要所有的样式,也不需要StatusBar导入,甚至不需要从 React Native 导入的任何组件。

  1. 删除所有内容后,我们可以在React导入之后立即导入我们的组件,并将其放入我们的主App函数中。

所以,我们的新组件现在应该看起来像这样:

图 4.4-删除所有不必要代码后的 App.js 文件

图 4.4-删除所有不必要代码后的 App.js 文件

你可能会想,“嗯,那个奇怪的<>语法是什么意思?”。那是Fragment的简短语法,这是 React 的一个特性。这样做是为了不向你的组件树添加更多不必要的节点。我们可以使用<View />组件,就像我们在之前的例子中看到的那样,但是通过使用Fragment,我们创建了一个包装器,而不是一个不必要的包装组件,因为我们不会在我们的主文件中进行任何样式设置。

如果这仍然造成一些问题,你可以很容易地将你的<Home />组件包装到一个<View />组件中。

现在我们在这里,让我们看看我们的components文件夹,并创建我们将要使用的所有必要文件。

  1. 创建四个新文件,分别命名为WelcomeHeader.jsMostPlayedGame.jsLastPlayedGameList.jsPlayedGameItem.js

  2. 让我们对我们新创建的每个文件都做与Home.js相同的事情。你甚至可以从Home.js文件中复制代码,然后粘贴到每个文件中;只是不要忘记将名称从Home改为你的组件名称。

现在我们已经初始化了所有的文件,我们准备开始进行代码移植。我们应该能够看到这些组件与上一章的组件之间的某些相似之处。几乎是一样的东西,所以你应该对我们如何继续有一个想法。

我们将从WelcomeHeader.js开始,然后查看我们的每个文件。如果你现在启动你的应用程序,你会看到一个空白的白屏。我们暂时忽略这一点,只是用一些基本的静态代码来勾勒我们的应用程序,这样当我们开始样式化时,就有一定的基础。

打开你的文件,这样我们就可以开始添加一些新元素。我们从设计中可以观察到什么,我们可能需要在我们的组件内部?嗯,首先,有很多文本,但我们还需要一个个人资料图片(在组件右侧的圆圈)。知道了这些,我们现在可以开始导入所需的组件,所以继续编辑我们导入View组件的第二行,使其看起来像这样:

import { View, Text, Image } from 'react-native';

还记得我们说过如果它们在同一行上,我们应该将组件分组吗?当我们开始样式化时,这将使事情变得更容易,因为这些组件在同一水平线上。

所以,我首先在我们的主View组件内添加了另一个View。之后,我将添加坐在同一行上的组件:我们的欢迎消息和我们的个人资料图片。在这个View组件下面,我们将添加另一个Text组件,它将呈现我们的Level

图 4.5 – 我们的 WelcomeHeader 的静态版本

图 4.5 – 我们的 WelcomeHeader 的静态版本

第二章React Native 的基础中,我们讨论了Image需要一个源来工作。这就是为什么我们使用了source属性并传递了一个占位图像链接。使用占位符更容易,因为我们不需要浪费时间搜索图像,当我们的主要目的只是编写一个静态版本时。

让我们继续并开始编写我们的下一个组件:MostPlayedGame。正如我们在之前的组件中所看到的,我们在这里需要与之前的组件相同的东西。所以,让我们导入一切并在我们的组件内使用它。一旦你做到了,我们将使用我们的组件来显示所有信息。现在,你的代码应该是这样的:

图 4.6 – 我们的 MostPlayedGame 的静态版本

图 4.6 – 我们的 MostPlayedGame 的静态版本

我在我们的占位链接中写了300而不是75,因为这会改变图像的宽度。但除此之外,这很容易理解。

在这一点上,我们会注意到一些非常有趣的事情。我们有一个遵循我们习惯的相同模式的列表。这是一个项目列表,每个项目都呈现了我们玩过的游戏以及我们玩了多少。我们可以复制我们以前使用的相同模式,它将工作得非常好:

图 4.7 – PlayedGameItem 组件

图 4.7 – PlayedGameItem 组件

我相信你还记得如何从父组件传递props到子组件是多么容易。如果我们已经知道某些组件应该如何编码,我们就不应该浪费任何时间。现在,是时候创建列表了,就像上次一样,但现在,我们在其中有另一个元素,一个Text组件作为我们组件的标题:

图 4.8 – 我们完成的 LastPlayedGameList 组件

图 4.8 – 我们完成的 LastPlayedGameList 组件

我们走得很快,但那是因为我们已经经历过这个,所以你应该明白这里发生了什么。我们代码目前的问题是我们没有向我们的项目发送任何信息。我们没有map函数需要运行的数组。正如你所看到的,数组来自props,所以我们的LastPlayedGameList组件期望一个名为gamesprop,带有一个数组,这样它就可以开始渲染我们的游戏列表了。

让我们进入我们的Home屏幕组件并设置一切。首先,我们将开始导入屏幕所需的所有组件。我们只需要这四个组件中的三个,因为其中一个是PlayedGameItem,它已经被我们的LastPlayedGameList组件使用和渲染。导入它们很容易,如下所示:

import WelcomeHeader from '../components/WelcomeHeader';
import MostPlayedGame from '../components/MostPlayedGame';
import LastPlayedGameList from '../components/LastPlayedGameList';

在导入我们需要的一切之后,是时候将组件放置在它们将出现在屏幕上的顺序中,放在我们的主View标签内:

图 4.9 – 我们的 Home 组件与其中的其他组件

图 4.9 – 我们的 Home 组件与其中的其他组件

正如你所看到的,我已经传递了我们需要的games数组给我们的列表,在我们的组件之上。让我们创建一个数组,这样我们就有东西可以传递给我们的LastPlayedGameList

首先,自己尝试一下 - 记住我们需要一个带有gametime键的对象数组。一旦你自己尝试了这个,回到这里看看下面的代码:

图 4.10 – 游戏对象准备发送到我们的列表组件

图 4.10 – 游戏对象准备发送到我们的列表组件

这并不难,对吧?在这里,我们编写了整个静态屏幕。我相当肯定,如果您回到模拟器,应该能够看到屏幕上弹出了一些东西。如果没有任何错误,那么我们应该可以继续。如果您在屏幕上遇到任何错误,或者仍然看不到任何东西,请尝试重新阅读一切,并确保您没有漏掉任何单词。我会说,70% 的错误是在开发阶段抛出的,因为我们通常会在变量中漏掉一些字符(不要引用我,这只是个人经验)。JavaScript 作为一种弱类型语言,意味着您不必指定变量中将存储什么类型的信息,因此我们不必像Java或**C#**开发人员那样担心错误地定义变量,但与此同时,变量在任何地方使用时都需要具有相同的名称。

现在,让我们开始让它变得漂亮起来。

让我们来设置样式吧!

在我们开始为应用程序设置样式之前,我们应该了解 React Native 中的样式工作原理。如果您之前有 React 的经验,您会知道样式是通过 CSS 完成的。然而,在 React Native 中,我们不能使用 CSS,所以一切都是通过 StyleSheet 完成的。

StyleSheet 是由 React Native 团队创建的。在这里,您有类似 CSS 的规则,但一切都是通过 JavaScript 完成的。

当将这些样式对象传递给我们的组件时,我们通过一个名为 style 的属性来进行。让我们首先直接为我们的Home屏幕创建一些样式。

我们可以通过两种方式将这些对象传递给我们的组件 - 我们可以直接在组件中编写它们,或者通过一个新的 StyleSheet 实例传递它们。让我们在行内编写,并为屏幕更改我们的背景颜色。通过转到我们的 Home.js 文件,我们可以为包裹其余组件的 <View /> 组件添加 style 属性:

图 4.11 - 为我们的组件添加行内样式

图 4.11 - 为我们的组件添加行内样式

在添加这个并保存文件后,您应该能够看到整个背景颜色如何改变为该十六进制颜色。现在,我们的背景颜色与设计图像的相同。这很酷,对吧?这也很容易阅读,因为本质上这就是 CSS,只是写法有点不同。

如果我们要编写 CSS,我们会说,例如,background-color: 'red',但因为在 React Native 中一切都是 JavaScript,我们无法用破折号在字符之间写变量或对象键,所以我们使用驼峰命名法。

但是关于内联样式存在一个问题;我们可能会有成千上万种样式,在这种情况下,我们会忘记一些东西在哪里,或者如何在我们的应用程序中更改某些东西。这就是为什么我们应该尝试使用更清晰的方式来编写样式。

让我们删除我们的内联样式,并通过在View旁边添加StyleSheet来更改导入,就像这样:

import { ViewStyleSheet } from 'react-native';

现在我们已经导入了StyleSheet,我们准备创建一些样式。为此,我们将使用.create()方法。这个方法将返回一个带有所有必要样式信息的对象:

图 4.12 - 样式对象

图 4.12 - 样式对象

现在,我们可以回到我们的<View />组件,并通过使用style={styles.container}将样式注入到我们的样式属性中。现在,一切应该看起来和我们内联样式时一样。我建议使用.create()方法来添加样式,因为它更清晰,更容易阅读。

现在,你可能会对flex有一些疑问。我的意思是,你在那里看到了它,但你还没有意识到那个属性到底在做什么。这些问题应该延伸到“我能通过以驼峰命名法编写所有 CSS 规则来在 React Native 中使用吗?”

问题是 CSS 有两种布局选项:网格flexbox。虽然你无法在 React Native 中使用网格,但整个布局都是基于 flexbox 的,所以你可以使用所有 flexbox 的规则。

你几乎可以以某种形式轻松地使用 CSS 中的所有规则。如果有一些你觉得在驼峰命名法中写不起作用的东西,那就去谷歌一下这个规则。你很容易找到如何使用几乎每一个规则。

flex: 1规则意味着“ <View /> 组件尽可能占据尽可能多的空间”,所以我们的主页现在是屏幕的全宽和全高。

让我们向我们的容器对象添加一些新规则:

  1. 添加paddingHorizontal: 32paddingVertical: 64。这将为我们创建一些美丽的呼吸空间,以便我们继续为我们的组件添加样式。

让我们从我们的WelcomeHeader组件开始。

  1. 我们将首先将StyleSheet添加到我们的导入列表中,然后创建styles对象。

  2. 之后,我们将创建upperSideprofilePicturewelcomeTextlevelText样式。

  3. 我们仍然看不到我们的图片,所以让我们给它一个宽度高度55。为了使它变成圆形,我们将给它一个borderRadius55/2

  4. 现在,我们将通过style属性向我们的图片添加profilePicture样式。

  5. 对于我们的welcomeTextlevelText,我们需要指定fontSize和颜色,所以让我们继续做。我会用38作为welcomeText的字体大小,18作为levelText的字体大小。文本的颜色将设置为'#707070'

我们将继续添加规则,直到我们的WelcomeHeader组件看起来像我们设计案例中的样子。一开始你可以自己试试。一旦你做到了,看看下面的代码,看看你是否得到了与我这里类似的东西:

图 4.13 – 我们完全样式化的 WelcomeHeader 组件

图 4.13 – 我们完全样式化的 WelcomeHeader 组件

有了这个,我们成功地为我们的WelcomeHeader组件添加了样式。我使用justifyContent将图像和文本推向相反的方向,我还指定了flexDirection,因为默认情况下,所有组件都以列的方式呈现。然而,对于这个特定的例子,我们需要一行。

我们不会在这里进一步查看样式规则,因为你可能需要通过练习自己去发现它们。所以,我现在最好的建议就是继续前进,创造一些东西。从你每天使用的应用程序中获得灵感,并创建一些外观类似于你选择的东西的组件。尽量重现尽可能多的组件,并看看哪些对你有视觉吸引力。过一段时间,这将成为你的第二天性。

如果你记不住某个规则,或者无法想出某种方式来以某种方式对某个东西进行样式设置,不要沮丧。事实上,大多数程序员都会忘记,他们中的大多数人会在 Google 上查找非常基本的东西。你现在最重要的事情不是因为某些事情不起作用而感到沮丧,而是把它看作一种挑战——这将百分之百地提高你作为开发者的能力。

我们将停止样式部分,因为我们已经为一个组件做了,我觉得我可以向你展示一些可能会改变你对样式的看法的东西。这是我们从现在开始创建应用程序时将开始使用的东西:加里奥。

超级英雄,加里奥

我们在本书开头谈到了 Galio。我们讨论了为什么要使用它,以及它如何为您的应用程序带来价值。现在,是时候使用它,看看这个 UI 库到底是什么。

现在,我们需要为我们使用的每个元素编写不同的样式对象。Galio 可以通过使用props来解决这个问题,这将帮助您在开发应用程序时为您的代码添加样式。

让我们从安装 Galio 到我们的应用程序开始。为此,我们需要打开我们的终端并运行以下命令:

npm i galio-framework

这将安装最新可用版本的 Galio 到我们的项目中。现在我们已经安装了 Galio,让我们从中导入一些组件到我们的WelcomeHeader组件中。

让我们去我们的import部分并写下以下内容:

import { BlockText } from 'galio-framework';

如果你已经写下并保存了你的文件,那么会出现一个错误。那是因为我们从react-nativegalio-framework都导入了Text。从react-native中删除它,一切应该再次正常工作。

哦,好吧,什么都没有改变。这是因为 Galio 的Text组件只是扩展了您通常的Text组件。但是,它附带了新的 props,可以让我们删除某些样式。

让我们删除我们两个Text元素上的style属性,并改为添加color="#707070"。现在,我们的文本很小,但它们是相同的颜色,这很酷。这意味着我们的 props 正常工作。如果我们想要改变字体大小,我们只需添加一个 prop。对于我们的第一个Text元素,我们将添加h3,代表标题 3,而对于我们的第二个Text元素,我们将添加p,代表段落

现在,如果我们点击保存,我们会看到我们的文本元素突然有了不同的大小,一切看起来都很好。我们现在可以删除未使用的样式对象;也就是welcomeTextlevelText

让我们继续看看是否可以删除更多。我们应该用Block组件替换包裹我们的TextImage元素的<View />组件。

现在,让我们向我们新实现的Block元素添加以下 props:rowspace="between"。因此,我们可以从我们的styles对象中删除upperSide对象。现在,一切看起来都一样,但代码更少,更容易注意到。

Block组件与View组件相同,但它包含了许多可以简化我们开发过程的 props。

一旦我们替换了它,让我们也替换另一个View元素。我们还将从导入中删除它,因为我们不再需要它:

图 4.14–我们的 WelcomeHeader 组件,其中包含了新实现的 Galio 元素

图 4.14–我们的 WelcomeHeader 组件,其中包含了新实现的 Galio 元素

我们现在了解了 Galio 的工作原理,我们将看到它将如何帮助我们继续开发这个应用。所以,让我们继续开始修改其余的组件。

让我们进入我们的MostPlayedGame组件,并开始从 Galio 中导入我们需要的任何内容。同样,我们需要使用BlockText。在导入这两个组件之后,我们可以从react-native中删除ViewText的导入,因为我们不再需要它们。但是在替换View元素之前,不要立即保存,我们需要将函数内部的View元素替换为Block元素,就像之前一样。现在,您可以继续保存文件,您将看不到任何更改。这很完美–我们现在可以开始为这个组件设置样式了。

让我们继续为我们的Text组件添加以下 props:size={15}color="#707070"。这将改变我们文本的字体大小和颜色。

现在,我们需要从react-native中导入StyleSheet并使用它来为Image设置样式,以便它可以在我们的屏幕上呈现。我们将使用StyleSheet.create方法创建一个新的styles对象,并在其中放置image对象。

之后,我们还将添加一个container对象,以便我们可以在组件之间创建一些空间。这将在我们的Block元素中使用。

我们的新styles对象应该看起来像这样,并具有以下值:

图 4.15–用于我们的 MostPlayedGame 组件的样式

图 4.15–用于我们的 MostPlayedGame 组件的样式

在写下所有这些并将我们的styles.containerstyles.image对象链接到正确的元素(Block元素和Image元素)之后,我们可以看到我们的屏幕开始越来越像我们在本章开头看到的设计。

顺便说一句,我在我们的容器样式中添加了 4px 的paddingBottom,只是因为我觉得我们的Text元素需要一些呼吸空间。我们也可以为Text创建一个新的样式,并在周围创建一些填充。写样式没有正确的方法,只要它的目的,也就是显示你想要显示的内容,得到尊重,那么尽情地玩耍和尝试吧。

不要忘记,我们通过style属性将样式链接到每个元素。

噢,好吧 - 我想随着我们已经经历了这么多,使用 Galio 和样式变得更容易了,所以我会休息一下,让你来为其余的组件添加样式。一旦你完成了,回到这本书上来,看看我们是否采取了相同的路径,通过比较你的结果和我的结果。也许你的看起来甚至比我的更好,同时代码更清晰,如果是这样的话,你今晚应该奖励自己。

你完成了吗?很好 - 让我们继续吧!让我们跳到我们的LastPlayedGameList组件。这应该很简单,所以让我们从galio-framework中导入我们的BlockText组件,同时完全删除我们从react-native中的导入。没错 - 我们不再需要那些了。

然后,我们将把View元素改为Block元素。在这里,让我们也添加一些内联样式;即style={{ marginTop: 32 }}。我们添加了这个来在组件之间创建更多的空间。

现在,让我们去我们的Text组件,并添加color="#707070"size={18}属性。就这样,我们完成了。我们创建了这个组件非常快,对吧?嗯,样式并不难,特别是当涉及到 Galio 时。

让我们继续我们的最后一个组件,PlayedGameItem。这个将和前一个一样。我们将从galio-framework中移除react-native的导入,同时添加BlockText的导入。

现在,让我们用我们的新Block元素替换View元素,并为其添加rowspace="between"style={{ marginTop: 16}}属性。之后,我们将为我们的两个Text元素添加color="#707070"size={14}属性:

图 4.16 - 在添加 Galio 和样式后,我们的全新组件

图 4.16 - 在添加 Galio 和样式后,我们的全新组件

有了这个,我们就完成了。保存你的文件,看看你的模拟器。它看起来就像我们想要的样子。在继续之前,花点时间为屏幕增添更多特色。将图片更改为你想要看到的任何图片 - 也许添加一个个人资料图片和你最喜欢的游戏的图片。

还记得我们是如何使用 props 将信息从父组件传递到子组件的吗?你可以做同样的事情,改变我们的WelcomeHeader中的名字,甚至可以更模块化,将所有信息从Home屏幕发送到你的组件中。

现在我们已经完成了对我们的应用进行样式设置,让我们看看如何在我们的手机上使用它。

让我们在手机上安装它

我们在第一章中讨论了为什么 Expo 很棒,React Native 和 Galio 的介绍,我认为 Expo 的人们在创建这个框架时做得很好。智能手机的问题在于你不能很容易地在手机上安装应用。

Android 比 iOS 更开放,你可能可以将一个.apk文件导出到你的手机上。然而,iOS 不允许你这样做。

当然,我们可以使用TestFlight,这是苹果的一个服务,允许你与其他测试人员测试和分享你的应用。但这对我们没有帮助,因为谁会在他们的手机上安装 TestFlight 来看你的一个屏幕应用,特别是当你需要一个苹果开发者账号时?

Expo 为我们提供了一个名为Expo Go的小应用。你可以在App StoreGoogle Play Store上找到它。下载并登录,或者如果你还没有账号的话就创建一个新账号。在这里,你可以为你的项目创建一个构建,以便以后测试。通过这样做,我们可以向朋友展示我们的应用,而不用太担心其他障碍。

在 Expo 上发布项目很容易;我们只需要按照一些步骤。让我们通过进入终端并按下Ctrl + C来关闭我们的开发服务器;然后,输入expo signin并按Enter。会出现一条消息,要求你输入用户名和密码。如果你还没有账号,就跳转到 Expo 的网站上创建一个。在输入用户名和密码后,你应该会得到以下回应:成功。你现在以 YOUR-USERNAME 的身份登录

现在,如果我们想要使用 Expo 发布我们的应用程序,有两个选项可供我们使用。我们将在接下来的章节中讨论它们,因为错误可能随时发生。如果遇到错误,最好尝试另一种方法。

通过 Expo 开发者工具发布

现在您已经登录,让我们通过在终端中输入expo start并按下Enter来再次打开我们的服务器。

开发服务器已启动,并且应该在您的浏览器中加载一个包含 Expo 开发者工具的新选项卡。请记住,在第一章中,介绍 React Native 和 Galio,我们展示了所有可用的选项;让我们点击发布或重新发布项目到互联网

图 4.17 - 单击发布按钮时显示的所有信息

图 4.17 - 单击发布按钮时显示的所有信息

现在,您的应用程序应该已经发布,这意味着您可以在手机上的 Expo Go 应用程序中打开您的应用程序。看?很容易!继续向朋友们展示吧!

通过 Expo CLI 发布

现在,第一种选项可能不适用于您,或者您遇到了错误的可能性。有时,错误就会发生,甚至可能不是您的错。在这种情况下,停止我们的开发服务器,并在终端中输入expo publish命令。将会出现一条大消息,说明它将开始捆绑您的应用程序并准备发布。过一会儿,您将看到它已成功发布到 Expo。

现在,您的应用程序已经准备好向世界展示了。嗯,有点。您可以登录到 Expo Go 应用程序,然后在个人资料选项卡下的已发布项目类别中查看您的应用程序。问题是……来自互联网的其他人可能会在 Expo 网站上看到它,并在他们的计算机上下载它,但您的朋友们无法在他们的手机上下载该应用程序。这是因为我们还没有在官方商店上发布该应用程序。它甚至不在商店上 - 它保存在云端供其他 Expo 用户查看,当然,您随时都可以访问它。

恭喜!我们终于创建了我们的第一个完整屏幕。我希望您感觉良好,因为还有更多的知识将使开发变得更容易,更有趣!

摘要

在本章中,我们经历了为我们的应用程序创建屏幕的过程。我们拿到了一个设计文件,看了一下,然后重新设计了没有功能的设计。这对任何人的职业生涯来说都是一个很大的进步,因为这是你第一次完成一个应用想法。我认为你应该给自己鼓掌,并意识到你在这里所做的并不容易。很多人甚至不会尝试开始学习这个,但你做到了。而且,你甚至创建了一个完全样式化的屏幕。

一旦我们了解了样式,Galio 就出现了。我们学会了如何使用 Galio 构建布局,这让我们的工作变得更容易。我们仍然没有完全摆脱样式的部分,但我们永远不可能不给东西加上样式。毕竟,样式是有趣的。通过使用 Galio,我们看到了如何轻松地排列元素并创建快速原型。

在本章末尾,我们看了两种不同的发布应用想法到 Expo Go 的方法,这是一个移动应用程序,可以帮助我们在不实际推送到商店的情况下玩我们的项目。这很酷,我敢打赌你的朋友和家人会因为看到你取得的进展而感到非常高兴。

现在,是时候进入下一章了,我们将讨论使用 Galio 的好处。

第五章:为什么选择 Galio?

在上一章中,我们创建了我们的第一个屏幕。在用普通的 React Native 代码创建它之后,我们继续导入了一些 Galio 组件,这些组件帮助我们以更加简单和轻松的方式进行样式和布局的创建。

本章将更好地介绍 Galio。我们将学习如何使用它,以及为什么大多数程序员寻找类似 Galio 这样的用户界面(UI)解决方案来解决他们大部分的开发过程。正如我们在上一章中看到的,仅仅使用核心的react-native组件意味着代码变得非常庞大且难以维护。Galio 组件打包了许多不同的属性,使生活变得更加轻松。

我们还将了解使用开源库的好处,以及如何创建一个愿意互相帮助的人群社区,以及你如何可以根据自己的意愿为库增加价值。

这次对话将打开许多你以前从未想到的新大门。它将创造一种新的心态,扩展你对开发者真正是什么以及他们如何交流的视野。

在本章中,我们将涵盖以下主题:

  • 使用 Galio 进行美丽的移动应用开发

  • 在你的应用中使用 Galio

  • 发现 Galio 的好处

在本章结束时,你应该能够理解人们为什么选择 Galio 来快速开始他们的项目。你将了解如何安装它并在你的应用中使用它,以及某些组件在你的应用中扮演的角色。了解某些组件肯定是有帮助的,但不要躲避——所有程序员都使用 Google 来发现他们的问题的解决方案,我强烈鼓励你在需要进一步解释或在时间过程中发生变化的情况下也这样做。

技术要求

你可以通过访问 GitHub 上的github.com/PacktPublishing/Lightning-Fast-Mobile-App-Development-with-Galio来查看本章的代码。你会发现一个名为Chapter 05的文件夹,其中包含了本章中我们编写的所有代码。为了使用该项目,请按照README.md文件中的说明进行操作。

使用 Galio 进行美丽的移动应用开发

我们有很多移动应用程序的例子,它们看起来并不真的好看。许多不同的社交媒体应用程序都是由随机的人创建的,他们认为他们会像 Facebook 一样大获成功。我发现大多数这些应用程序的最常见问题是设计问题,除了你总是会在初学者开发的应用程序中发现的错误。

布局很快就创建好了,他们并没有注意到他们的设计可能会因为用户体验UX)而受到影响。他们认为只要他们有一个好主意,就不需要注意其他任何事情。

我不同意。我真诚地相信只要设计时尚,用户体验一流,你就可以销售任何东西。我之所以这样认为,主要是因为我通常使用1 分钟规则。这是我为自己创建的一些个人规则。基本上,一旦我安装了一个应用程序,我只需要大约一分钟的时间来尝试看看这个特定应用程序发生了什么。

为什么要等一分钟呢?嗯,我们使用移动应用程序是因为我们希望事情变得快速和易于使用。我们总是在寻找移动应用程序的替代方案,因为我们希望更轻松和更快速地访问我们的网络相关活动。我们希望能够查看一些信息,甚至可能做一些活动。如果我在 1 分钟内无法弄清楚如何使用你的应用程序,那么我会卸载它。

这对我们应该如何构建我们的应用程序有什么影响?我们应该时刻考虑用户,并且只使用足够的信息,让他们不必考虑如何使用我们的应用程序。

Galio 很方便,因为它使用相同的流程——简单,快速和直接。你不必太在意按钮应该有多宽,或者你的应用程序中像素大小应该是多少。它预先装载了你设计和制作最佳想法所需的所有工具。

让我们先看看按钮的外观和我们为它们提供的许多不同样式。我们几乎在应用程序的任何情况下都会使用按钮,所以我觉得这将是一个很好的开始。看一下以下的截图:

![图 5.1 – 应用程序中显示的按钮

]

图 5.1 – 应用程序中显示的按钮

正如你所看到的,我们有很多不同的方式来显示按钮,从明亮的颜色和阴影到无阴影和简单。你可以有方形,甚至——直截了当地——只是一个圆圈和一个图标。

让我们看看这在我们的应用程序中如何轻松实现。这是图 5.1 中显示的按钮的代码:

图 5.2 - 图 5.1 中按钮的代码

图 5.2 - 图 5.1 中按钮的代码

因此,就我们所看到的,我们为所有事情都有 props。有些需要我们更多或更少的工作,但与此同时,只需从组件内部编辑一切的便利性每次都是值得的。只是因为我们想要将按钮大写并使其始终大写,我们可以使用capitalize prop。或者也许我们希望文本始终是大写的;那没问题——我们也有一个 prop。这真的使得开发过程变得非常容易,任何人都可以轻松使用。

我们已经讨论过应用程序应该对我们的用户看起来和感觉良好。但这也应该转化到我们的开发过程中。这就是为什么我真诚地相信,清晰而美丽的代码几乎总是等于一个美丽的产品。

现在,让我们来看看 Galio 包中另一个很酷的组件——Accordion。你永远不知道何时需要一个外观漂亮的手风琴来为你的内容创建更多的空间。你可以在这里看到它的表示:

图 5.3 - 手机屏幕上显示的手风琴组件

图 5.3 - 手机屏幕上显示的手风琴组件

这个组件非常容易使用。它需要一个具有指定高度的View(或Block)组件和定义组件内部内容的对象数组。以下是与此组件相关的代码:

<Accordion dataArray={data} />

这基本上对于任何人来说都应该很容易配置和在需要时使用。数组内的对象必须具有特定的键,以便我们的组件可以识别和理解在哪里放置内容。对象可能看起来像这样:

{title: "2nd Chapter", content: "Lorem ipsum dolor sit amet"}

看起来并不那么难,对吧?如果我们想使用一个图标,就像我们在创建第一个项目时看到的那样(在第一章**,React Native 和 Galio 简介),我们所要做的就是在对象内添加icon键,其中将包含我们想要使用的指定图标的namefamilysize值。

这基本上是 Galio 所有组件的构建方式。它们直截了当,外观良好,可以立即用于在几秒钟内创建新应用程序。

在继续之前,我们应该查看另一个组件,看看使用 Galio 自定义和使用复选框有多容易。看一下以下截图:

图 5.4 - 复选框组件在您的屏幕上显示

图 5.4 - 复选框组件在您的屏幕上显示

如果要使用核心 React Native 组件创建这个布局,看起来会很复杂,但我们很幸运,因为 Galio 使它变得如此简单,只需写一行代码,如下所示:

<Checkbox color="primary" flexDirection="row-reverse" label="row-reverse checkbox" />
<Checkbox color="info" initialValue={true} label="initialValue set to true" />
<Checkbox color="error" initialValue={true} label="different icon" iconFamily="font-awesome" iconName="plane" />
<Checkbox color="warning" labelStyle={{ color: '#FF9C09' }} label="labelStyle used here" />
<Checkbox color="success" image="https://images.unsplash.com/photo-1569780655478-ecffea4c165c?ixlib=rb-1.2.1" flexDirection="column-reverse"/>

正如我们所看到的,我们可以在我们的组件内设置颜色、方向,甚至图标。它们在没有任何修改的情况下写入和显示都很美丽。这让我们为我们的库感到自豪,因为我们真的为它的外观感到自豪。

现在,让我们看看使用Block组件创建基本布局有多容易。我们将仅在布局设计中使用此组件,并为每个方块着色,以便更好地理解每个元素实际显示的内容。

在您的应用程序中使用 Galio

现在,让我们看看 Galio 的实际效果。Galio 最大的特点之一是我们的Block组件,它基本上是一个带有超能力的View组件。为什么说是超能力呢?我们可以轻松使用此组件来创建布局,并且只需使用 props 就可以轻松地为所有内容设置样式。

因此,让我们付诸行动,看看使用Block组件创建基本布局有多容易。我将逐步向您展示使用Block的最常见方式,并演示布局的最常见排列方式。您可以在我们的 GitHub 存储库中找到该项目,或者可以跟着我一起编码。

我将从创建一个新的 Expo 项目开始。之后,我将通过命令行安装 Galio,写入以下代码:

npm i galio-framework

现在我们已经安装了所有内容,我将跳过整个组织文件的过程,因为我们只是用于演示目的。因此,我们将直接将代码编写到我们的App.js文件中,即我们的入口点 - App函数中。

我们将通过import函数在其他导入项下导入我们的Block组件,就像这样:

import { Block } from 'galio-framework';

我将删除App函数内的所有内容,然后开始创建我的第一个Block组件。这将用于将所有元素放在内部,因为我们知道,在函数中我们不能返回多个组件,所以总之,一个组件将必须将其他组件封装在内部。

我们将在其中使用flex属性,这将使我们的Block具有flex: 1的属性,以便它可以水平和垂直拉伸,覆盖整个屏幕。

现在我们完成了这一点,让我们使用style属性。正如我们所说,每个Block元素都将具有backgroundColor属性,以便我们可以更容易地识别哪个是哪个。在我们的style属性内,我们将写styles.container

请记住,在下面有一个styles对象,其中包含我们可以通过StyleSheet.create函数使用的所有样式。我们将删除容器内的所有内容,只写backgroundColor: '#F94144'

保存一下,现在,我们的屏幕应该是一种红色。有趣的是,这种颜色叫做红色莎莎

现在一切都正常运行,让我们继续开始创建我们的盒子布局,看看使用Block组件在我们的应用程序中排列元素有多容易。

顺便说一句,您还应该删除不必要的导入,比如StatusBarTextView

我们现在将在主Block组件内创建三个Blocks。正如我们所知,React Native 中的所有组件都是从上到下排列的,所以我们基本上要创建三行Blocks

这些行中的每一个都将在它们上面使用style属性,从上到下的顺序,样式将被称为styles.row1styles.row2styles.row3。现在,我们将进入我们的styles对象并创建row1row2row3样式。它们每个都只有一个属性,那就是backgroundColor,值的顺序从row1row3,就像这样:#F3722C#90BE6D#277DA1

现在,如果我们保存,我们将看不到任何东西。那是因为我们的Block元素没有设置大小,所以它不知道需要占用多少空间。还记得我们上次做的吗?我们使用了flex,所以让我们在所有三个组件上使用flex属性,如下所示:

图 5.5-我们用来创建三行的代码

图 5.5-我们用来创建三行的代码

点击保存,突然间我们从上到下看到了三种颜色:橙色,绿色和蓝色;更确切地说:橙红色,开心果色和 CG 蓝色。

由于使用flex属性时应用了flex: 1属性,每个组件在主Block组件内获得了相等的空间。现在,关于这个flex属性的酷炫之处在于我们可以使用它来设置我们需要的空间量。

让我们继续,对于第一行,我们将把它设置为flex={2};对于第二行,我们将保持原样;对于第三行,我们将把它设置为flex={3}。现在,我们可以看到每个框都分配了不同的空间。这都归功于 React Native 使用flex 系统来创建布局;我们只是利用了 Galio 与之搭配使用的便利性。

现在,让我们看看当我们将所有这些数字设置为flex属性时它是如何进行计算的。因为我们将第二个保持原样,当渲染时它将被转换为flex={1}。我们将对三个 flex 进行计算,得到以下结果:2+1+3 = 5。所以,简而言之,我们可以说第一行是五份中的两份第二行是一份第三行是三份。这里使用的数字是特定于我们的应用程序,但你可能有不同的数字。主要的想法是要理解这些数字正在分配它们所拥有的空间——一个更大的数字给我们更多的空间,而一个更小的数字给我们更少的空间。

现在,让我们使用第一行来放置另一组Block组件并使用更多的属性。是的——我们确实有很多属性可以与之搭配使用。

我们先只输入一个组件,并创建一个名为row1el的样式。将该样式应用到我们的新Block上,并使用#577590颜色。嗯,是的——什么都没有显示出来,但让我们使用两个更多的属性来让它显示出来。我们将写width={50}height={50}。这将以像素为单位设置我们的Block组件的宽度和高度。

让我们通过在父组件上使用middle属性来使这个元素居中。父组件是我们的第一行。现在你可以看到,我们深蓝色的block元素位于第一行的中间:

图 5.6 – 我们的代码中包含最新的元素

图 5.6 – 我们的代码中包含最新的元素

现在,对于第二行,让我们进入我们的styles.row2对象并添加填充。我们将添加padding: 30,我们可以观察到我们的第二行突然变得更高了。那是因为我们整个布局(三行)都是用 flex 构建的,它不是以像素为单位设置绝对大小;组件现在需要更多的空间。

在我们的第二行内,我们将创建另一个具有flexmiddlestyle={styles.row2gal}属性的Block。现在,对于我们的row2gal,我们将有backgroundColor: '#F9844A'。让我们在其中添加三个Block组件。它们每个将具有以下属性:width={30}height={30}style。样式将按顺序命名,从上到下依次为row2p1row2p2row2p3。按照我们的样式的确切顺序,对于每个样式,我们将设置backgroundColor属性为'#4D908E''#43AA8B''#F94144'

现在,如果我们点击保存,我们会看到我们的Blocks被定位在一列中。让我们通过在父组件中使用row属性来解决这个问题。现在,我们把它们放在了一行中 - 这很酷,对吧?让我们也使用middle属性,以及space="evenly"。保存并查看效果。我们的元素现在居中,并且它们与父组件的左右边距之间有均匀的空间。

现在,让我们进入第二个Block并使用bottom属性。这将使第二个元素位于第一个和第三个元素下方。有点有趣 - 看起来像一张脸,对吧?看看你是否同意:

图 5.7 - 我们填充第二行后的代码

图 5.7 - 我们填充第二行后的代码

你可以看到仅使用Block就可以轻松创建基本布局。现在,在继续之前,你应该花些时间,而不是使用bottom,也许在另一个组件上使用top属性,看看它是如何工作的。或者,而不是使用space="evenly",你可以使用space="between"space="around"

通过使用这些组件,我们实际上可以完全控制创意。最好的部分是你可以创建一个由Blocks组成的全屏幕,然后只需用你想要的组件填充每个Block元素。老实说,这些功能本身就足以让我开始喜欢 Galio。幸好我们还有更多功能。

现在我们已经在我们的应用程序中使用了一些 Galio 功能,让我们继续前进,看看 Galio 提供了哪些好处。

发现 Galio 的好处。

现在我们已经了解了使用 Galio 的几个好处,比如编写代码的便利性,它的美观程度,以及使用它创建布局的酷炫之处,我们准备看看使用它的其他好处,我觉得我们应该开始我们的旅程的最佳地点是 GitHub。

你可以在这里看到 Galio 的图标:

图 5.8 - 从 Galio 的登陆页面截取的屏幕截图

图 5.8 - 从 Galio 的登陆页面截取的屏幕截图

正如我所说的,我们很幸运有这样一个伟大的社区,总有人伸出援手帮助你。你也可以帮助其他人,我们总是鼓励这样做。我觉得 Galio 的社区可能最好地用“集体”这个词来定义。在音乐行业,这个词通常用来定义一群有着相似兴趣的人,他们一起合作,互相帮助,因为他们知道更多的人意味着更快更容易的发展。

让我们看看你可以如何帮助并成为这个社区的一部分。

首先,我们有 Discord 服务器,这是我们大多数开发者聚集讨论各种事情,包括错误和如何解决特定问题。这个地方基本上是一个大型的聊天室,每个人都在开心地交谈。

任何人都可以加入并提出问题,甚至报告错误或一些不起作用的东西。也许你觉得设计可以改进,想要给 Galio 和它的社区一个全新的外观。你可以在那里做到这一点,不用担心有人会嘲笑你或不认真对待你。

除了 Discord 服务器,我们还有 GitHub 存储库和网站。GitHub 存储库是我们保存所有与代码相关的东西的地方。这是我们维护代码、回答问题、为未来创建新的开发计划、为某些产品创建热修复,并与pull requestsPRs)一起工作的地方。

PR 是指当有人想要帮助一个库时。所以,他们首先创建一个fork,这是克隆某人的存储库的行为。然后,他们进行自己的修改,然后新的存储库副本被提交为PR。然后由管理员验证并根据代码是否符合规则以及是否符合开发计划的一部分来接受或拒绝。

我们的网站主要是我们想要展示人们的应用程序和有关 Galio 的新闻的地方。这是我们向世界展示 Galio 的地方,但也是我们保留整个库中非常重要的部分的地方:文档。

文档是您随时想要了解有关特定组件或如何使用 Galio 功能的更多信息的首选位置,例如……GalioTheme功能。

与 Galio 相关的所有内容,如颜色、大小和布局规则,都存储在我们的默认主题中。这可以在我们的库内部的theme文件夹中找到。每个组件都从该文件中继承其样式规则。最酷的是,您实际上可以使用我们的主题组件,仅重写您想要修改的内容来重写我们的主题文件。

例如,假设您想要为primary设置不同的颜色代码。您可以用自己的颜色覆盖我们的主色,并将其与 Galio 一起使用,就好像它一直存在一样。

要使用 GalioTheme 功能,您需要从我们的库中导入themewithGalioGalioProvider。让我们举个小例子:

const customTheme = {
  SIZES: { BASE: 18, } 
  // this will overwrite the Galio SIZES BASE value 16
  COLORS: { PRIMARY: 'red', } 
  // this will overwrite the Galio COLORS PRIMARY color #B23AFC
};
 <GalioProvider theme={customTheme}>
  <YourComponent />
</GalioProvider>

这将创建一个包含两个键SIZESCOLORScustomTheme对象。如果您只想修改颜色,您可以只使用特定的键。然后,您需要使用我们的高阶组件HoCGalioProvider来封装您的组件。我们还需要通过theme属性将新的customTheme对象传递给 Galio。

提示

HoC 是一种高级的 React 功能,可以更容易地定义为返回一个组件并以某种方式改进该组件的函数。假设您是托尼·斯塔克,HoC 就是钢铁侠套装。套装由铁手套、靴子、盔甲和头盔组成,而穿上铁靴的托尼可以飞行。

现在,customTheme常量将覆盖默认的 Galio 主题常量。

但是等等——也许您不想改变我们的主题,而是想在样式中使用我们的常量。使用我们的设计系统可能有助于更快地设计布局,我们总是在为客户创建的不同产品中使用 Galio 的常量。

使用withGalio函数导出 React 组件使您的组件能够使用 Galio 的 React 上下文,并将主题作为属性或作为styles对象的参数传递给您的组件。让我们看看如何做到这一点——我相信您会理解的:

const styles = theme => StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: theme.COLORS.FACEBOOK
  }
});
export default withGalio(App, styles);

因为我们使用withGalio函数来导出我们的组件,Galio 将向我们选择的对象(在本例中是styles)传递我们库中所有的常量主题变量。因此,我们能够在我们的styles对象内使用theme作为参数,并将backgroundColor属性更改为我们库中的 Facebook 颜色。

您可以在我们的文档网站上找到有关我们常量的所有信息的表格,网址为galio.io/docs

正如你所看到的,Galio 充满了许多很酷的功能,将帮助我们极快地开发任何移动应用,并最终使其看起来非常漂亮。那么,为什么不试一试呢?我们将从现在开始使用 Galio 编写所有项目。这将成为本书中每个应用程序开始时的强制导入。我们将使用更多的 Galio 组件,而不是 React Native 的组件。

因此,我们将学会如何使用 Galio,如何设计出色的应用程序,直到我们能够开始编写自己的想法。也许我们中的某个人实际上会创建一个对社会有很大价值的伟大应用程序——这将改变世界。

梦想着我们掌握更多知识后能做多少事情真是件美好的事情。这种白日梦和对目标的持续关注将成为学习编码的最强大武器之一。

总结

在本章中,我们已经通过多个示例说明了 Galio 为何是如此出色的库。到最后,你一定已经意识到 Galio 真的应该成为你的库之一——一个库来统治它们所有。这将成为你的主要包,你将用它来创建令人惊叹的应用程序,无论是视觉上对我们的用户,还是对想要帮助我们编写代码的编程伙伴。

不要害怕查看 Galio 的核心代码。你可能会从体验和理解 Galio 的代码中学到很多东西。你甚至可能能够创建自己的库。

因此,我们发现 Galio 真的很酷,因为代码易于使用。我们只有一些可以改变整个世界的属性,无论是编码速度还是对特定参数的轻松访问。我们还看到了 Galio 开箱即用的优势。我的意思是...这个库很华丽。有时,我甚至不会编辑样式;我只会使用 Galio 样式,因为它们看起来很棒。

我们还看到使用Block组件创建布局有多么容易,以及只要我们了解与Block组件配套的一些属性,放置对象在屏幕上就比我们想象的要容易得多。

之后,我们讨论了 Galio 拥有一个多么伟大的社区,以及我们如何参与其中。虽然这超出了本书的范围,我们并没有深入研究 GitHub,但我们确实学到了很多关于这个社区的运作方式以及我们如何参与其中。

最后,我们讨论了 Galio 的一些更高级的功能,或者更准确地说,使用了 React 的更高级功能,因为如果我们想要从 Galio 中使用它们,它们真的很容易使用。

最后,我们可以说 Galio 为每个人进入移动开发世界创造了一条简单的途径,我想可以说我们都对它的存在表示感激。

接下来的章节将涵盖移动 UI 的基础知识。我们将学习如何为我们的应用构建一个清晰的 UI,同时学习一些关于如何为用户提供最佳用户体验的指导方针和规则。

第六章:移动 UI 构建的基础知识

既然我们更了解 Galio 如何帮助我们构建跨平台移动应用程序,现在是时候学习一些关于设计的规则,以便我们可以最大限度地利用这个框架。

本章将浅显地介绍一些设计概念和准则,这些将帮助我们至少在设计技能上更有信心。我希望这一章能给你带来信心和动力,去构建/创建一个美观的用户界面(UI)。

我们将首先探讨清晰设计的重要性以及我们应该遵循的一些基本准则,以确保我们的设计尽可能清洁和简约,同时向用户提供最有用的信息。之后,我们将慢慢地进入对用户体验(UX)的基本解释,以及如何找出对我们的用户最好的内容。

一旦我们讨论完所有这些,我们将找出如何最小化用户输入,以便我们的用户不会感觉在填写表单时中途放弃。我们将讨论到到底是什么可能会阻碍我们的用户完成一个表单,以及我们如何改进我们的表单,以便完成率可能会增加。

之后,我们将看到整理我们的设计理念通常是确保我们的应用程序看起来整洁和良好的最佳方式。我们将发现如何做到这一点的准则以及创建呼吸空间的最合适方式。我们还将介绍我的创意过程,从第一次设计草稿到我认为值得实施的最终屏幕。

整理完毕后,是时候谈谈一致性了。我们将学习一致性在移动应用程序中的重要性以及原因。我们还将介绍三种不同 UI 设计工具的主要思想,这样你至少可以知道要研究什么,并形成自己对于原型设计自己应用程序的意见。

本章将涵盖以下主题:

  • 探索清晰设计的重要性

  • 最小化用户输入

  • 为了更好地组织应用程序而进行整理。

  • 保持应用程序的一致性

探索清晰设计的重要性

既然我们已经到了这一步,现在是时候学习一些关于如何为我们的应用程序创建一个好看设计的规则和准则了。现在,美是主观的,我们都知道,但有一些规则可能会在你的移动应用程序甚至你的网站内创造更好的流畅性。

我们并不是试图透过客观的镜头来审视美是什么,但美的某些方面与我们的大脑以及它的构造直接相关。例如,颜色在不同文化中可能有不同的含义,这没关系,因为我们不会去选择黄色而不是黑色。

与此同时,我们可以采用三分法,这是用于创建视觉艺术作品如电影、绘画或照片的经验法则。关于三分法的一点是,我们发现由于某种原因,当我们将屏幕分成两部分,水平和垂直各占三分之二后,我们的眼睛更加关注照片的主题当它位于两条线的交汇处。你可以现在就尝试一下。你的手机很可能已经在相机应用程序中内置了这个功能,所以试着拍一张主题在中心的照片,然后再拍一张主题在交汇线处的照片。

当然,这并不意味着我们所有的图片都必须遵循三分法,但在大多数情况下这会有所帮助。问题在于还有其他因素需要考虑,比如阴影、对比度、亮度等等。

解释这一切的整个目的是让你明白,设计的某些方面可以向我们的用户展现“美”的概念。

其中一个重要的方面实际上是清晰设计的重要性,以及它如何帮助我们直接传达移动应用程序的目的。我并不是在创造一个热爱极简主义的团体,但我确实觉得在当今时代,极简主义变得更加重要。在一个有如此多选择的世界中,用户喜欢信息直接,他们不想要在网站上滚动浏览大屏幕的信息和干扰,才能找到重点。

“设计不仅仅是外观和感觉。设计是如何运作的。”

  • 史蒂夫·乔布斯

那么,拥有清晰的设计到底意味着什么呢?还记得那些在 2000 年代甚至 2010 年代充斥着不必要信息的网站吗,比如随机放置在屏幕右上角的时钟?人们不想看到你的应用或网站上挤满了……东西。他们实际上更喜欢更简约的方式,使其看起来更时尚、更酷,并避免让用户通过多个页面的废话来达到他们的目标,也许只是找出你的公司在哪里。

让我们实施一些规则,这样我们就不必处理那种噩梦般的应用程序。

基本要素

专注于基本要素使我们能够保持简洁和直截了当。我们可以通过限制视觉元素和菜单的数量来做到这一点。如果你考虑在你的移动应用中使用下拉菜单,最好现在就停止考虑,也许开始考虑如何将你的应用划分为适用于底部选项卡导航器之类的类别。

配色方案

让我们诚实点。我们都喜欢颜色!我们喜欢!它们很漂亮,每当我们和朋友一起出去玩或者只是一般地玩得开心时,我们总是在纠结该穿什么。那是因为并不是所有的颜色都能搭配在一起,有时如果你选择超过 10 种颜色,人们就不知道该把注意力放在哪里了。

网站和移动应用也是如此。我们应该将我们的颜色使用限制在三种颜色之内——当然,在必要时应用不同的色调——但是在我们的应用程序中只有三种主要颜色,我们可以创造一种连贯性。

假设一个屏幕有一个绿色的“提交”按钮。另一个屏幕有一个紫色的“提交”按钮。一旦用户看到这一点,他们会立刻想:“那是正确的按钮吗?”一旦你为某些事物的外观创建了规则,就要坚持下去!

可用性和可访问性

这实际上非常关键。你的移动应用设计必须能够在你的目标受众感兴趣的所有分发平台上运行。我实际上会说,现在,在今天的市场上,至少在 iOS 和 Android 上拥有你的产品是强制性的。

问题是,因为这些平台是以不同的方式构建的,并且具有不同的用户体验,你必须为每个平台适应你的产品。你做得越好,越多的人会喜欢使用你的应用。

此外,我们已经进入了 2021 年,因此您应该实现对屏幕阅读器的支持,例如 iOS 的VoiceOver或 Android 的TalkBack。这将使您对自己感觉更好,因为您不仅为每个人创造了更好的数字世界,而且通过为您的应用程序提供更广泛的受众,您将有更好的机会将您的想法发展成成功的想法。

简单

我无法再强调这一点了,但你需要专注于重要的事情。你不需要在一个屏幕上列出你的应用程序可以做的每一件事。尽量保持简短。没有人有时间真正阅读页面上的所有信息,因此尽可能少地提供信息,同时使其尽可能有意义,这是简单的关键。

信息架构

每个与您的应用程序交互的用户在首次使用您的应用程序时都会表现出预先构建的行为模式。研究您的竞争对手,并确保这种行为不会妨碍您制作应用程序的创意过程。例如,他们可能期望特定按钮,比如开始按钮在闪屏界面内,总是在屏幕底部。您的工作是确保您会利用这些行为,并且如果您想为用户创建某种新的 UX,花时间教他们如何使用您的应用程序。

一致性

确保您的设计和信息在整个应用程序中保持一致。通过保持一致,您可以确保您的用户永远不会出现不理解发生了什么或如何使用您的应用程序的时刻。通过保持一致,我们实际上教会了我们的用户使用我们的平台的最佳方式,而无需额外的乏味文本。

用户体验

您可能已经注意到了短语用户体验UX),但我们并没有真正定义它。UX 指的是产品(网站或移动应用程序)如何满足用户的需求。

我们应该区分 UX 和可用性,因为后者是 UI 的质量属性,涵盖了系统学习的容易程度或使用的效率。

在设计移动 UX 设计时,我们可以牢记的一个好的经验法则是问自己以下问题:移动应用程序有用吗?

如果没有,我们可以说对最终用户没有价值。

如果答案是肯定的,但不够直观,最终用户不会花时间去学习它。

移动用户体验设计涵盖了三个重要方面:可访问性、可发现性和效率。这导致了快速、积极和以体验为驱动的最终结果。

Net Solutions2020 年 B2B 商务状况报告指出65.8%的企业将在未来 12 个月内投资于改善移动用户体验设计

基于这些数据,我们应该意识到用户体验是一门永无止境的科学。我们永远不会拥有完美的用户体验——随着用户的变化,这将会发生改变。随着时间的推移,我们可能会在使用手机时改变我们的行为,因此您的设计师需要为最终用户设计出一个出色的体验,以满足特定时间的特定用户的期望。

现在自然的问题应该是:*我们应该如何处理这个问题,以便我们始终能够为用户提供高质量的用户体验?*我认为,对于构建出色的用户体验,以下部分提到的方法将为您带来最佳结果。

研究

花费多天时间与最终用户在一起。了解他们的需求,以及他们对目前工作方式的真实感受。倾听他们,因为他们的反馈是整个过程中最重要的部分之一。

例如,如果你看看家里年长的成员在使用应用时,你会注意到他们对应用的某些部分非常容易感到沮丧。观察他们,看看他们期望什么。他们可能会说类似于“为什么通过这个应用订购东西这么难?”然后紧张地随意在屏幕上点按,因为事情并不完全符合他们的期望。你周围的人,尤其是那些被应用所针对的人,可以为你提供最宝贵的信息。

共情

与用户讨论并了解他们的需求后,就是找到解决方案的时候了。使用任何对你最有帮助的方法来整理这些想法,并尝试找到解决用户遇到的问题的方法。你需要注意,以免制造更多问题,所以在找到解决方案后要测试你的应用。

构建

嗯,这是不言而喻的。一旦一切都经过测试,你已经找到了所有问题的解决方案,就该是构建应用的时候了。问题是……根据你的研究,你应该能够意识到你的应用真正需要哪些技术。有时,即使是 React Native 也不够用,所以你可能需要做一些改变。这是成为一名优秀程序员的一部分,所以不要担心!一旦你了解了一种编程语言和一个框架,你就可以学会任何东西。

现在我们已经经历了这一切,并且对为什么清晰的设计对我们的应用非常重要以及 UX 是如何运作有了一些了解,我们应该对为什么某些应用采用极简主义路线并为所有用户提供直接的学习路径有了相当清楚的想法。

现在,让我们讨论为什么最小化用户输入很重要,这是确保我们有清晰设计的另一个部分,以及我们如何做到这一点。

最小化用户输入

许多人在填写表单时都有所犹豫,特别是当表单很长,充满了涉及他们必须搜索实际文件并填写看似无关紧要的步骤的个人信息时。

了解这一点,我们有责任为我们的用户创建一个良好的表单,这样他们在填写时不会觉得这是一项琐事。任何表单的主要目标是完成。为此,我们首先需要了解有效表单的主要概念。这些内容在这里介绍:

  • 复杂性的感知:每当我们面对一个表单时,我们首先要做的是视觉扫描,以便估计需要多少时间才能完成。了解这一点,我们几乎可以立即意识到复杂性的感知在完成表单中起着至关重要的作用。看起来越复杂,用户完成的可能性就越小。

  • 交互成本:这是完成表单所需的所有努力的总和。用户付出的努力越多,他们完成的可能性就越小。想象一下一个有 bug 的表单,你无法添加你的出生日期,或者添加起来不直观。你可能会失去注意力,对表单感到生气,以及它有多难以使用。最终,你可能根本无法完成它。这种有缺陷的交互会让用户对应用程序和表单本身产生负面印象。这种缺陷会让用户忘记设计有多漂亮,或者应用程序的其他部分有多有用。

现在我们知道用户实际上会如何考虑我们的表单,让我们看看我们应该遵循哪些准则,以便我们能够创建一个高效的表单设计,所有用户都能够遵循和完成。考虑以下几点:

  • 通过提出正确的问题减少用户的努力:表单中的问题应该按直觉的顺序排列,并且从用户的角度看应该是逻辑排序的。在考虑提出问题的顺序时,我们总是从姓名、出生地和个人信息开始。这是因为这就像一次对话。不要只因为你的数据库或应用逻辑有不同的提问顺序而妥协——用户是第一位的。我们作为程序员的工作在用户对应用程序的实际工作方式一无所知时表现得最好。

一个很好的经验法则可能是不断地问自己为什么以及你请求的信息是如何被使用的。

  • 单列布局:双列布局对我们的表单来说最大的问题是你不知道用户会如何阅读信息。为了使这更容易,只使用单列应该对用户来说是直观的,他们会明白自己首先必须完成屏幕顶部的任何问题。

  • 尽量使用较少的输入字段:想象一下,你想要订一次航班,但它要求你提供关于整个旅程的所有信息。你只是想查看价格,看看自己是否能负担得起下个月去巴哈马的航班,但你看到的表单却和整个屏幕一样大。你会看着屏幕,也许会觉得自己并不真的想去巴哈马,至少不想和这家预订公司一起去。

尽可能少地使用输入字段不仅意味着从表单中删除不必要的问题;你还应该考虑不同的方式来提出这些问题。例如,不是为出发日期(日、月、年)设置三个输入字段,而是使用一个日期选择器和一个输入字段可能更容易。另一个使用其他类型的表单元素的好例子可能是,不是为乘客人数设置下拉菜单,而是使用一个“+”和“-”按钮。这将使内容更具互动性,对于试图快速填写表单的用户来说更少具威胁性。

  • 输入框的正确宽度:这种情况经常发生。我正在网上订购东西,然后他们要求我填写街道地址和门牌号码。这显然意味着我应该在一个输入框中写街道名称,然后在另一个输入框中写门牌号码。问题是街道输入框非常大。这让我感到困惑,我在想:“除了街道名称,我还应该写些什么吗?”这种情况不应该发生;如果你知道用户应该写邮政编码,尽量让邮政编码输入框尽可能大。使它比必要的尺寸更大可能会让用户感到困惑,我们不想让用户感到困惑。

  • 顶部的标签:将输入标签放在文本输入框的顶部可以更容易地跟踪表单。假设我们将它们放在屏幕的左侧;这会使你的眼睛来回移动,这似乎并不是太大的工作,但我们试图设计尽可能清洁和直接的设计,所以任何能帮助用户感觉我们的表单不会太困难的东西都会对我们有利。

  • 可选和必填字段:我们知道,我们应该尽量避免在表单中使用可选字段,因为它们会使表单变得比必要的更长,但有些情况下,如果我们想要为我们的营销团队获取更多信息,或者可能我们只是需要结账表单的第二个地址,那么一些可选字段是必要的。如果它们对我们来说是必要的,那么我们最好让它们真的明显地表明它们是可选的而不是必填的。你可以在标签旁边写上“可选”,但确保它是可见的,绝对不是隐藏的信息。

  • 高度可见的错误消息:当我在表单中出错但不知道出了什么问题时,我真的很讨厌这种情况(而且我不是唯一一个)。一切都变成了一个谜题:“是密码吗?”“是邮箱吗?”“我哪里错了?”通过为每个输入表单提供清晰可见的错误消息来避免这种情况。

这些消息必须仅通过扫描屏幕就能看到。为此,您可以使用任何可用的东西,无论是图标、颜色还是文本。

在用户完成表单后通知用户有错误的时间是他们完成表单之后。不要在他们填写表单的过程中打断他们,告诉他们有错误,因为这可能会让一些用户感到非常恼火。

使用这些准则应该确保我们有一个真正好的表单。但这并不止步于此。每种情况都是不同的,所以不要害怕打破规则或想法。设计应用程序的很酷的一点是,你的想法和任何人的想法一样重要。当你试图与众不同时,最好的做法是始终问自己:“这如何改善我的用户体验?”如果找不到答案,最好还是坚持这些主要想法,或者从设计书籍或心理学书籍中找到新的想法。

到目前为止,我们已经讨论了为用户设计一个干净的设计和一个漂亮的表单。我们应该开始考虑创建我们设计的另一个方面——精简。

为了更好地组织应用程序而进行精简

在向用户显示相关信息和保持界面尽可能清洁和简洁之间总是存在问题。当我们说精简时,我们指的是设计的视觉和可读性方面。

在桌面网站上,混乱是可怕的,但在移动应用上更糟,因为屏幕尺寸要小得多。摆脱任何绝对不必要的信息是至关重要的。

因此,让我们看看如何在我们的应用程序中做到这一点。我们可以参考我们在第四章中创建的第一个屏幕,您的第一个跨平台应用程序,如下所示:

图 6.1-我们创建的第一个屏幕

图 6.1-我们创建的第一个屏幕

正如你所看到的,我们的应用程序已经填满了用户所需的唯一重要信息:最近玩过的游戏、最常玩的游戏、他们的名字和等级。但当我开始开发这个屏幕的想法时,实际上是从一个充满信息的屏幕开始的。我的屏幕看起来真的很乱,有很多不必要的信息,但出于某种原因,我认为这可能与我们的用户相关。

让我们看看之前的样子,然后试着注意我是如何将它整理成最终形式的,如下所示:

图 6.2 - 我们清理之前的屏幕

图 6.2 - 我们清理之前的屏幕

我知道,你的第一反应是“呃”,这是完全可以理解的。这个屏幕看起来充满了太多东西。而且,感觉就像没有呼吸空间,信息占据了所有可用的空间。

让我们一步一步来看看我是如何从最初的想法(图 6.2)到最终的产品的。我们将尝试理解我的创意过程中到底发生了什么,以及我们是如何清理屏幕的。它是如何演变的:

  1. 空白

屏幕边缘和主要内容区域之间的空间被称为排版中的“边距”。即使你写一个 Word 文档,也总会有一些空白空间;我们不是把东西从纸的一边写到另一边。尽管我有 8 像素(px)的边距,但它仍然感觉不对劲。我觉得需要更多的空间,所以我将边距增加到 32 像素。

这限制了我们的内容,让我们有更少的空间来工作,但一切看起来都有了更多的呼吸空间。这是一个公平的交换;少一些信息并不总是坏事,特别是在评估屏幕内容之后。

  1. 删除不必要的信息

一旦我们确定了在这个特定屏幕上用户不绝对需要的信息,就是时候将它们移除了。起初,我认为一个漂亮的小图表会很酷,但看到它占据了多少空间,我意识到对于我的假设应用程序来说,最好是将那个图表视为用户可以通过点击他们感兴趣的游戏来查看的东西。

同样的道理也适用于他们上次玩这些游戏的日期。这些在第一眼看来并不需要,因为一旦他们真正对该游戏的统计数据感兴趣,他们可以在另一个屏幕上看到它们。所有这些信息都可以轻松地在另一个屏幕上实现,那么为什么我们要把它放在第一个屏幕上呢?

  1. 对齐

现在我们已经去掉了一些元素,并且我们选择了距离屏幕边缘到内容区域的 32 像素边距,是时候为对齐创建一些规则了。首先,我想我们应该让所有东西对齐到屏幕的左侧。如果我们打破这个规则,突然在屏幕中央有一个标题文本,我们的用户可能会觉得有些不对劲。

现在我们已经选择了文本对齐的位置,是时候在整个应用程序中保持这一点了。

  1. 一致性

例如,在图 6.1中,我们的三个主要类别(标题,最常玩的游戏和最近玩的游戏)之间有相等的空间,最近玩的游戏标题下显示的游戏之间也有相等的空间。所以,我们选择了两种不同的大小,赋予它们意义,然后在需要时使用它们。想象一下,如果一个游戏标题距离底部只有 2 像素;也许你不会立刻注意到,但你会觉得有些不对劲。

颜色也是如此。我们选择了三种主要颜色,赋予它们意义,然后保持一致性。这也适用于其他屏幕——相同的边距、颜色和对齐。这就是我们确保我们的屏幕永远不会对某人显得奇怪的方法。

完成创意过程后,我会看一看之前和之后的版本,试着判断哪个版本更好。另一个好的判断标准可能是亲戚或朋友,所以不要害怕与其他人分享你的作品,看看他们的想法。

我的初始设计总是会与我实际实施的不同,因为在我看来,你对某件事的第一印象总是受到当时周围发生的事情的影响。最好退后一步,让所有信息围绕着你。之后,你可以更准确地评判你的作品。

一旦我们确定了设计,我们应该能够在整个应用程序中保持规则。这就是一致性,这是我收到的最好的建议之一。

在应用程序中保持一致性

一致性是一种非常有帮助的东西,无论是在设计还是我们的个人生活中。我已经学会了保持一致对于健康、成功的生活至关重要。保持一致是让我从 A 点到 B 点的关键,我相信这适用于生活的每个方面。保持一致是关于体验的。

从我们的移动应用程序的主屏幕慢慢进展到最后一个屏幕是用户需要享受的体验。只有通过避免混淆和减少用户的学习量,才能享受这种体验。

让我们看看如何在设计中实现一致性以及处理一致性问题的适当方式。

设备用户界面指南和行为

iOS 和 Android 有不同的用户界面和不同的可用性指南。你最好熟悉它们。通过识别平台之间的差异,我们可以确保我们的应用在每个特定平台上都能正常工作和运行。尽管设计必须相似,但用户实际使用这些平台的方式有所不同,因此你要确保你的应用不会让用户学习不同的使用模式。

意义

有些应用程序的某些方面我们不希望被改变。想象一下,在结账过程中有一个蓝色的提交按钮,然后在注册表单中有一个红色的提交按钮。这会造成混淆。

一旦我们赋予颜色和按钮意义,重要的是无论用户使用哪个屏幕或平台,都保持相同的意义。如果你来自网页开发行业,你可能知道 Bootstrap。Bootstrap是 Twitter 创建的一个带有颜色、层叠样式表CSS)类和网页设计指南的 UI 库。例如,他们确定了一种蓝色作为信息的颜色。这就是他们保持一致性的方式。

另一个很好的例子是,在我们在[第四章](B17074_04_epub_Final_SB.xhtml#_idTextAnchor070)中开发的屏幕中,你的第一个跨平台应用,我选择了屏幕边缘和主要内容之间的 32 像素的边距。如果我们要开发另一个屏幕,我们必须保持相同的约束。

语言

我相信我们都知道收件箱、提交、垃圾邮件和删除这些词的意思。这些词是被所有应用用户普遍接受和了解的。仅仅为了改变而改变这些词需要用户开发另一层理解并学习这些新词。为了保持一致,我们将确保所有这些词在我们的应用中具有相同的含义。

当然,单词列表远不止这些,但一个很好的经验法则是问自己以下问题:“我是否曾经在另一个应用程序的不同上下文中看到过这个单词或图标的使用?”如果答案是“是”,你可能需要重新考虑你设计应用程序的方式,或者至少是语言方面。

在讨论了所有这些一致性和清晰设计的准则之后,我认为我们应该探索一些可能帮助你设计完美移动应用的不同软件产品。众所周知,有 Adobe Photoshop,它几乎在设计的各个方面都被广泛使用,无论是网页、移动还是独立游戏的像素艺术。但我们不会深入探讨 Photoshop 之所以如此重要的原因,因为我们可以使用其他更简单学习和更便宜的产品。

Figma

Figma 是一个几乎兼容所有浏览器的工具。这使它成为一种独特的设计工具,因为它是基于浏览器的。你不需要担心安装它的最新版本或处理兼容性问题或版本问题。它也是一个协作工具,所以你可以加入设计你的项目的团队。

价格是免费的,但为了获得更好的功能,需要进行月度订阅付款。这是一个非常好的工具,很多人喜欢使用它。

Adobe XD

Adobe Experience DesignXD)是 Sketch 的直接竞争对手。因为 Sketch 只在 macOS 上运行,XD 是 Windows 用户的替代选择。当然,它在 macOS 上的运行效果和在 Windows 上一样好。对于初学者来说,它非常快速和易于使用。它拥有 Sketch 的所有功能,比如线框设计、原型设计等等。

这是一个免费工具,但也可以按订阅模式供公司使用。

Sketch

Sketch 是一款非常轻量级的设计工具,被视为设计师的行业标准原型工具。一旦你想要更深入的关于设计的教程,你会发现 Sketch 比你想象的更常见。它与 Photoshop 非常相似,但它的重点是在图形设计上。

Sketch 现在的价格是 99 美元(USD),还有 30 天的免费试用期。我强烈推荐尝试这个工具,因为它是整个行业中使用的标准工具。

我不得不说,我个人最喜欢的是 Sketch,但在不得不在 Windows 上设计之后,我开始尝试使用 Adobe XD。现在,我用 XD 做所有的事情。我甚至在这本书中找到的屏幕和示例图片中使用了它。我喜欢你可以在上面进行原型设计,我完全推荐在选择你最喜欢的工具之前尝试所有这些工具。

总结

本章充满了关于如何为我们的移动应用程序保持良好清洁设计的信息。我希望到最后,你至少理解了一些,因为毕竟,我们不是设计师,我们是程序员。不过,我认为,至少对其他人使用的工具有一点了解,以及一些基本规则和指导方针,将对你成为一个更好、更有准备的程序员有很大帮助。

我们了解了如何最小化用户输入,并创建具有更高完成率的出色表单,以获得出色的用户体验。我们还学习了一些关于如何以更合乎逻辑的方式创建这些表单的规则,以便我们永远不会让用户感到困惑。

之后,我们学习了如何简化我们的设计,使其看起来有更多的空间,我们看到了我从屏幕设计的第一稿到最终结果的创作过程。

在了解一致性以及它的确切含义之后,我们探讨了每个设计工具的主要思想,以便你能够选择最适合你的工具。

希望你对下一章感到兴奋,因为我们正在更接近理解和创建实际的酷小应用程序。我们将开始学习关于我们应用程序的状态以及如何使用它来动态地改变应用程序中的信息。

第七章:探索我们应用程序的状态

在经历了关于如何构建应用的许多不同想法之后,是时候为我们房屋的基础设置最后的石头之一了。在本章中,我们将了解状态是什么,更重要的是,状态在 React 应用程序中是如何工作的。

我们将对状态的基本定义进行讨论,以及它在 React 应用程序中的传统用法。我们还将了解一些新的现代状态使用方式以及它们的工作原理。我们将不得不自己决定哪种状态最适合在我们的特定情况下使用,但当然,我会给出我的建议。

然后,我们将把所有新的信息应用到一个实际的练习中,这将帮助我们巩固我们的大脑中的这些新概念,以便我们能够正确理解我们所涵盖的一切。

在实际练习之后,将是时候看一些不同的钩子以及它们究竟是什么。我们将了解在类组件中使用状态与使用钩子如何帮助我们编写更少的代码之间的区别。我们还将了解另一个处理生命周期函数的钩子。所有这些将帮助我们在 React Native 和 Galio 中创建更复杂的应用程序之前继续学习,并且在创建更复杂的应用程序之前,这对我们来说是必不可少的。

本章将涵盖以下主题:

  • 什么是状态?

  • 升级我们的屏幕

  • 其他钩子及其相关性

技术要求

您可以通过访问 GitHub github.com/PacktPublishing/Lightning-Fast-Mobile-App-Development-with-Galio 来查看本章的代码。您会发现一个名为Chapter 07的文件夹,其中包含我们为本章编写的所有代码。为了使用该项目,请按照README.md文件中的说明进行操作。

什么是状态?

现在我们已经到了这一步,对于我们继续前进来说,了解状态是什么以及它在 React 组件中是如何工作的是至关重要的。一旦我们学会了这一点,我们将完全能够充分利用 React 的能力。这将解开我们迄今为止一直缺少的环节,更确切地说,它将解开使我们的移动应用程序更加动态的关键。

我们在第三章中学习了props。这是我们用来从一个组件传递数据到另一个组件的技术。将 props 视为组件的第一层。我们需要提升我们的组件创建技能,所以在进入任何实际挑战之前,现在最合乎逻辑的步骤是学习关于状态的知识。

传统上,为了能够在组件中使用状态,我们必须使用类组件。在 React 的后续版本中,我们还可以使用一种叫做hooks的东西,在函数组件中使用状态。在学习状态的基础知识之后,我们将讨论 hooks,而为此,我们必须从类组件开始。

但是什么是类呢?类是创建对象的模板。对象通常用于面向对象编程。尽管 JavaScript 不是基于类的面向对象语言,但它仍然有使用面向对象编程的方式。

让我们看看在 JavaScript 中如何创建一个类,以及在 React/React Native 项目中它需要什么才能正常运行:

图 7.1 - React 中类组件的代码

图 7.1 - React 中类组件的代码

这与函数非常相似,但它没有任何参数,而且我们可以看到那里的extends单词。关键字extends基本上是用来让类知道它应该从另一个类继承属性;在这种情况下,另一个类是React.Component。所有类都需要从React.Component继承,以便该类可以作为 React 组件使用。

我们还看到了render()函数。这个函数是 React 组件所必需的。这是我们编写所有 JSX 的地方。现在,还有另一个函数我们应该使用。这是在使用类创建新对象时调用的函数。

现在我们已经学会了如何创建一个类,是时候进入状态了。让我们看看如何将状态添加到我们的App类组件中。为此,我们需要在App类中创建另一个名为constructor()的函数:

图 7.2 - 添加到我们类中的构造函数

图 7.2 - 添加到我们类中的构造函数

重要提示

在基于类的面向对象编程中,构造函数是一种特殊类型的函数,每当我们创建一个对象时就会被调用。它通常接受参数,以便以任何我们想要的方式自定义初始化一个新对象。

如你所见,这个函数接受一个参数props,这使我们能够使用这个组件可能接收的 props。构造函数中的super()函数是一个关键字,用于访问并调用对象父级的函数。这个函数必须在使用this关键字之前使用。

正如我们所看到的,我们的状态变量前面有一个this关键字。这个关键字指的是它所属的对象。它基本上指的是状态变量只与这个对象相关联,所以你不能直接从另一个对象访问它。

现在让我们看看我们如何在render函数中使用它。这与我们使用props的方式完全相同:

图 7.3 - 在渲染函数中使用的状态

图 7.3 - 在渲染函数中使用的状态

正如我们所看到的,我们仍然使用this关键字,以确保状态变量在渲染时指的是这个特定的对象。现在应该在屏幕上显示的消息是大家好!我今年 24 岁了!

这与我们一直在使用的props非常相似,但到底有什么不同呢?

实际的区别在于状态是局部的,而props是我们从一个组件传递到另一个组件的东西。另一个区别是,因为状态是一个局部变量,我们可以在组件内部改变它,唯一需要重新渲染的是特定的组件。而props的情况是,一旦我们更新了一个 prop,使用该 prop 的所有子组件都需要重新渲染,这会给我们的应用程序带来一些压力。

什么是状态?

在计算机科学中,只要系统被设计为记住先前的信息,就被称为有状态的系统。被记住的信息被称为系统的状态。

这并不是说状态props更好。它们都有各自的目的,当构建应用程序时,你会使用所有这些概念。有时,你需要状态,我们将看一些使用两者的例子,这样我们就可以更好地理解它们的工作原理。

那么我们如何改变这个变量呢?你们中的一些人可能自然地会想到“嘿,这很容易 - 就像平常一样改变变量”,然后你会尝试像这样做一些事情:

state.age = 54;

但这并不会真正起作用。你可以尝试在组件内部进行操作,但你不会看到任何变化。状态将保持在你的屏幕上为24,组件不会重新渲染。React 状态应该被视为不可变的。在编程世界中,不可变对象是指在创建后无法修改的对象。

实际上,我们有一个 React 函数为我们实现了setState()。这有助于我们用另一个状态替换状态,因此我们实际上并没有修改主变量;我们实际上是用另一个变量替换了变量。

因此,如果我们想要改变年龄,我们需要写类似这样的东西:

this.setState({ age: 54 });

现在,这似乎相当容易,但我们到底在哪里改变状态呢?嗯,有很多地方可以改变状态,但这取决于你的应用程序以及你希望它如何工作。假设我们想在组件在屏幕上渲染时立即改变年龄。React 为我们的类组件提供了一些称为生命周期函数的特定函数。

这些函数在组件生命周期的特定时刻被调用。我们将讨论其中的两个:componentDidMount()componentWillUnmount()

这些函数确切地代表了它们的名字所暗示的。第一个函数在我们的组件已经挂载(渲染)到屏幕上后被调用。第二个函数在组件需要从屏幕上移除时被调用。因此,我们在组件生命周期中有这些时刻,我们可以插入代码来确保组件的行为符合我们的期望。

显然,如果我们想要在组件渲染后改变年龄,我们必须使用componentDidMount()函数:

图 7.4 - 在我们的类组件中使用 componentDidMount

图 7.4 - 在我们的类组件中使用 componentDidMount

现在当我们打开应用程序时,我们会看到大家好!我今年 54 岁!。但实际上状态在渲染开始时是24,一旦渲染完成,状态就变成了54。所以,这真的很酷,我们有很多不同的新功能和属性。我完全建议你阅读更多关于 JavaScript 类如何工作的信息,如果有任何你觉得不太理解的地方。你可以通过访问 Mozilla 的网站来做到这一点,那里充满了有关 JavaScript 的有趣信息:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes。只是让你知道,很多人在this关键字的工作方式以及状态的确切工作方式上遇到问题或感到困惑。我觉得一旦你更多地了解 JavaScript 的工作原理,这种困惑就会消失。

现在让我们运用到目前为止学到的知识,进行一个有趣的小实践。我们将开始使用状态,使我们的屏幕看起来更加动态,而不仅仅是我们通常的静态屏幕。

升级我们的屏幕

让我们看看我们要创建什么样的应用程序。我在想我们可以有一个屏幕,显示我们当前的年龄,包括月份、天数、小时和分钟。我是说,那挺酷的,对吧?每当有人问起你的年龄,你就可以从口袋里拿出手机,展示你创建的屏幕。让我们开始吧:

  1. 让我们打开终端,并像往常一样使用以下命令创建一个新的expo托管项目:
expo init RealAge

现在让我们打开项目并开始编写一些代码!

  1. 现在让我们直接打开App.js文件,除了导入和样式表之外,删除里面的所有内容。我总是保留样式表,因为我喜欢居中的文本。

  2. 现在让我们将App组件重写为class组件。图 7.5 - App.js 重写为类组件

图 7.5 - App.js 重写为类组件

  1. 现在让我们通过终端内使用以下命令打开我们的 Expo 应用程序:
expo r -c

我总是使用这个命令来清除缓存。这样,我就确保缓存不会干扰我的更改。

  1. 现在 Expo 服务器已经打开,就像我们学到的那样,打开你选择的模拟器。一旦你的应用程序打开,你应该能在屏幕上看到我的真实年龄是:的文字。

  2. 现在让我们将我们的年龄作为App类组件内的状态集成进去。

就像我们之前看到的那样,我们需要在类组件的所有其他内容之上编写我们的constructor()函数。不要忘记关于super(props)这一行 - 这很重要!然后我们将在constructor函数中创建我们的状态:

图 7.6 - 带有我们新创建的状态的构造函数

图 7.6 - 带有我们新创建的状态的构造函数

我已经提到我们将以年、月和日的形式显示我们的年龄,一直到秒,所以我在那里放了一个填满零的对象作为占位符。它实际上可以是任何东西,因为我们将在一些快速的数学运算之后更改它。

现在让我们直接进入如何计算年龄的方法。为了这个小技巧,我们将使用 JavaScript 中的Date()对象。尽管这个对象对一些人来说可能有点令人困惑,但在你了解更多关于时区的知识之后,它真的只是另一个可以玩耍的对象。别担心,我们不会深入研究 JavaScript 中的日期,因为我们有更好的东西要学习。

因此,我们将创建一个名为getAge()的新函数,它将接收您的生日日期。这个函数将获取当前时间,并从中减去您的出生日期。所有这些都将以毫秒为单位完成。之后,我们将取得的结果创建一个新的Date对象。从这个新对象中,我们将提取关于我们年龄的所有信息。

最后,我们将使用setState来创建一个新的状态,其中包含我们从Date对象中计算出的所有信息:

图 7.7 - 我们计算当前年龄的函数

图 7.7 - 我们计算当前年龄的函数

现在,你可能想知道为什么我们要减去1970年和1天。噢,正如我所说的,Date对象有点奇怪。我们必须减去1970,因为 UTC 时间从 1970 年开始,所以为了确保我们得到正确的年份值,它必须从我们的方程中消失。至于天数的值,这可能与我真的想确保时区被考虑进去有关,我的时区需要那个-1。事实上,即使我们少了 1 天,重要的是要看到这个东西真的起作用。

现在我们有了这个函数,并且我们正在使用setState函数来正确地改变状态,是时候从某个地方调用这个函数了。正如你所知,一个普通的函数不会自己调用(尽管有一些函数可以做到这一点)。

所以,让我们做和之前一样的事情 - 让我们在componentDidMount()中调用我们的函数,就像这样:

this.getAge(new Date("June 29, 1996 03:32 UTC+2"));

正如你所看到的,我使用了关键字this来确保我们的对象知道我们正在引用它的函数getAge。我还在函数内使用了我的生日,但你可以使用你自己的生日来使这更加个人化。

我们的工作还没有完成!让我们进入我们的render函数并进行一些修改,以便我们可以正确显示一切:

图 7.8 - 在我们实现状态后的渲染函数

图 7.8 - 在我们实现状态后的渲染函数

我们render函数内的第一行可能对你们中的一些人来说有点奇怪。这被称为对象解构。这就是我们之前在导入中已经做过的事情。这是一个非常有用的 JavaScript 特性,用于从对象中提取属性,甚至将它们绑定到变量上。

例如,现在我们可以在引用this.state.age.years时只说years。这节省了我们的写作时间,而且看起来也清晰得多。你会经常看到人们像这样解构变量 - 这是一个非常酷的特性!

现在我们已经确保我们将使用state内的所有变量,我们的componentDidMount正在调用我们的getAge函数,并且state是在那个函数内设置的,一切准备就绪。运行你的应用程序并检查结果。你应该能够看到屏幕上显示出你真正的年龄,甚至可以看到最细微的细节。

但有一些问题 - 秒数不会刷新,所以一切都保持不变。你可能会认为我可能欺骗了你,但相信我,我没有。现在,你的真实年龄没有更新,因为我们的getAge函数只被调用了一次。正如我们所说,componentDidMount在组件首次渲染在屏幕上时调用该函数。我们的组件渲染了,函数被调用了,故事就此结束。

我们不知何故必须让那个函数多次调用;我认为至少每秒一次,这样我们才能确保我们的秒数与真实时间同步。现在让我们来做吧!

在我们的componentDidMount函数内部,我们将调用一个很酷的函数叫做setInterval()。它接受的第一个参数是一个函数。这个函数将会以一定的时间间隔被调用。它接受的第二个参数实际上是以毫秒为单位的时间,用于执行这个函数的频率。

图 7.9 - 使用我们的 setInterval 函数的 componentDidMount

图 7.9 - 使用我们的 setInterval 函数的 componentDidMount

现在我们创建了这个间隔,getAge()函数被调用。当我们不再需要它工作时,停止间隔是一个很好的做法。你脑海中现在可能会冒出一个问题:“什么时候我们不需要它运行呢?”嗯...这通常是主观的,但在我们的特定情况下,答案是在组件的生命周期结束时。

记得我们说过还有另一个叫做componentWillUnmount()的生命周期函数吗?好吧,这正是我们要结束这个函数的地方:

图 7.10 - 在我们的 class 组件中使用的 componentWillUnmount 函数

图 7.10 - 在我们的 class 组件中使用的 componentWillUnmount 函数

现在我们已经做到了这一点,我们的应用应该准备好正确显示我们当前的年龄了。保存一切,刷新模拟器,然后检查一下!你的真实年龄现在正确地显示在屏幕上。不过,不要让这些数字毁了你的一天 - 我们都只有自己感觉年轻!

现在我们已经看到了状态在class组件中的行为,这在某种程度上是状态的传统用法,是时候看看其他使用状态的方式了。在最近,React 给我们带来了一些很酷的小东西,叫做hooks。让我们更多地了解它们,它们与传统状态有什么不同,以及它们为我们带来了什么新功能。

其他 hooks 及其相关性

状态的主要问题在于我们只能在class组件中使用它。对于一些初学者来说,类组件通常被认为有点丑陋且难以学习,因此 React 团队尝试创建一些新的东西,承诺解决初学者和高级用户在使用传统状态的类组件时可能遇到的问题。这就是hooks诞生的原因。

Hooks 是在 React v16.8 和 React Native v0.59 中引入的。它们基本上让你在不编写类的情况下使用状态和其他 React 特性。

那么,这对我们究竟意味着什么?让我们看一个示例,看看我们如何使用新的钩子功能编写状态:

图 7.11 - 使用钩子的示例

图 7.11 - 使用钩子的示例

哇!这是什么?这真的是我们迄今为止一直在使用的相同状态特性吗?是的,是的。如果你将这段代码复制到一个全新的项目中,你会发现一旦启动你的应用程序,每次你按下那个按钮,数字都会从 0 更新到你按下它的次数。

让我们看看我们到底写了什么。

正如你所看到的,我们创建了一个名为Example的函数。只要不是你的主要函数,名字并不重要,主要函数应该总是叫做App。函数看起来比类清晰得多,显然更容易编写。

然后我们使用useState()钩子在我们的函数中定义了两个变量。这到底是如何工作的呢?

const [count, setCount] = useState(0);

在这个示例中,useState是一个钩子。我们在函数组件中调用这个方法,以便为我们的组件添加本地状态。这个函数返回一对值:当前状态值 - count,以及一个可以更新该值的函数 - setCountsetCount函数与类中的this.setState函数非常相似,只是它不会合并旧状态和新状态。

useState接受的唯一参数是赋给我们的count变量的初始状态。请记住,我们的this.state变量必须是一个对象,而且一切都在那个对象里。count不必是一个对象,尽管如果你愿意的话它也可以是。

现在让我们直接比较使用this.stateuseState钩子。我们将看到相同的状态使用这两个特性写成,这样我们就可以清楚地比较这两者。

首先,我们来看一下this.state。我们想象一下有一个应用程序,需要一些关于用户的信息,一些朋友在用户个人资料上留下的评论,还有这个个人资料有多少个赞:

图 7.12 - 在类组件中编写的状态对象

图 7.12 - 在类组件中编写的状态对象

这很容易理解,对吧?我们的state有以下值:userInfo - 一个对象,comments - 一个字符串数组,likes - 一个数字。让我们看看使用hooks会是什么样子:

图 7.13 - 我们在函数组件中编写的状态

图 7.13 - 我们在功能组件中编写的状态

这和之前的例子完全一样,但我们使用了useState钩子。所有的值和之前的例子完全一样,不同之处在于我们的状态不再存在于单个对象中。

现在,举个例子,假设我们想改变喜欢的数量。也许有人点击了喜欢按钮,我们想要更新屏幕上显示的数字。让我们看看在类组件中如何改变它:

图 7.14 - 在类组件中改变状态

图 7.14 - 在类组件中改变状态

看起来复杂,对吧?除此之外,与我们一直使用的setState()函数相比,还有很多新的东西。问题是,因为我们只需要更新喜欢的数量,所以我们使用了一种叫做previous state的东西。这就是prevState的来源。一旦需要根据先前的状态来改变状态,就像我们在这里需要增加喜欢的数量一样,就必须将一个函数作为参数传递给this.setState。这为我们提供了先前状态的快照(prevState)。到目前为止,我们一直使用简化版本,因为我们不需要根据先前的状态来更新它。

现在让我们看看如果我们使用钩子会是什么样子:

图 7.15 - 在功能组件中改变状态

图 7.15 - 在功能组件中改变状态

这显然更加清晰和简单。我们知道我们只想改变喜欢的数量,所以我们使用了setLikes。在这里,我们可以取likes状态,然后将其增加1

正如你所看到的,钩子使我们的生活变得更加容易。它们非常简单易用,需要写的代码也少得多。

现在问题是,如果我们在进入hooks之前创建的应用程序,显示我们真实年龄的应用程序,我们如何能够调用setInterval函数,因为生命周期函数 - componentDidMountcomponentWillUnmount - 仅在类组件中可用。

我们很幸运,因为 React 团队为我们提供了除了setState之外更多的钩子供我们使用。首先,让我们看看什么是钩子。

正如我们所知,React 是关于代码重用的。现在,我们可以编写简单的函数,并在需要计算某些东西时调用它们,甚至编写组件以便在应用程序的任何部分重用它们,但组件的问题在于它们必须渲染一些 UI。这使得组件有点不方便。React 团队提出了钩子的想法,因为他们希望能够共享复杂的逻辑而不必渲染某种 UI。钩子让你可以通过简单的函数调用从函数中使用 React 功能。我们提供的钩子涵盖了 React 的最重要部分:状态、生命周期和上下文。

那么,让我们看看我们可以用什么类型的钩子来替代componentDidMount函数。

useEffect

useEffect钩子使我们能够从函数组件中使用副作用。什么是副作用?例如,数据获取订阅都是副作用。它们被称为副作用,因为它们可以影响其他组件,并且不能在渲染期间完成。

通常,这些操作是在类组件中使用生命周期函数执行的。你可以把useEffect想象成所有这些生命周期函数合并在一个函数中。就像useState一样,useEffect可以在同一个函数组件中多次使用。

通过使用这个钩子,你基本上告诉 React 你的组件需要在渲染后做一些事情。React 会记住你传递的函数,并在执行所有更新后调用它。useEffect在每次渲染后运行。所以基本上,它在第一次渲染后运行,并在你的组件进行每次更新后运行。

好了,那么componentWillUnmount呢?我们如何确保我们的函数只在移除组件时才起作用?useEffect就足够了,我们不需要另一个钩子。如果我们从我们的 effect 中返回一个函数,React 会确保在组件卸载时调用该函数一次。

Hooks 是 React 的一个非常重要的部分,需要大量的解释,我觉得你最好的学习方式就是阅读文档。还有其他的 hooks,比如useMemouseRefuseReducer。所以,阅读文档对所有程序员来说都是救命稻草,特别是因为你会在里面找到很多很酷的信息,我敢保证你在任何书中都找不到。当学习一门新技术时,你的第一步应该是阅读文档,然后研究其他更具体、更关键的方法来深入研究你真正想学习的东西。就像这本书一样,我们在这里学习如何构建一些 React Native 跨平台应用,所以让我们继续前进,当我们在下一章节开始使用 hooks 时,我们会更详细地解释。

总结

这一章已经涵盖了我们继续前进所需的大部分关于状态的信息。到现在为止,我们应该能够理解状态在类组件和函数组件中是如何工作的。

在学习了关于状态以及状态的确切含义之后,我们了解了一些生命周期函数以及它们的工作原理。学习这些非常重要,因为我们现在明白了一个组件会经历不同的阶段,并且在不同的时刻,我们能够干预一些 JavaScript 代码。

整个冒险给了我们一个想法,真实年龄应用。我们现在能够创建一个动态数字随时间变化的应用。我们学会了如何实现我们到目前为止学到的关于状态的一切,并创造一个展示我们年龄的绝妙想法。

因为类组件看起来有点像需要写太多代码,我们开始学习关于 hooks 的知识。经过仔细分析它们的区别,我们了解了一个叫做useEffect的 hook。

长期来看,学习所有这些将会非常有益,特别是在接下来的章节中,那些都是关于实际挑战,我们将学到很多技巧,并创建许多不同类型的 React Native 应用。