ReactJS - 快速指南


ReactJS - 简介

ReactJS 是一个简单、功能丰富、基于组件的 JavaScript UI 库。它可用于开发小型应用程序以及大型复杂应用程序。ReactJS 提供了最少且可靠的功能集来启动 Web 应用程序。React 社区通过提供大量现成组件来在创纪录的时间内开发 Web 应用程序,从而对 React 库进行了补充。React 社区还在 React 库之上提供了状态管理、路由等高级概念。

反应版本

React 的初始版本 0.3.0 于 2013 年 5 月发布,最新版本17.0.1于 2020 年 10 月发布。主要版本引入了重大更改,次要版本引入了新功能,但不破坏现有功能。必要时会发布错误修复。React 遵循语义版本控制 (semver)原则。

特征

React 库的显着特点如下:

  • 坚实的基础架构
  • 可扩展的架构
  • 基于组件的库
  • 基于JSX的设计架构
  • 声明式 UI 库

好处

使用React 库的一些好处如下 -

  • 简单易学
  • 轻松适应现代和遗留应用程序
  • 更快地编写功能代码的方法
  • 大量现成组件的可用性
  • 大型且活跃的社区

应用领域

下面列出了一些由React 库支持的流行网站 -

  • Facebook,流行的社交媒体应用程序
  • Instagram,流行的照片共享应用程序
  • Netflix,流行的媒体流应用程序
  • Code Academy,流行的在线培训应用程序
  • Reddit,流行的内容共享应用程序

如您所见,各个领域最流行的应用程序都是由React Library开发的。

ReactJS - 安装

本章介绍了在您的计算机中安装 React 库及其相关工具。在开始安装之前,让我们首先验证先决条件。

React 为开发人员提供 CLI 工具来快速创建、开发和部署基于 React 的 Web 应用程序。React CLI 工具依赖于 Node.js,并且必须安装在您的系统中。希望您已经在计算机上安装了 Node.js。我们可以使用以下命令检查它 -

node --version

您可以看到您可能安装的 Nodejs 版本。对我来说如下所示,

v14.2.0

如果未安装Nodejs,可以访问https://nodejs.org/en/download/下载并安装。

工具链

要开发表单验证、模型对话框等轻量级功能,React 库可以通过内容分发网络 (CDN) 直接包含到 Web 应用程序中。它类似于在 Web 应用程序中使用 jQuery 库。对于中型到大型应用程序,建议将应用程序编写为多个文件,然后使用 webpack、parcel、rollup 等捆绑器来编译和捆绑应用程序,然后再部署代码。

React 工具链有助于创建、构建、运行和部署 React 应用程序。React 工具链基本上提供了一个入门项目模板,其中包含引导应用程序所需的所有代码。

一些用于开发 React 应用程序的流行工具链是 -

  • 创建 React App - 面向 SPA 的工具链
  • Next.js - 面向服务器端渲染的工具链
  • Gatsby - 面向静态内容的工具链

开发 React 应用程序所需的工具是 -

  • 服务,一个静态服务器,用于在开发过程中为我们的应用程序提供服务
  • 巴别塔编译器
  • 创建 React 应用程序 CLI

让我们在本章中学习上述工具的基础知识以及如何安装它们。

服务静态服务器

服务是一个轻量级 Web 服务器。它服务于静态站点和单页应用程序。它加载速度快并且消耗最少的内存。它可用于为 React 应用程序提供服务。让我们在系统中使用npm包管理器安装该工具。

npm install serve -g

让我们创建一个简单的静态站点并使用serve app为应用程序提供服务。

打开命令提示符并转到您的工作区。

cd /go/to/your/workspace

创建一个新文件夹static_site并将目录更改为新创建的文件夹。

mkdir static_site 
cd static_site

接下来,使用您最喜欢的 html 编辑器在文件夹内创建一个简单的网页。

<!DOCTYPE html> 
<html> 
   <head> 
      <meta charset="UTF-8" /> 
      <title>Static website</title> 
   </head> 
   <body> 
      <div><h1>Hello!</h1></div> 
   </body> 
</html>

接下来,运行服务命令。

serve .

我们还可以提供单个文件,index.html,而不是整个文件夹。

serve ./index.html

接下来,打开浏览器并在地址栏中输入http://localhost:5000并按回车键。服务应用程序将为我们的网页提供服务,如下所示。

你好

服务器将使用默认端口 5000 为应用程序提供服务。如果该端口不可用,它将选择一个随机端口并指定它。

│ Serving!                                     │   
   │                                              │ 
   │ - Local: http://localhost:57311              │ 
   │ - On Your Network: http://192.168.56.1:57311 │ 
   │                                              │ 
   │ This port was picked because 5000 is in use. │ 
   │                                              │ 
   │ Copied local address to clipboard!

巴别塔编译器

Babel 是一个 JavaScript 编译器,它将 JavaScript 的许多变体(es2015、es6 等)编译成所有浏览器支持的标准 JavaScript 代码。React 使用 JSX(JavaScript 的扩展)来设计用户界面代码。Babel 用于将 JSX 代码编译为 JavaScript 代码。

要安装 Babel 及其 React 伴侣,请运行以下命令 -

npm install babel-cli@6 babel-preset-react-app@3 -g
... 
... 
+ babel-cli@6.26.0 
+ babel-preset-react-app@3.1.2 
updated 2 packages in 8.685s

Babel 帮助我们用下一代高级 JavaScript 语法编写应用程序。

创建 React App 工具链

Create React App是一个现代 CLI 工具,用于创建单页 React 应用程序。它是React社区支持的标准工具。它也处理 babel 编译器。让我们在本地系统中安装Create React App 。

> npm install -g create-react-app
+ create-react-app@4.0.1 
added 6 packages from 4 contributors, removed 37 packages and updated 12 packages in 4.693s

更新工具链

