如何用Create React App构建渐进式网络应用程序(PWA)
渐进式网络应用程序(PWA)是试图表现得像本地安装的应用程序的网络应用程序。
它们可以离线工作,与本地通知系统集成,并有能力运行长的后台进程,甚至在你离开网站后还能继续运行。它们被称为渐进式,因为如果某些功能在当前浏览器中不可用,它们会平滑地降级其功能。
在这篇文章中,你将学习如何使用React构建一个PWA。由于React是一个流行的网络框架,本文首先介绍了设置和开发过程,并将其旋转起来,看看它的外观如何。在这个例子中,你将创建一个倒数计时器的应用程序。基本上,倒计时器将显示一个报价或事件的结束或开始的时间。它主要用于即将发生的销售或大事件。
使用渐进式网络应用程序模板创建一个React应用程序
在开始编码之前,请确保你已经在你的本地机器上安装了Node.js。
在你开始编码之前,你需要设置你的项目。让我们从确保你能使用React开始。
在任何使用Angular、React或Vue.js等网络框架的开发中,你都需要使用Node.js--尤其是当你希望使用库和包来协助开发项目时。
使用此类包和库的一个流行工具是Node包管理器,简单地说就是 "npm"。这个工具允许你安装/卸载软件包,使用webpack启动你的React应用程序构建,以及其他许多功能。
对于你的需求,你可以利用npm来创建一个带有PWA模板的React应用程序,这让你可以立即进行编码。每当你开始构建React应用时,你可以使用npm的 "create-react-app "命令,使用Facebook提供的模板。
让我们通过在你的终端运行以下命令来构建PWA启动器应用程序。
$ npx create-react-app appname --template cra-template-pwa
上述命令可以分解为以下内容:
- npx:npx 是一个非常强大的命令,从2017年7月发布的5.2版本开始,npm中就有这个命令。它可以让你运行用Node.js构建并通过npm注册表发布的代码。
- create-react-app:该命令启动了流行的Create React App工具,帮助你构建启动的react项目。
- appname:这是你的应用程序的标题。将应用程序命名为你想要的任何东西。这里,使用默认的 "appname"名称。
- -模板:这是一个参数。当你有一个参数时,你基本上是在同一命令中启用一个选项。在这里,你可以为我们的启动器react应用程序指定一个特定的模板。
- cra-template-pwa: PWA模板的名称,用于你的PWA反应应用
在此命令后点击 "Enter",将启动你的PWA React应用程序的构建。 它将在一个名为appname的新文件夹中生成一个React应用程序。该应用程序看起来与其他CRA应用程序几乎一样,但它将安装几个Workbox库。它将添加三个额外的源文件。在src目录中,你会发现一个例子service-worker.js、serviceWorkerRegistration.js、manifest.json脚本。
你应注意这三个文件:
- service-worker.js: 这是一个脚本,一旦你的应用程序开始运行,就在后台运行。服务工作者确保你可以离线使用你的React应用程序,并处理UI的多个请求。
- serviceWorkerRegistration.js:这个文件的工作是告诉你的服务工作者是否被成功注册。如果你查看该文件,你会注意到多个控制台日志,一旦你部署了你的应用程序,就会根据服务工作者的状态显示出来。
- manifest.json。这基本上是一个配置文件,它列出了不同的属性,你可以专门为渐进式网络应用程序进行定制。它可以决定诸如图标、名称以及应用程序显示时使用的颜色。
使用React创建倒计时器
对于我们的项目,我们将建立一个简单的倒计时器。
我们将在React中使用以下方法来使用倒计时器。
- getTimeRemaining: 这将计算出目标定时器和我们当前时间的差值。这个函数将通过计算来检查从目标定时器剩下的时间,并返回一个小时、分钟和秒的总数。
- startTimer:这个函数将从getTimeRemaining函数中得到的总时分秒数开始计时。
- clearTimer: 这个函数用于重置定时器,这意味着如果你重新启动定时器,它将清除前一个倒计时的剩余时间,否则它将开始平行的两次计时,或者它可能会相互折叠。
- getDeadTimer:这个函数提供了定时器的最后期限,意味着它给出了你想开始倒计时的时间。在这里,如果你想延长,你必须增加时间。我们在两种情况下使用这个函数,第一是在页面加载时,第二是在有人点击重置按钮时。
现在,你知道了这个项目背后的方法,请加快进度吧。
复制并粘贴以下代码到App.js文件中
import React, { useState, useRef, useEffect } from 'react'
const App = () => {
// We need ref in this, because we are dealing
// with JS setInterval to keep track of it and
// stop it when needed
const Ref = useRef(null);
// The state for our timer
`
const [timer, setTimer] = useState('00:00:00');
const getTimeRemaining = (e) => {
const total = Date.parse(e) - Date.parse(new Date());
const seconds = Math.floor((total / 1000) % 60);
const minutes = Math.floor((total / 1000 / 60) % 60);
const hours = Math.floor((total / 1000 / 60 / 60) % 24);
return {
total, hours, minutes, seconds
};
}
const startTimer = (e) => {
let { total, hours, minutes, seconds }
= getTimeRemaining(e);
if (total >= 0) {
// update the timer
// check if less than 10 then we need to
// add '0' at the beginning of the variable
setTimer(
(hours > 9 ? hours : '0' + hours) + ':' +
(minutes > 9 ? minutes : '0' + minutes) + ':'
+ (seconds > 9 ? seconds : '0' + seconds)
)
}
}
const clearTimer = (e) => {
// If you adjust it you should also need to
// adjust the Endtime formula we are about
// to code next
setTimer('00:00:10');
// If you try to remove this line the
// updating of timer Variable will be
// after 1000ms or 1sec
if (Ref.current) clearInterval(Ref.current);
const id = setInterval(() => {
startTimer(e);
}, 1000)
Ref.current = id;
}
const getDeadTime = () => {
let deadline = new Date();
// This is where you need to adjust if
// you entend to add more time
deadline.setSeconds(deadline.getSeconds() + 10);
return deadline;
}
// We can use useEffect so that when the component
// mount the timer will start as soon as possible
// We put empty array to act as componentDid
// mount only
useEffect(() => {
clearTimer(getDeadTime());
}, []);
// Another way to call the clearTimer() to start
// the countdown is via action event from the
// button first we create function to be called
// by the button
const onClickReset = () => {
clearTimer(getDeadTime());
}
return (
<div className="App">
<h2>{timer}</h2>
<button onClick={onClickReset}>Reset</button>
</div>
)
}
export default App;
运行应用程序
有了这些简单的组件,让我们试着把这个应用程序转起来,确保它能正常工作。
输入命令:
npm start
这将在一个设定的localhost URL上启动应用程序。一旦开发服务器开始工作并在命令提示符下运行,进入该URL查看应用程序。
现在,一切都很好,准备好了应用程序的运行和工作,但对PWA方面更感兴趣。
运行PWA
重点回到 index.js文件。做以下改变:
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://cra.link/PWA
serviceWorkerRegistration.register(); //change the service worker registration from 'unregistered' to 'registered'
从本质上讲,将服务工作者从未注册改为注册 ,将允许你在离线时也能使用该应用,这是涉及PWA的一个关键好处。
随着PWA文件的设置,为了查看差异,你可以使用serve包将你的应用程序部署到静态服务器上,该包将为你的应用程序提供本地主机。
简而言之,通过安装确保你有serve包,再次构建应用程序,并使用serve 来部署应用程序。
npm install serve
npm run build
serve -s build //if you encounter an error with this command, try 'npx serve -s build'
一旦你使用serve命令,你应该看到以下信息,你的应用程序已经部署到http://localhost:64192。
我们的PWA应用现在正在运行。从这里,你可以测试许多PWA功能,如安装、离线查看和Lighthouse审计测试。
现在,点击URL栏右侧的'+'符号。你的 PWA 将被自动安装。
结语
在这篇文章中,我们已经看到了PWA的神奇之处。添加一个网络应用程序清单文件 和一个服务工作者确实改善了我们传统网络应用程序的用户体验。这是因为PWA是快速、安全、可靠的,而且--最重要的是--它们支持脱机模式。
谢谢你阅读这篇文章!