翻译 | 《JavaScript Everywhere》第12章 使用React构建Web客户端(^_^)

翻译 | 《JavaScript Everywhere》第12章 使用React构建Web客户端(_

写在最前面

大家好呀,我是毛小悠,是一位前端开发工程师。正在翻译一本英文技术书籍。

为了提高大家的阅读体验,对语句的结构和内容略有调整。如果发现本文中有存在瑕疵的地方,或者你有任何意见或者建议,可以在评论区留言,或者加我的微信:code_maomao,欢迎相互沟通交流学习。

(σ゚∀゚)σ…:*☆哎哟不错哦

第12章 使用React构建Web客户端

超文本背后的原始想法是获取相关文档并将它们链接在一起:如果学术论文A引用学术论文B,让我们可以轻松地单击某些内容并在它们之间导航。1989年,CERN的一位名为Tim Berners-Lee的软件工程师提出了将超文本与联网计算机相结合的想法,从而使人们可以轻松地建立这些连接,而不管文档的位置如何。每张猫的照片、新闻、推文、流媒体视频、求职网站和餐厅评论都应归功于全局链接文档的简单想法。

从本质上讲,网络仍然是将文档链接在一起的媒介。在网络浏览器中,每个页面都是HTML,带有CSS(用于样式设置)和JavaScript(用于增强功能)。今天,我们使用这些技术来构建从个人博客和小型手册站点到复杂的交互式应用程序的所有内容。其根本优点是Web提供了通用访问权限。任何人只需要一个可以连接网络的网络浏览器,会创建一个默认的环境。

我们正在构建什么

在接下来的章节中,我们将为社交笔记应用Notedly构建Web客户端。用户将能够创建和登录帐户,在Markdown中编写笔记,编辑他们的笔记,查看其他用户笔记的摘要以及“收藏”其他用户笔记。为此,我们将与GraphQL服务器API进行交互。

在我们的Web应用程序中:

  • 用户将能够创建笔记、阅读、更新和删除他们创建的笔记。

  • 用户将能够查看其他用户创建的笔记的摘要,并阅读其他人创建的单个笔记,尽管他们将无法更新或删除它们。

  • 用户将能够创建帐户,登录和注销。

  • 用户将能够检索其个人资料信息以及其他用户的公共个人资料信息。

  • 用户将能够收藏其他用户的笔记以及检索其收藏夹列表。

这些功能将涉及很多领域,但是在本书的这一部分中,我们将把它们分成小块。一旦学会了使用所有这些功能构建React应用程序,就可以将工具和技术应用于构建各种富Web应用程序。

我们将如何构建它

你可能已经猜到了,要构建此应用程序,我们将使用React作为客户端JavaScript库。此外,我们将从GraphQL API查询数据。为了帮助查询,修改和缓存数据,我们将使用Apollo客户。Apollo Client包含用于使用GraphQL的一系列开源工具。我们将使用库的React版本,但是Apollo的团队还开发了AngularVueScala.jsNative iOSNative Android集成。

其他GraphQL客户端库

尽管我们将在本书中使用Apollo,但它远远不是唯一一个GraphQL客户端选项。FacebookRelayFormiddableurql也是两个受欢迎的选择。

此外,我们将使用parcel作为我们的代码捆绑器。代码捆绑器使我们可以使用Web浏览器中可能不具备的功能(例如,较新的语言功能,代码模块,压缩)编写JavaScript,并将其打包以供在浏览器环境中使用。ParcelWebpack等应用程序构建工具的无配置替代方案。它提供了许多不错的功能,例如代码拆分和在开发过程中自动更新浏览器(又称热模块替换),而无需建立构建。如上一章所述,create-react-app它还提供了零配置的初始设置,在后台使用Webpack,但Parcel允许我们从头开始构建应用程序,这是我发现学习的理想方式。

入门

在开始开发之前,我们需要将项目启动代码文件复制到我们的电脑上。

项目的源代码包含我们开发应用程序所需的所有脚本和对第三方库的引用。要将代码克隆到本地计算机,请打开终端,导航到保存项目的目录,然后git clone项目存储库。如果你已经遍历了API章节,则可能已经创建了一个notedly目录来保持项目代码的条理性:

# change into the Projects directory
$ cd
$ cd Projects
$ # type the `mkdir notedly` command if you don't yet have a notedly directory  
$ cd notedly  
$ git clone git@github.com:javascripteverywhere/web.git
$ cd web
$ npm install 

安装第三方依赖项

通过使用本书的入门代码的副本并在目录中运行npm install,你无需为任何第三方依赖项再次运行npm install

该代码的结构如下:

  • /src

    这是你随书一起进行开发的目录。

  • /solutions

    该目录包含每章的解决方案。如果你卡住了,这些可以供你参考。

  • /final

    该目录包含最终的工作项目。

现在,你已经在电脑上安装了代码,复制项目的.env文件。这个文件保存了我们特殊的工作环境变量。

例如,在本地工作时,我们将指向API的本地实例,但是在部署应用程序时,我们将指向我们远程的API。复制.env文件,从Web目录在终端中键入以下内容:

$ cp .env.example .env

你现在应该看到一个.env文件。你无需对该文件做任何事情,但是随着API后端的开发,我们将向其中添加信息。项目附带的.gitignore文件将确保你不会无意间提交.env文件。

求助,我看不到.env文件!

默认情况下,操作系统隐藏以句点开头的文件,因为这些文件通常由系统使用,而不是最终用户使用。如果看不到.env文件,请尝试在文本编辑器中打开目录。该文件应该在编辑器的文件浏览器中可见。或者,在终端窗口中键入ls -a将列出当前工作目录中的文件。

构建Web应用程序

在本地克隆了启动代码之后,我们就可以构建React Web应用程序了。首先让我们看一下src/index.html文件。这看起来像一个标准的但完全为空的HTML文件,但请注意以下两行:

<div id="root"></div>
<script src="./App.js"></script> 

这两行对我们的React应用程序非常重要。

root将提供整个应用程序的容器。同时,App.js文件将成为我们JavaScript应用程序的入口。

现在我们可以开始在src/App.js文件中开发React应用程序了。如果你跟随上一章中的React简介,可能会觉得很熟悉。在src/App.js中,我们首先导入reactreact-dom库:

import React from 'react';
import ReactDOM from 'react-dom'; 

现在,我们将创建一个名为App的函数,该函数将返回应用程序的内容。现在,这将只是元素中包含的两行HTML

const App = () => {
    
    
  return (
   <div>
    <h1>Hello Notedly!</h1>
    <p>Welcome to the Notedly application</p>
   </div>
  );
}; 

和所有的div相关的是什么?

如果你只是从React入手,你可能会想知道用标签包围组件的趋势。React的组件必须包含于父元素,这往往是一种标签,但也可以是任何其他适当的HTML标签,例如,或.

如果感觉包含HTML的标记多余,我们可以用空的<>标记在我们的JavaScript代码中包含这些组件。

最后,我们将通过添加以下内容来指示React在根IDroot的元素内渲染应用程序:

ReactDOM.render(<App />, document.getElementById('root'));

现在,我们的src/App.js文件的完整内容应为:

import React from 'react';
import ReactDOM from 'react-dom';

const App = () => {
    
    
  return (
   <div>
    <h1>Hello Notedly!</h1>
    <p>Welcome to the Notedly application</p>
   </div>
  );
};

ReactDOM.render(<App />, document.getElementById('root')); 

完成此操作后,让我们在Web浏览器中进行查看。通过在终端应用程序中键入npm run dev来启动本地开发服务器。编译代码后,请访问 http://localhost:1234来查看页面(图12-1)。

12-1我们最初在浏览器中运行的React应用程序

路由

网络的定义特征之一是能够将文档链接在一起。同样,对于我们的应用程序,我们希望用户能够在屏幕或页面之间导航。在HTML呈现的应用程序中,这将涉及创建多个HTML文档。每当用户导航到新文档时,即使两个页面上存在共享的方面(例如页眉或页脚),整个文档也会重新加载。

JavaScript应用程序中,我们可以利用客户端路由。在许多方面,这将类似于HTML链接。用户将单击一个链接,URL将更新,并且他们将导航到新屏幕。不同之处在于我们的应用程序只会使用更改后的内容来更新页面。体验将是“类似于应用程序的”的流畅,这意味着将不会看到页面的刷新。

React中,最常用的路由库是Router。这个库使我们能够向React Web应用程序添加路由功能。为了将路由引入我们的应用程序,让我们首先创建一个src/pages目录并添加以下文件:

  • /src/pages/index.js

  • /src/pages/home.js

  • /src/pages/mynotes.js

  • /src/pages/favorites.js

我们的home.jsmynotes.jsfavorite.js文件将成为我们单独的页面组件。我们可以为每个文件创建一些初始内容和效果钩子,当用户导航到页面时,它们将更新文档标题。

src/pages/home.js中:

import React from 'react';  
  
const Home = () => {
    
      
 return (  
 <div>  
 <h1>Notedly</h1>  
 <p>This is the home page</p>  
 </div>  
 );  
};  
  
export default Home;

src/pages/mynotes.js中:

import React, {
    
     useEffect } from 'react';

const MyNotes = () => {
    
    
  useEffect(() => {
    
    
    // update the document title
    document.title = 'My Notes — Notedly';
  });

  return (
    <div>
      <h1>Notedly</h1>
      <p>These are my notes</p>
    </div>
  );
};

export default MyNotes; 

src/pages/favorites.js中:

import React, {
    
     useEffect } from 'react';

const Favorites = () => {
    
    
  useEffect(() => {
    
    
    // update the document title
    document.title = 'Favorites — Notedly';
  });

  return (
    <div>
      <h1>Notedly</h1>
      <p>These are my favorites</p>
    </div>
  );
};

export default Favorites; 

useEffect

在前面的示例中,我们使用ReactuseEffect钩子来设置页面标题。Effect挂钩使我们在组件中存在副作用,会更新与组件本身无关的内容。如果你有兴趣,可以深入探讨ReactEffect hooks文档。

现在,在src/pages/index.js中,我们将使用react-router-dom包导入React RouterWeb浏览器路由所需的方法:

import React from 'react';
import {
    
     BrowserRouter as Router, Route } from 'react-router-dom'; 

接下来,我们将导入刚刚创建的页面组件:

import Home from './home';
import MyNotes from './mynotes';
import Favorites from './favorites'; 

最后,我们将使用特定的URL指定我们创建为路由的每个页面组件。请注意,对于我们的“Home”路由使用了完全匹配,这将确保仅针对根URL呈现主页组件:

const Pages = () => {
    
    
  return (
    <Router>
      <Route exact path="/" component={
    
    Home} />
      <Route path="/mynotes" component={
    
    MyNotes} />
      <Route path="/favorites" component={
    
    Favorites} />
    </Router>
  );
};

export default Pages; 

现在,我们完整的src/pages/index.js文件应如下所示:

// import React and routing dependencies
import React from 'react';
import {
    
     BrowserRouter as Router, Route } from 'react-router-dom';

// import routes
import Home from './home';
import MyNotes from './mynotes';
import Favorites from './favorites';

// define routes
const Pages = () => {
    
    
  return (
    <Router>
      <Route exact path="/" component={
    
    Home} />
      <Route path="/mynotes" component={
    
    MyNotes} />
      <Route path="/favorites" component={
    
    Favorites} />
    </Router>
  );
};

export default Pages; 

最后,我们可以通过导入路由并渲染组件来更新src/App.js文件以使用我们的路由:

import React from 'react';
import ReactDOM from 'react-dom';

// import routes
import Pages from '/pages';

const App = () => {
    
    
  return (
    <div>
      <Pages />
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById('root')); 

现在,如果你在Web浏览器中手动更新URL,则应该能够查看每个组件。例如,键入http:// localhost:1234/favorites来呈现“收藏夹”页面。

链接

我们已经创建了页面,但是缺少将它们链接在一起的关键部分。因此,让我们从首页添加到其他页面的链接。为此,我们将使用React RouterLink组件。

src/pages/home.js中:

import React from 'react';
// import the Link component from react-router
import {
    
     Link } from 'react-router-dom';

const Home = () => {
    
    
  return (
    <div>
      <h1>Notedly</h1>
      <p>This is the home page</p>
      {
    
     /* add a list of links */ }
      <ul>
        <li>
          <Link to="/mynotes">My Notes</Link>
        </li>
        <li>
          <Link to="/favorites">Favorites</Link>
        </li>
      </ul>
    </div>
  );
};

export default Home; 

这样我们就可以浏览我们的应用程序。
单击主页上的链接之一将导航到相应的页面组件。
浏览器的核心导航功能(如后退和前进按钮)也将继续起作用。

UI组件

我们已经成功创建了单个页面组件,并且可以在它们之间进行导航。在构建页面时,它们将具有几个共享的用户界面元素,例如标题和站点范围的导航。每次使用它们时重写它们都不会非常高效(并且会很烦人)。取而代之的是,我们可以编写可重用的接口组件,并将它们导入到我们需要的任何地方。实际上,将我们的UI视为由微小的组件组成是React的核心功能之一,也是我在掌握框架方面的突破。

我们将从为应用程序创建标题和导航组件开始。首先,让我们在src目录中创建一个名为components的新目录。在src/components目录中,我们将创建两个名为Header.jsNavigation.js的新文件。React组件必须大写,因此我们也将遵循大写文件名的惯例。

让我们首先在src/components/Header.js中编写标头组件。为此,我们将导入logo.svg文件,并为我们的组件添加相应的标记:

import React from 'react';
import logo from '../img/logo.svg';

const Header = () => {
    
    
  return (
    <header> <img src={
    
    logo} alt="Notedly Logo" height="40" /> <h1>Notedly</h1> </header> );
};

export default Header; 

对于我们的导航组件,我们将导入React RouterLink功能并标记一个无序的链接列表。在src/components/Navigation.js中:

import React from 'react';
import {
    
     Link } from 'react-router-dom';

const Navigation = () => {
    
    
  return (
    <nav> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/mynotes">My Notes</Link> </li> <li> <Link to="/favorites">Favorites</Link> </li> </ul> </nav>
  );
};

export default Navigation; 

在屏幕截图中,你会发现我还包括了表情符号字符作为导航图标。

如果你要这样做,包含表情符号字符的可访问标记如下:

<span aria-hidden="true" role="img">
  <!-- emoji character --> </span> 

完成标题和导航组件后,我们现在可以在应用程序中使用它们了。让我们更新src/pages/home.js文件以包含这些组件。我们将首先导入它们,然后将组件包括在我们的JSX标记中。

我们的src/pages/home.js现在将如下所示(图12-2):

import React from 'react';

import Header from '../components/Header';
import Navigation from '../components/Navigation';

const Home = () => {
    
    
  return (
    <div> <Header /> <Navigation /> <p>This is the home page</p> </div>
  );
};

export default Home; 

12-2使用React组件,我们可以轻松地组合可共享的UI功能。

这是我们能够在我们的应用程序中创建可共享组件所需的一切。有关在UI中使用组件的更多信息,我强烈建议阅读React文档页““Thinking in React”.

结论

网络仍然是分发应用程序的无比重要的媒介。它使开发者可以实时更新访问。

在本章中,我们在React中构建了JavaScript Web应用程序。在下一章中,我们将使用React组件和CSS-in-JS向应用程序添加布局和样式。

如果有理解不到位的地方,欢迎大家纠错。如果觉得还可以,麻烦您点赞收藏或者分享一下,希望可以帮到更多人。

猜你喜欢

转载自blog.csdn.net/code_maomao/article/details/110217906