React Create App工具链使用react-scripts 包来构建和运行应用程序。一旦我们开始开发应用程序,我们就可以随时使用npm包管理器将反应脚本更新到最新版本。

npm install react-scripts@latest

使用React工具链的优点

React 工具链提供了许多开箱即用的功能。使用 React 工具链的一些优点是 -

  • 应用程序的预定义和标准结构。
  • 适用于不同类型应用程序的现成项目模板。
  • 包括开发网络服务器。
  • 包含第三方 React 组件的简单方法。
  • 用于测试应用程序的默认设置。

ReactJS - 架构

React 库建立在坚实的基础之上。它简单、灵活、可扩展。正如我们之前了解到的,React 是一个在 Web 应用程序中创建用户界面的库。React 的主要目的是使开发人员能够使用纯 JavaScript 创建用户界面。通常,每个用户界面库都会引入一种新的模板语言(我们需要学习)来设计用户界面,并提供在模板内部或单独编写逻辑的选项。

React 没有引入新的模板语言,而是引入了三个简单的概念,如下所示 -

反应元素

HTML DOM 的 JavaScript 表示。React 提供了一个 API React.createElement创建 React Element

JSX

用于设计用户界面的 JavaScript 扩展。JSX 是一种基于 XML 的可扩展语言,只需很少的修改即可支持 HTML 语法。JSX 可以编译为 React Elements 并用于创建用户界面。

反应组件

React 组件是 React 应用程序的主要构建块。它使用 React 元素和 JSX 来设计其用户界面。React 组件基本上是一个 JavaScript 类(扩展了React.component类)或纯 JavaScript 函数。React 组件具有属性、状态管理、生命周期和事件处理程序。React 组件可以执行简单的逻辑,也可以执行高级的逻辑。

让我们在“React 组件”章节中了解有关组件的更多信息。

React 应用程序的工作流程

让我们通过创建和分析一个简单的 React 应用程序来了解本章中 React 应用程序的工作流程。

打开命令提示符并转到您的工作区。

cd /go/to/your/workspace

接下来,创建一个文件夹static_site并将目录更改为新创建的文件夹。

mkdir static_site 
cd static_site

例子

接下来,创建一个文件hello.html并编写一个简单的 React 应用程序。

<!DOCTYPE html> 
<html> 
   <head> 
      <meta charset="UTF-8" /> 
      <title>React Application</title> 
   </head> 
   <body> 
      <div id="react-app"></div> 
      <script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script> 
      <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script> 
      <script language="JavaScript"> 
         element = React.createElement('h1', {}, 'Hello React!') 
         ReactDOM.render(element, document.getElementById('react-app')); 
      </script> 
   </body> 
</html>

接下来,使用服务 Web 服务器为应用程序提供服务。

serve ./hello.html

输出

接下来,打开您最喜欢的浏览器。在地址栏中输入http://localhost:5000 ,然后按回车键。

反应你好

让我们分析一下代码并做一些修改,以更好地理解 React 应用程序。

在这里,我们使用了 React 库提供的两个 API。

React.createElement

用于创建 React 元素。它需要三个参数 -

  • 元素标签
  • 元素属性作为对象
  • 元素内容 - 它也可以包含嵌套的 React 元素

ReactDOM.render

用于将元素渲染到容器中。它需要两个参数 -

  • React 元素或 JSX
  • 网页的根元素

嵌套反应元素

由于React.createElement允许嵌套 React 元素,让我们添加嵌套元素,如下所示 -

例子

<script language="JavaScript">
   element = React.createElement('div', {}, React.createElement('h1', {}, 'Hello React!'));
   ReactDOM.render(element, document.getElementById('react-app')); 
</script>

输出

它将生成以下内容 -

<div><h1> Hello React!</h1></div> 

使用 JSX

接下来,让我们完全删除 React 元素并引入 JSX 语法,如下所示 -

<!DOCTYPE html> 
<html> 
   <head> 
      <meta charset="UTF-8" /> 
      <title>React Application</title> 
   </head> 
   <body> 
      <div id="react-app"></div> 
      <script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script> 
      <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script> 
      <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> 
      <script type="text/babel"> 
         ReactDOM.render(
            <div><h1>Hello React!</h1></div>, 
            document.getElementById('react-app') 
         ); 
     </script> 
   </body> 
</html>

在这里,我们添加了 babel 将 JSX 转换为 JavaScript,并在 script 标签中添加了type=“text/babel” 。

<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> 
<script type="text/babel"> 
   ... 
   ... 
</script>

接下来,运行应用程序并打开浏览器。应用程序的输出如下 -

你好Jsx

接下来,让我们创建一个新的 React 组件 Greeting,然后尝试在网页中使用它。

<script type="text/babel"> 
   function Greeting() {
      return <div><h1>Hello JSX!</h1></div> 
   } 
   ReactDOM.render(<Greeting />, document.getElementById('react-app') ); 
</script>

结果相同,如下所示 -

你好Jsx

通过分析应用程序,我们可以可视化 React 应用程序的工作流程,如下图所示。

工作流 JSX

React 应用程序通过传递使用 React 组件(以 JSX 或 React 元素格式编码)创建的用户界面和渲染用户界面的容器来调用ReactDOM.render方法。

ReactDOM.render处理 JSX 或 React 元素并发出虚拟 DOM。

虚拟 DOM 将被合并并渲染到容器中。

React 应用程序的架构

React 库只是 UI 库,它不强制执行任何特定模式来编写复杂的应用程序。开发人员可以自由选择自己喜欢的设计模式。React 社区提倡一定的设计模式。其中一种模式是 Flux 模式。React 库还提供了许多概念,如高阶组件、上下文、渲染道具、引用等,以编写更好的代码。React Hooks 正在不断发展在大型项目中进行状态管理的概念。让我们尝试了解 React 应用程序的高级架构。

反应应用程序
  • React 应用程序从单个根组件开始。

  • 根组件是使用一个或多个组件构建的。

  • 每个组件都可以与其他组件嵌套到任意级别。

  • 组合是 React 库的核心概念之一。因此,每个组件都是通过组合较小的组件来构建的,而不是从一个组件继承另一个组件。

  • 大多数组件都是用户界面组件。

  • React 应用程序可以包含用于特定目的的第三方组件,例如路由、动画、状态管理等。

ReactJS - 创建 React 应用程序

正如我们之前了解到的,React 库可以用于简单和复杂的应用程序。简单应用程序通常在其脚本部分包含 React 库。在复杂的应用程序中,开发人员必须将代码拆分成多个文件,并将代码组织成标准的结构。在这里,React 工具链提供了预定义的结构来引导应用程序。此外,开发人员可以自由地使用自己的项目结构来组织代码。

让我们看看如何创建简单和复杂的 React 应用程序 -

使用 Rollup 捆绑器

Rollup是小型且快速的 JavaScript 捆绑器之一。让我们在本章中学习如何使用 rollup 捆绑器。

打开终端并转到您的工作区。

cd /go/to/your/workspace

接下来,创建一个文件夹,expense-manager-rollup并移至新创建的文件夹。另外,在您喜欢的编辑器或 IDE 中打开该文件夹。

mkdir expense-manager-rollup 
cd expense-manager-rollup

接下来,创建并初始化项目。

npm init -y

接下来,安装React库(react和react-dom)

npm install react@^17.0.0 react-dom@^17.0.0 --save

接下来,安装 babel 及其预设库作为开发依赖项。

npm install @babel/preset-env @babel/preset-react 
@babel/core @babel/plugin-proposal-class-properties -D

接下来,安装 rollup 及其插件库作为开发依赖项。

npm i -D rollup postcss@8.1 @rollup/plugin-babel 
@rollup/plugin-commonjs @rollup/plugin-node-resolve 
@rollup/plugin-replace rollup-plugin-livereload 
rollup-plugin-postcss rollup-plugin-serve postcss@8.1 
postcss-modules@4 rollup-plugin-postcss

接下来,安装 corejs 和 regenerator 运行时以进行异步编程。

npm i regenerator-runtime core-js

接下来,在根文件夹下创建一个babel配置文件.babelrc来配置babel编译器。

{
   "presets": [
      [
         "@babel/preset-env",
         {
            "useBuiltIns": "usage",
            "corejs": 3,
            "targets": "> 0.25%, not dead"
         }
      ],
      "@babel/preset-react"
   ],
   "plugins": [
      "@babel/plugin-proposal-class-properties"
   ]
}

接下来,在根文件夹中创建一个rollup.config.js文件来配置 rollup 捆绑程序。

import babel from '@rollup/plugin-babel';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import replace from '@rollup/plugin-replace';
import serve from 'rollup-plugin-serve';
import livereload from 'rollup-plugin-livereload';
import postcss from 'rollup-plugin-postcss'

export default {
   input: 'src/index.js',
   output: {
      file: 'public/index.js',
      format: 'iife',
   },
   plugins: [
      commonjs({
         include: [
            'node_modules/**',
         ],
         exclude: [
            'node_modules/process-es6/**',
         ],
      }),
      resolve(),
      babel({
         exclude: 'node_modules/**'
      }),
      replace({
         'process.env.NODE_ENV': JSON.stringify('production'),
      }),
      postcss({
         autoModules: true
      }),
      livereload('public'),
      serve({
         contentBase: 'public',
         port: 3000,
         open: true,
      }), // index.html should be in root of project
   ]
}

接下来,更新package.json并包含我们的入口点(public/index.js 和 public/styles.css)以及用于构建和运行应用程序的命令。

...
"main": "public/index.js",
"style": "public/styles.css",
"files": [
   "public"
],
"scripts": {
   "start": "rollup -c -w",
   "build": "rollup"
},
...

接下来,在应用程序的根目录中创建一个 src 文件夹,该文件夹将保存应用程序的所有源代码。

接下来,在 src 下创建一个文件夹,components,以包含我们的 React 组件。我们的想法是创建两个文件,<component>.js 用于编写组件逻辑,<component.css> 用于包含组件特定样式。

应用程序的最终结构如下 -

|-- package-lock.json
|-- package.json
|-- rollup.config.js
|-- .babelrc
`-- public
   |-- index.html
`-- src
   |-- index.js
   `-- components
   |  |-- mycom.js
   |  |-- mycom.css

让我们创建一个新组件HelloWorld来确认我们的设置工作正常。在 Components 文件夹下创建一个文件HelloWorld.js,并编写一个简单的组件来发出Hello World消息。

import React from "react";

class HelloWorld extends React.Component {
   render() {
      return (
         <div>
            <h1>Hello World!</h1>
         </div>
      );
   }
}
export default HelloWorld;

接下来,在src文件夹下创建我们的主文件index.js并调用我们新创建的组件。

import React from 'react';
import ReactDOM from 'react-dom';
import HelloWorld from './components/HelloWorld';

ReactDOM.render(
   <React.StrictMode>
      <HelloWorld />
   </React.StrictMode>,
   document.getElementById('root')
);

接下来,在根目录中创建一个公用文件夹。

接下来,创建一个 html 文件,index.html(在 public 文件夹* 下),这将是我们应用程序的入口点。

<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="utf-8">
      <title>Expense Manager :: Rollup version</title>
   </head>
   <body>
      <div id="root"></div>
      <script type="text/JavaScript" src="./index.js"></script>
   </body>
</html>

接下来,构建并运行应用程序。

npm start

npm build命令将执行汇总并将我们的应用程序捆绑到单个文件dist/index .js 文件中,并开始为应用程序提供服务。每当源代码发生更改时, dev命令都会重新编译代码,并在浏览器中重新加载更改。

> expense-manager-rollup@1.0.0 build /path/to/your/workspace/expense-manager-rollup 
> rollup -c 
rollup v2.36.1 
bundles src/index.js → dist\index.js... 
LiveReload enabled 
http://localhost:10001 -> /path/to/your/workspace/expense-manager-rollup/dist 
created dist\index.js in 4.7s 

waiting for changes...

接下来,打开浏览器并在地址栏中输入http://localhost:3000并按回车键。服务应用程序将为我们的网页提供服务,如下所示。

你好世界

使用包裹捆绑器

Parcel是零配置的快速捆绑器。它只需要应用程序的入口点,它将解决依赖关系本身并捆绑应用程序。本章让我们学习如何使用parcelbundler。

首先,安装包裹捆绑器。

npm install -g parcel-bundler

打开终端并转到您的工作区。

cd /go/to/your/workspace

接下来,创建一个文件夹,expense-manager-parcel并移至新创建的文件夹。另外,在您喜欢的编辑器或 IDE 中打开该文件夹。

mkdir expense-manager-parcel 
cd expense-manager-parcel

接下来,创建并初始化项目。

npm init -y

接下来,安装React库(react和react-dom)

npm install react@^17.0.0 react-dom@^17.0.0 --save

接下来,安装 babel 及其预设库作为开发依赖项。

npm install @babel/preset-env @babel/preset-react @babel/core @babel/plugin-proposal-class-properties -D

接下来,在根文件夹下创建一个babel配置文件.babelrc来配置babel编译器。

{
   "presets": [
      "@babel/preset-env",
      "@babel/preset-react"
   ],
   "plugins": [
      "@babel/plugin-proposal-class-properties"
   ]
}

接下来,更新 package.json 并包含我们的入口点 (src/index.js) 以及用于构建和运行应用程序的命令。

... 
"main": "src/index.js", 
"scripts": {
   "start": "parcel public/index.html",
   "build": "parcel build public/index.html --out-dir dist" 
},
...

接下来,在应用程序的根目录中创建一个src文件夹,该文件夹将保存应用程序的所有源代码。

接下来,在 src 下创建一个文件夹,components,以包含我们的 React 组件。我们的想法是创建两个文件,<component>.js用于编写组件逻辑,<component.css>用于包含组件特定样式。

应用程序的最终结构如下 -

|-- package-lock.json
|-- package.json
|-- .babelrc
`-- public
   |-- index.html
`-- src
   |-- index.js
   `-- components
   |  |-- mycom.js
   |  |-- mycom.css

让我们创建一个新组件HelloWorld来确认我们的设置工作正常。在 Components 文件夹下创建一个文件HelloWorld.js,并编写一个简单的组件来发出 Hello World消息。

import React from "react";

class HelloWorld extends React.Component {
   render() {
      return (
         <div>
            <h1>Hello World!</h1>
         </div>
      );
   }
}
export default HelloWorld;

接下来,在src文件夹下创建我们的主文件index.js并调用我们新创建的组件。

import React from 'react';
import ReactDOM from 'react-dom';
import HelloWorld from './components/HelloWorld';

ReactDOM.render(
   <React.StrictMode>
      <HelloWorld />
   </React.StrictMode>,
   document.getElementById('root')
);

接下来,在根目录中创建一个公用文件夹。

接下来,创建一个 html 文件,index.html(在public文件夹中),这将是我们应用程序的入口点。

<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="utf-8">
      <title>Expense Manager :: Parcel version</title>
   </head>
   <body>
      <div id="root"></div>
      <script type="text/JavaScript" src="../src/index.js"></script>
   </body>
</html>

接下来,构建并运行应用程序。

npm start

npm build 命令执行 Parcel 命令。它将即时捆绑并提供应用程序。每当源代码发生更改时,它都会重新编译,并在浏览器中重新加载更改。

> expense-manager-parcel@1.0.0 dev /go/to/your/workspace/expense-manager-parcel 
> parcel index.html Server running at http://localhost:1234 
√ Built in 10.41s.

接下来,打开浏览器并在地址栏中输入http://localhost:1234并按回车键。

你好世界

要创建应用程序的生产包以将其部署在生产服务器中,请使用build命令。它将在 dist 文件夹下生成一个包含所有捆绑源代码的index.js文件。

npm run build
> expense-manager-parcel@1.0.0 build /go/to/your/workspace/expense-manager-parcel
> parcel build index.html --out-dir dist

√  Built in 6.42s.

dist\src.80621d09.js.map    270.23 KB     79ms
dist\src.80621d09.js        131.49 KB    4.67s
dist\index.html                 221 B    1.63s

ReactJS-JSX

正如我们之前了解到的,React JSX 是 JavaScript 的扩展。它使开发人员能够使用 XML 语法创建虚拟 DOM。它编译为纯 JavaScript(React.createElement 函数调用)。由于它编译为 JavaScript,因此可以在任何有效的 JavaScript 代码中使用。例如,下面的代码是完全有效的。

  • 分配给一个变量。
var greeting = <h1>Hello React!</h1>
  • 根据条件分配给变量。
var canGreet = true; 
if(canGreet) { 
   greeting = <h1>Hello React!</h1> 
}
  • 可以用作函数的返回值。
function Greeting() { 
   return <h1>Hello React!</h1> 
   
} 
greeting = Greeting()
  • 可以用作函数的参数。
function Greet(message) { 
   ReactDOM.render(message, document.getElementById('react-app') 
} 
Greet(<h1>Hello React!</h1>)

表达式

JSX 支持纯 JavaScript 语法的表达。表达式必须括在花括号{ }内。表达式可以包含定义 JSX 的上下文中可用的所有变量。让我们用表达式创建简单的 JSX。

例子

<script type="text/babel">
   var cTime = new Date().toTimeString();
   ReactDOM.render(
      <div><p>The current time is {cTime}</p></div>, 
      document.getElementById('react-app') );
</script>

输出

这里,cTime在 JSX using 表达式中使用。上述代码的输出如下:

The Current time is 21:19:56 GMT+0530(India Standard Time)

在 JSX 中使用表达式的积极副作用之一是它可以防止注入攻击,因为它将任何字符串转换为 html 安全字符串。

功能

JSX 支持用户定义的 JavaScript 函数。函数的用法与表达式类似。让我们创建一个简单的函数并在 JSX 中使用它。

例子

<script type="text/babel">
   var cTime = new Date().toTimeString();
   ReactDOM.render(
      <div><p>The current time is {cTime}</p></div>, 
      document.getElementById('react-app') 
   );
</script>

输出

这里,getCurrentTime()用于获取当前时间,输出类似于下面指定的 -

The Current time is 21:19:56 GMT+0530(India Standard Time)

属性

JSX 支持类似 HTML 的属性。支持所有 HTML 标签及其属性。属性必须使用驼峰命名约定(并且遵循 JavaScript DOM API)而不是普通的 HTML 属性名称来指定。例如,HTML 中的 class 属性必须定义为className。以下是其他一些例子 -

  • htmlFor代替for
  • tabIndex代替tabindex
  • onClick而不是onclick

例子

<style>
   .red { color: red }
</style>
<script type="text/babel">
   function getCurrentTime() {
      return new Date().toTimeString();
   }
   ReactDOM.render(
      <div>
         <p>The current time is <span className="red">{getCurrentTime()}</span></p>
      </div>,
      document.getElementById('react-app') 
   );
</script>

输出

输出如下 -

The Current time is 22:36:55 GMT+0530(India Standard Time)

属性中的表达

JSX 支持在属性内指定表达式。在属性中,双引号不应与表达式一起使用。必须使用使用双引号的表达式或字符串。可以将上面的示例更改为在属性中使用表达式。

<style>
   .red { color: red }
</style>

<script type="text/babel">
   function getCurrentTime() {
      return new Date().toTimeString();
   }
   var class_name = "red";
   ReactDOM.render(
      <div>
         <p>The current time is <span className={class_name}>{getCurrentTime()}</span></p>
      </div>, 
      document.getElementById('react-app') 
   );
</script>

ReactJS - 组件

React 组件是 React 应用程序的构建块。让我们在本章中学习如何创建一个新的 React 组件以及 React 组件的特性。

React 组件代表网页中的一小部分用户界面。React 组件的主要工作是渲染其用户界面并在其内部状态发生更改时更新它。除了渲染 UI 之外,它还管理属于其用户界面的事件。总而言之,React 组件提供了以下功能。

  • 用户界面的初始呈现。
  • 事件的管理和处理。
  • 每当内部状态发生变化时更新用户界面。

React 组件使用三个概念来完成这些功能 -

  • 属性- 使组件能够接收输入。

  • 事件- 使组件能够管理 DOM 事件和最终用户交互。

  • 状态- 使组件保持有状态。有状态组件根据其状态更新其 UI。

让我们在接下来的章节中一一学习所有概念。

创建一个 React 组件

React 库有两种组件类型。类型根据其创建方式进行分类。

  • 函数组件 - 使用纯 JavaScript 函数。
  • ES6 类组件 - 使用 ES6 类。

函数和类组件之间的核心区别是 -

  • 功能组件本质上非常少。它唯一的要求是返回一个React 元素

function Hello() { 
   return '<div>Hello</div>' 
}

使用 ES6 类组件可以完成相同的功能,只需很少的额外编码。

class ExpenseEntryItem extends React.Component {         
   render() { 
      return ( 
         <div>Hello</div> 
      ); 
   }
}
  • 类组件支持开箱即用的状态管理,而函数组件不支持状态管理。但是,React为功能组件提供了一个钩子useState()来维护其状态。

  • 类组件有一个生命周期,并通过专用的回调 API 访问每个生命周期事件。函数组件没有生命周期。同样,React 为函数组件提供了一个钩子useEffect()来访问组件的不同阶段。

创建类组件

让我们创建一个新的 React 组件(在我们的费用管理器应用程序中)ExpenseEntryItem 来展示费用条目项目。费用录入项目由名称、金额、日期和类别组成。费用条目的对象表示是 -

{ 
   'name': 'Mango juice', 
   'amount': 30.00, 
   'spend_date': '2020-10-10' 
   'category': 'Food', 
}

在您最喜欢的编辑器中打开费用管理器应用程序。

接下来,在src/components文件夹下创建一个文件ExpenseEntryItem.css来设置组件的样式。

接下来,通过扩展React.Component在src/components文件夹下创建一个文件ExpenseEntryItem.js

import React from 'react'; 
import './ExpenseEntryItem.css'; 
class ExpenseEntryItem extends React.Component { 
}

接下来,在ExpenseEntryItem类中创建一个render方法。

class ExpenseEntryItem extends React.Component { 
   render() { 
   } 
}

接下来,使用 JSX 创建用户界面并从render方法返回它。

class ExpenseEntryItem extends React.Component {
   render() {
      return (
         <div>
            <div><b>Item:</b> <em>Mango Juice</em></div>
            <div><b>Amount:</b> <em>30.00</em></div>
            <div><b>Spend Date:</b> <em>2020-10-10</em></div>
            <div><b>Category:</b> <em>Food</em></div>
         </div>
      );
   }
}

接下来,将组件指定为默认导出类。

import React from 'react';
import './ExpenseEntryItem.css';

class ExpenseEntryItem extends React.Component {
   render() {
      return (
         <div>
            <div><b>Item:</b> <em>Mango Juice</em></div>
            <div><b>Amount:</b> <em>30.00</em></div>
            <div><b>Spend Date:</b> <em>2020-10-10</em></div>
            <div><b>Category:</b> <em>Food</em></div>
         </div>
      );
   }
}
export default ExpenseEntryItem;

现在,我们成功创建了第一个 React 组件。让我们在index.js中使用新创建的组件。

import React from 'react';
import ReactDOM from 'react-dom';
import ExpenseEntryItem from './components/ExpenseEntryItem'

ReactDOM.render(
   <React.StrictMode>
      <ExpenseEntryItem />
   </React.StrictMode>,
   document.getElementById('root')
);

例子

使用 CDN 在网页中可以完成相同的功能,如下所示 -

<!DOCTYPE html>
<html>
   <head>
      <meta charset="UTF-8" />
      <title>React application :: ExpenseEntryItem component</title>
   </head>
   <body>
      <div id="react-app"></div>
       
      <script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
      <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
      <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
      <script type="text/babel">
         class ExpenseEntryItem extends React.Component {
            render() {
               return (
                  <div>
                     <div><b>Item:</b> <em>Mango Juice</em></div>
                     <div><b>Amount:</b> <em>30.00</em></div>
                     <div><b>Spend Date:</b> <em>2020-10-10</em></div>
                     <div><b>Category:</b> <em>Food</em></div>
                  </div>
               );
            }
         }
         ReactDOM.render(
            <ExpenseEntryItem />,
            document.getElementById('react-app') );
      </script>
   </body>
</html>

接下来,使用 npm 命令为应用程序提供服务。

npm start

输出

接下来,打开浏览器并在地址栏中输入http://localhost:3000并按回车键。

Item: Mango Juice
Amount: 30.00
Spend Date: 2020-10-10
Category: Food

创建功能组件

React 组件也可以使用纯 JavaScript 函数创建,但功能有限。基于函数的 React 组件不支持状态管理和其他高级功能。它可用于快速创建简单的组件。

上面的ExpenseEntryItem可以在函数中重写,如下所示 -

function ExpenseEntryItem() {
   return (
      <div>
         <div><b>Item:</b> <em>Mango Juice</em></div>
         <div><b>Amount:</b> <em>30.00</em></div>
         <div><b>Spend Date:</b> <em>2020-10-10</em></div>
         <div><b>Category:</b> <em>Food</em></div>
      </div>
   );
}

在这里,我们只包含了渲染功能,这足以创建一个简单的 React 组件。

ReactJS - 样式

一般来说,React 允许通过 className 属性使用 CSS 类来设置组件的样式。由于React JSX支持JavaScript表达式,因此可以使用许多常见的CSS方法。一些最重要的选项如下 -

  • CSS 样式表- 普通 CSS 样式以及className

  • 内联样式- CSS 样式作为 JavaScript 对象以及驼峰式属性。

  • CSS 模块- 本地范围的 CSS 样式。

  • 样式化组件- 组件级别样式。

  • Sass stylesheet - 通过在构建时将样式转换为普通 CSS 来支持基于 Sass 的 CSS 样式。

  • 后处理样式表- 通过在构建时将样式转换为普通 CSS 来支持后处理样式。

让我们在本章中学习如何应用三种重要的方法来设计我们的组件。

  • CSS 样式表

  • 内联样式

  • CSS 模块

CSS 样式表

CSS 样式表是常用的、通用的且经过时间考验的方法。只需为组件创建 CSS 样式表并输入该特定组件的所有样式即可。然后,在组件中,使用 className 来引用样式。

让我们设置ExpenseEntryItem组件的样式。

在您最喜欢的编辑器中打开费用管理器应用程序。

接下来,打开ExpenseEntryItem.css文件并添加一些样式。

div.itemStyle { 
   color: brown; 
   font-size: 14px; 
}

接下来,打开ExpenseEntryItem.js并将className添加到主容器。

import React from 'react';
import './ExpenseEntryItem.css';

class ExpenseEntryItem extends React.Component {
   render() {
      return (
         <div className="itemStyle">
            <div><b>Item:</b> <em>Mango Juice</em></div>
            <div><b>Amount:</b> <em>30.00</em></div>
            <div><b>Spend Date:</b> <em>2020-10-10</em></div>
            <div><b>Category:</b> <em>Food</em></div>
         </div>
      );
   }
}
export default ExpenseEntryItem;

接下来,使用 npm 命令为应用程序提供服务。

npm start

接下来,打开浏览器并在地址栏中输入http://localhost:3000并按回车键。

CSS 样式表

CSS 样式表易于理解和使用。但是,当项目规模增大时,CSS 样式也会增加,最终会在类名中产生很多冲突。此外,直接加载CSS文件仅在Webpack捆绑器中支持,在其他工具中可能不支持。

内联样式

内联样式是设计 React 组件最安全的方法之一。它使用基于 DOM 的 css 属性将所有样式声明为JavaScript 对象,并通过样式属性将其设置到组件。

让我们在组件中添加内联样式。

在您喜欢的编辑器中打开费用管理器应用程序并修改src 文件夹中的ExpenseEntryItem.js文件。声明一个对象类型的变量并设置样式。

itemStyle = {
   color: 'brown', 
   fontSize: '14px' 
}

这里,fontSize代表css属性font-size。所有 css 属性都可以通过以驼峰格式表示来使用。

接下来,使用大括号 {} 在组件中设置itemStyle样式 -

render() {
   return (
      <div style={ this.itemStyle }>
         <div><b>Item:</b> <em>Mango Juice</em></div>
         <div><b>Amount:</b> <em>30.00</em></div>
         <div><b>Spend Date:</b> <em>2020-10-10</em></div>
         <div><b>Category:</b> <em>Food</em></div>
      </div>
   );
}

此外,样式可以直接在组件内部设置 -

render() {
   return (
      <div style={
         {
            color: 'brown',
            fontSize: '14px'
         }         
      }>
         <div><b>Item:</b> <em>Mango Juice</em></div>
         <div><b>Amount:</b> <em>30.00</em></div>
         <div><b>Spend Date:</b> <em>2020-10-10</em></div>
         <div><b>Category:</b> <em>Food</em></div>
      </div>
   );
}

现在,我们已经成功地在我们的应用程序中使用了内联样式。

接下来,使用 npm 命令为应用程序提供服务。

npm start

接下来,打开浏览器并在地址栏中输入http://localhost:3000并按回车键。

内联样式

CSS 模块

Css 模块提供了最安全且最简单的方式来定义样式。它使用正常的 css 样式表和正常的语法。在导入样式时,CSS 模块会将所有样式转换为本地范围的样式,这样就不会发生名称冲突。让我们更改组件以使用CSS 模块

在您最喜欢的编辑器中打开费用管理器应用程序。

接下来,在 src/components 文件夹下创建一个新的样式表 ExpenseEntryItem.module.css 文件,并编写常规的 css 样式。

div.itemStyle {
   color: 'brown'; 
   font-size: 14px; 
}

在这里,文件命名约定非常重要。React 工具链会通过CSS Module来预处理以.module.css结尾的 css 文件。否则,它将被视为普通样式表。

接下来,打开src/component文件夹中的ExpenseEntryItem.js文件并导入样式。

import styles from './ExpenseEntryItem.module.css'

接下来,在组件中使用样式作为 JavaScript 表达式。

<div className={styles.itemStyle}>

现在,我们已经在我们的应用程序中成功使用了 CSS 模块。

最终完整的代码是 -

import React from 'react';
import './ExpenseEntryItem.css';
import styles from './ExpenseEntryItem.module.css'

class ExpenseEntryItem extends React.Component {
   render() {
      return (
         <div className={styles.itemStyle} >
            <div><b>Item:</b> <em>Mango Juice</em></div>
            <div><b>Amount:</b> <em>30.00</em></div>
            <div><b>Spend Date:</b> <em>2020-10-10</em></div>
            <div><b>Category:</b> <em>Food</em></div>
         </div>
      );
   }
}
export default ExpenseEntryItem;

接下来,使用 npm 命令为应用程序提供服务。

npm start

接下来,打开浏览器并在地址栏中输入http://localhost:3000并按回车键。

CSS 模块

ReactJS - 属性(props)

React 使开发人员能够使用属性创建动态和高级组件。每个组件都可以具有类似于 HTML 属性的属性,并且可以使用属性 (props) 在组件内部访问每个属性的值。

例如,具有 name 属性的Hello组件可以通过 this.props.name 变量在组件内部访问。

<Hello name="React" />
// value of name will be "Hello* const name = this.props.name

React 属性支持不同类型的属性值。它们如下:

  • 细绳
  • 数字
  • 约会时间
  • 大批
  • 列表
  • 对象

让我们在本章中一一学习。

ReactJS - 事件管理

事件管理是 Web 应用程序的重要功能之一。它使用户能够与应用程序交互。React 支持 Web 应用程序中可用的所有事件。React 事件处理与 DOM 事件非常相似,几乎没有什么变化。让我们在本章中学习如何在 React 应用程序中处理事件。

让我们看看 React 组件中处理事件的逐步过程。

  • 定义一个事件处理程序方法来处理给定的事件。

log() { 
   cosole.log("Event is fired"); 
}

React 提供了一种使用 lambda 函数来定义事件处理程序的替代语法。lambda 语法是 -

log = () =;> { 
   cosole.log("Event is fired"); 
}

如果您想知道事件的目标,请在处理程序方法中添加参数e 。React 会将事件目标详细信息发送到处理程序方法。

log(e) { 
   cosole.log("Event is fired"); 
   console.log(e.target); 
}

另一种 lambda 语法是 -

log = (e) => { 
   cosole.log("Event is fired"); 
   console.log(e.target); 
}

如果您想在事件期间发送额外的详细信息,请添加额外的详细信息作为初始参数,然后添加事件目标的参数(e) 。

log(extra, e) { 
   cosole.log("Event is fired"); 
   console.log(e.target); 
   console.log(extra); 
   console.log(this); 
}

另一种 lambda 语法如下 -

log = (extra, e) => { 
   cosole.log("Event is fired"); 
   console.log(e.target); 
   console.log(extra); 
   console.log(this); 
}

在组件的构造函数中绑定事件处理程序方法。将确保事件处理程序方法中的可用性。

constructor(props) { 
   super(props); 
   this.logContent = this.logContent.bind(this); 
}

如果事件处理程序是用替代 lambda 语法定义的,则不需要绑定。关键字将自动绑定到事件处理程序方法。

设置特定事件的事件处理程序方法,如下所示 -

<div onClick={this.log}> ... </div>

要设置额外的参数,请绑定事件处理程序方法,然后将额外的信息作为第二个参数传递。

<div onClick={this.log.bind(this, extra)}> ... </div>

替代 lambda 语法如下 -

<div onClick={this.log(extra, e)}> ... </div>

这里,

ReactJS - 状态管理

状态管理是任何动态应用程序的重要且不可避免的功能之一。React 提供了一个简单而灵活的 API 来支持 React 组件中的状态管理。本章让我们了解如何在 React 应用程序中维护状态。

什么是状态?

状态表示给定实例下 React 组件的动态属性的值。React 为每个组件提供动态数据存储。内部数据表示 React 组件的状态,可以使用组件的 this.state 成员变量来访问。每当组件的状态发生更改时,组件都会通过调用render()方法以及新状态来重新渲染自身。

为了更好地理解状态管理,一个简单的例子是分析实时时钟组件。时钟组件的主要工作是显示给定实例中某个位置的日期和时间。由于当前时间每秒都会发生变化,因此时钟组件应保持当前日期和时间的状态。由于时钟组件的状态每秒都在变化,因此每秒都会调用时钟的render()方法,并且render()方法使用其当前状态显示当前时间。

状态的简单表示如下 -

{ 
   date: '2020-10-10 10:10:10' 
}

让我们在本章后面创建一个新的Clock组件。

这里,

ReactJS - Http 客户端编程

Http 客户端编程使应用程序能够通过 JavaScript 连接 http 服务器并获取数据。它减少了客户端和服务器之间的数据传输,因为它仅获取所需的数据而不是整个设计,从而提高了网络速度。它改善了用户体验,成为每个现代 Web 应用程序不可或缺的功能。

如今,许多服务器端应用程序通过 REST API(基于 HTTP 协议的功能)公开其功能,并允许任何客户端应用程序使用该功能。

React 不提供自己的 http 编程 api,但它支持浏览器内置的fetch() api 以及 axios 等第三方客户端库来进行客户端编程。本章让我们学习如何在 React 应用程序中进行 http 编程。开发人员应该具备 Http 编程的基本知识才能理解本章。

费用休息 API 服务器

进行Http编程的前提是具备Http协议和REST API技术的基础知识。Http编程涉及两部分,服务器和客户端。React 提供创建客户端应用程序的支持。Express 是一个流行的 Web 框架,提供创建服务器端应用程序的支持。

让我们首先使用 Express 框架创建一个 Expense Rest Api 服务器,然后使用浏览器的内置 fetch api从ExpenseManager应用程序访问它。

打开命令提示符并创建一个新文件夹express-rest-api

cd /go/to/workspace 
mkdir apiserver 
cd apiserver

使用以下命令初始化新的节点应用程序 -

npm init

npm init会提示并要求我们输入基本的项目详细信息。让我们输入apiserver作为项目名称,输入 server.js作为入口点。将其他配置保留为默认选项。

This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (apiserver)
version: (1.0.0)
description: Rest api for Expense Application
entry point: (index.js) server.js
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to \path\to\workspace\expense-rest-api\package.json:
{
   "name": "expense-rest-api",
   "version": "1.0.0",
   "description": "Rest api for Expense Application",
   "main": "server.js",
   "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1"
   },
   "author": "",
   "license": "ISC"
}
Is this OK? (yes) yes

接下来,使用以下命令安装express、nedb和cors模块 -

npm install express nedb cors
  • Express用于创建服务器端应用程序。

  • nedb是用于存储费用数据的数据存储。

  • cors是Express框架的中间件,用于配置客户端访问详细信息。

接下来,让我们创建一个文件 data.csv 并在其中填充初始费用数据以进行测试。该文件的结构是每行包含一个费用条目。

Pizza,80,2020-10-10,Food
Grape Juice,30,2020-10-12,Food
Cinema,210,2020-10-16,Entertainment
Java Programming book,242,2020-10-15,Academic
Mango Juice,35,2020-10-16,Food
Dress,2000,2020-10-25,Cloth
Tour,2555,2020-10-29,Entertainment
Meals,300,2020-10-30,Food
Mobile,3500,2020-11-02,Gadgets
Exam Fees,1245,2020-11-04,Academic

接下来,创建一个文件expenddb.js并包含用于将初始费用数据加载到数据存储中的代码。该代码检查数据存储中的初始数据,并且仅当数据在存储中不可用时才加载。

var store = require("nedb")
var fs = require('fs');
var expenses = new store({ filename: "expense.db", autoload: true })
expenses.find({}, function (err, docs) {
   if (docs.length == 0) {
      loadExpenses();
   }
})
function loadExpenses() {
   readCsv("data.csv", function (data) {
      console.log(data);

      data.forEach(function (rec, idx) {
         item = {}
         item.name = rec[0];
         item.amount = parseFloat(rec[1]);
         item.spend_date = new Date(rec[2]);
         item.category = rec[3];

         expenses.insert(item, function (err, doc) {
            console.log('Inserted', doc.item_name, 'with ID', doc._id);
         })
      })
   })
}
function readCsv(file, callback) {
   fs.readFile(file, 'utf-8', function (err, data) {
      if (err) throw err;
      var lines = data.split('\r\n');
      var result = lines.map(function (line) {
         return line.split(',');
      });
      callback(result);
   });
}
module.exports = expenses

接下来,创建一个文件server.js并包含用于列出、添加、更新和删除费用条目的实际代码。

var express = require("express")
var cors = require('cors')
var expenseStore = require("./expensedb.js")
var app = express()
app.use(cors());
var bodyParser = require("body-parser");
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
var HTTP_PORT = 8000
app.listen(HTTP_PORT, () => {
   console.log("Server running on port %PORT%".replace("%PORT%", HTTP_PORT))
});
app.get("/", (req, res, next) => {
   res.json({ "message": "Ok" })
});
app.get("/api/expenses", (req, res, next) => {
   expenseStore.find({}, function (err, docs) {
      res.json(docs);
   });
});
app.get("/api/expense/:id", (req, res, next) => {
   var id = req.params.id;
   expenseStore.find({ _id: id }, function (err, docs) {
      res.json(docs);
   })
});
app.post("/api/expense/", (req, res, next) => {
   var errors = []
   if (!req.body.item) {
      errors.push("No item specified");
   }
   var data = {
      name: req.body.name,
      amount: req.body.amount,
      category: req.body.category,
      spend_date: req.body.spend_date,
   }
   expenseStore.insert(data, function (err, docs) {
      return res.json(docs);
   });
})
app.put("/api/expense/:id", (req, res, next) => {
   var id = req.params.id;
   var errors = []
   if (!req.body.item) {
      errors.push("No item specified");
   }
   var data = {
      _id: id,
      name: req.body.name,
      amount: req.body.amount,
      category: req.body.category,
      spend_date: req.body.spend_date,
   }
   expenseStore.update( { _id: id }, data, function (err, docs) {
      return res.json(data);
   });
})
app.delete("/api/expense/:id", (req, res, next) => {
   var id = req.params.id;
   expenseStore.remove({ _id: id }, function (err, numDeleted) {
      res.json({ "m