读书笔记《hands-on-full-stack-development-with-spring-boot-2-0-and-react》Reaction快速入门
在本书中,我们使用 Windows 操作系统,但所有工具也可用于 Linux 和 macOS。
根据 Facebook 的说法,React 是一个用于用户界面的 JavaScript 库。从版本 15 开始,React 是在 MIT 许可下开发的。 React 是基于组件的,组件是独立且可重用的。这些组件是 React 的基本 构建块。当你开始使用 React 开发用户界面时,最好从创建开始 一个模拟接口。这样,很容易确定您必须创建什么样的组件以及它们如何交互。
从下面的 mock 图中,我们可以看到如何将用户界面拆分为组件。在这种情况下,将有一个应用程序根组件、一个搜索栏组件、一个表格组件和一个表格行组件:
然后可以将组件排列在以下树层次结构中。使用 React 要理解的重要一点是数据流是从父组件流向子组件的:
React 使用虚拟 DOM 来选择性地重新渲染用户界面,这使得它更具成本效益。 Virtual DOM 是 DOM 的轻量级copy,对虚拟 DOM 的操作比真实 DOM 快得多。更新虚拟 DOM 后,React 会将其与更新运行之前从虚拟 DOM 中获取的快照进行比较。比较之后,React 就知道哪些部分被改变了,只有这些部分被更新到真实的 DOM 中。
可以使用 JavaScript 函数或 ES6 JavaScript 类来定义 React 组件。我们将在下一节更深入地介绍 ES6。以下是呈现 Hello World
文本的简单组件源代码。第一个代码块使用 JavaScript 函数:
而这个是使用类来创建一个组件:
使用该类实现的组件包含必需的 render()
方法。此方法显示并更新组件的渲染输出。用户定义组件的名称应以大写字母开头。
让我们更改组件的 render
方法,并在其中添加新的 header 元素:
当您运行应用程序时,您会收到 相邻的 JSX 元素必须包含在封闭标记中
错误。要修复此错误,我们必须将 headers 包装在一个元素中,例如 div
;从 React 16.2 版本开始,我们还可以使用 Fragments
,看起来像空的 JSX 标签:
让我们更仔细地看一下我们在上一章中使用 create-react-app
创建的第一个 React 应用程序。根目录下Index.js
文件源码如下:
在文件的开头,有 import
将组件或资产加载到我们的文件中的语句。例如,第二行从 node_modules
文件夹中导入 react-dom
包,第四行行导入 App
(根文件夹中的 App.js
文件)组件。 react-dom
包为我们提供了特定于 DOM 的方法。要将 React 组件渲染到 DOM,我们可以使用 render
方法来自 react-dom
包裹。第一个参数是要渲染的组件,第二个参数是 element 或容器将被渲染。在这种情况下, root
元素是 <div id="root"></div>
,可以在 public
文件夹内的 index.html
文件中找到。请参阅以下 index.html
文件:
以下源代码显示了我们第一个 React 应用程序中的 App.js
组件。您可以看到 import
也适用于资产,例如图像和样式表。在源代码的末尾,有一个 export
语句,用于导出组件,并通过 import 提供给其他组件。每个文件只能有一个默认导出,但可以有多个命名导出:
以下示例显示如何导入默认导出和命名导出:
导出如下所示:
ES6(ECMAScript 2015)于 2015 年发布,它 < span>引入了 很多新功能。 ECMAScript 是一种标准化的脚本语言和 JavaScript 是它的一种实现。在这里,我们将介绍 ES6 中发布的最重要 特性,我们将在下一节中使用这些特性。
常量或不可变变量可以使用 const
关键字来定义。当使用 const
关键字时,变量内容 不能 被重新赋值:
const
的作用域是块作用域,与 let
的作用域相同。这意味着 const
变量只能在定义它的块内使用。实际上,块是大括号 { }
之间的区域。以下示例代码显示了作用域的工作原理。第二个console.log
语句给出了错误,因为我们试图在范围之外使用 total
变量:
很高兴知道如果 const
是对象或数组,则可以更改内容。以下示例说明:
箭头函数使函数声明 much 更加紧凑。在 JavaScript 中定义函数的传统方式是使用 function
关键字。以下函数获取一个参数并仅返回参数值:
通过使用 ES6 箭头函数,函数如下所示:
如果您有多个参数,则必须将参数括在括号中并用逗号分隔参数。以下函数获取两个参数并返回参数的总和。如果函数体是表达式,则不需要使用 return
关键字。表达式总是从函数中隐式返回:
如果函数没有任何参数,则语法如下:
ES6 中的类定义类似于 Java 或 C# 等其他面向对象的语言。定义类的关键字是class
。类可以有字段、构造函数和类方法。以下示例代码显示了 ES6 类:
继承是通过一个 extends
关键字完成的。以下 sample 代码显示了一个 Employee
类,它继承了一个 < code class="literal">Person 类。因此,它继承 来自父类的所有字段,并且可以拥有自己的特定于员工的字段。在构造函数中,我们首先使用 super
关键字调用父类构造函数。该调用是必需的,如果丢失,您将收到错误消息:
尽管 ES6 已经很老了,但它仍然只被现代 Web 浏览器部分支持。 Babel 是一个 JavaScript 编译器,用于将 ES6 编译为兼容所有浏览器的旧版本。你可以在 Babel 网站(https://babeljs.io)上测试编译器。以下屏幕截图显示了编译回旧 JavaScript 语法的箭头函数:
JSX 是 JavaScript 的语法扩展。将 JSX 与 React 一起使用并不是强制性的,但有一些好处可以使开发更容易。例如,JSX 可以防止注入攻击,因为在呈现 它们 之前,所有值都在 JSX 中进行了转义。最有用的功能是您可以将 JavaScript 表达式嵌入到 JSX 中,方法是用 with 大括号在后面的章节中使用了很多。在这个例子中,我们可以在使用 JSX 时访问组件的 props。组件道具将在下一节中介绍:
您还可以将 JavaScript 表达式作为道具传递:
JSX 被 Babel 编译为React.createElement()
调用。您可以对 React JSX 元素使用内部或外部样式。以下是内联样式的两个示例。第一个直接在 div
元素内定义样式:
第二个示例首先创建样式对象,然后将其用于 div
元素。对象名称应使用 camelCase 命名约定:
如上一节所示,您可以将样式表导入 React 组件。要从外部 CSS 文件中引用类,您应该使用 className
属性:
Props 和 state 是用于渲染组件的输入 data。 props 和 state 实际上都是 JavaScript 对象,当 props 或 state 发生变化时,组件会重新渲染。
props 是不可变的,因此组件无法更改其 props。 props 是从父组件接收的。组件可以通过 this.props
对象访问props。例如,看一下以下组件:
父组件可以通过以下方式向 Hello
组件发送 props:
当 Hello
组件被渲染时,它会显示 Hello World John
文本。
可以在组件内部更改状态。状态的初始值在组件的构造函数中给出。可以使用 this.state
对象访问状态。状态的范围是组件,因此它不能在定义它的组件之外使用。正如您在下面的示例中看到的,道具作为参数传递给构造函数,并且状态在构造函数中被初始化。然后可以使用大括号在 JSX 中呈现状态值, {this.state.user}
:
状态可以包含多个不同类型的值,因为它是一个 JavaScript 对象,如下例所示:
使用 setState
方法更改状态的值:
您永远不应该通过 使用 等号运算符来更新状态,因为这样 React 不会重新渲染组件。更改状态的唯一方法是使用 setState
方法,该方法会触发重新渲染:
setState
方法是异步的,因此您无法确定何时更新状态。 setState
方法有一个回调函数,在状态更新时执行。
状态的使用始终是可选的,它增加了组件的复杂性。只有 props 的组件被称为 stateless< /span> 组件。当输入相同时,它总是会呈现相同的输出,这意味着它们非常容易测试。同时具有状态和 props 的组件称为 stateful 组件。以下是简单无状态组件的示例,它是使用类定义的。您还可以使用以下函数定义它:
如果要更新依赖于当前状态的状态值,则应将更新函数传递给 setState()
方法而不是对象。演示这种情况的一个常见案例是此处显示的反例:
React 组件有许多可以覆盖的生命周期方法。这些方法在组件生命周期的某些阶段执行。 生命周期方法的名称是合乎逻辑的,您几乎可以猜到 什么时候 它们将被执行。带有前缀的生命周期方法在发生任何事情之前执行,带有前缀的方法在发生事情之后执行。挂载是组件生命周期的一个阶段,它是组件被创建并插入 DOM 的时刻。 我们已经介绍过的两个生命周期方法在组件挂载时执行: constructor()
和 render()
。
挂载阶段一个有用的方法是 componentDidMount()
,在组件被挂载后调用。此方法适用于调用一些 REST API 来获取数据,例如。以下示例代码给出了使用 componentDidMount()
方法的示例。
在下面的示例代码中,我们首先将 this.state.user
的初始值设置为 John
。然后,当组件被挂载时,我们将值更改为 Jim
:
还有一个 componentWillMount()
在组件挂载之前调用的生命周期方法,但Facebook建议不要使用它,因为它可能用于内部开发目的.
shouldComponentUpdate()
方法在 state 或 props 已经更新并且组件被渲染之前被调用。该方法将新的道具作为第一个参数,将新的状态作为第二个参数,并返回布尔值。如果返回值为true
,则重新渲染组件;否则,它不会被重新渲染。此方法允许您避免无用的渲染并提高性能:
componentWillUnmount()
生命周期方法在组件从 DOM 中移除之前被调用。这是清理资源、清除计时器或取消请求的好方法。
错误边界是在其子组件树中捕获 JavaScript 错误的组件。他们还应该记录这些错误并在用户界面中显示回退。为此,有一个名为 componentDidCatch()
的生命周期方法。它适用于 React 组件,例如标准 JavaScript catch
块。
对于列表处理,我们引入了 new JavaScript 方法, map()< /code>,这在您必须操作列表时很方便。
map()
方法创建一个新数组,其中包含对原始数组中每个元素调用函数的结果。在以下示例中,每个数组元素都乘以 2:
map()
方法还有 index
第二个参数,这在 React 中处理列表时很有用。 React 中的列表项需要一个唯一键,用于检测已更改、添加或删除的行。
以下示例显示了将整数数组转换为列表项数组并在 ul
元素中呈现它们的组件:
以下屏幕截图显示了组件在渲染时的样子:
如果数据是一个对象数组,那么更好 以表格形式呈现数据。这个想法和列表一样,但是现在我们只是将数组映射到表格行并在表格元素中呈现它们,如下面的代码所示:
以下屏幕截图显示了组件在渲染时的样子:
React 中的事件处理类似于处理 DOM 元素事件。与 HTML 事件处理相比,不同之处在于事件 naming 在 React 中使用 camelCase。以下示例代码为按钮添加了一个事件侦听器,并在按下按钮时显示警报消息:
在 React 中,您不能从事件处理程序返回 false
以防止默认行为。相反,您应该调用 preventDefault()
方法。在下面的示例中,我们正在使用一个表单并且我们想要阻止表单提交:
表单处理与 React 有点不同。提交时,HTML 表单将导航到下一页。一个常见的情况是 我们希望调用一个 JavaScript 函数,该函数在提交后可以访问表单数据并避免导航到下一个页。我们已经在上一节中介绍了如何使用 preventDefault()
来避免提交。
让我们首先创建一个带有一个输入字段和提交按钮的简约表单。为了能够获取输入字段的值,我们使用了 onChange
事件处理程序。当输入字段的值改变时,新的值将被保存到状态。 this.setState({text: event.target.value});
语句从输入字段中获取值并将其保存到名为 文本
。最后,我们将在用户按下提交按钮时显示键入的值。以下是我们第一个表单的源代码:
下面是我们的表单组件在 Submit
按钮被按下后的截图:
现在是查看 React 开发人员工具的好时机,它们是调试 React 应用程序的便捷工具。如果我们使用我们的 React 表单应用程序打开 React 开发者工具并在输入字段中输入一些内容,我们可以看到 value的状态变化。我们可以查看 的当前值道具和状态。以下屏幕截图显示了当我们在输入字段中输入内容时状态如何变化:
通常,我们在表单中有多个输入字段。处理多个输入字段的一种方法是添加与输入字段一样多的更改处理程序。但这会产生很多样板代码,这是我们想要避免的。因此,我们将名称属性添加到我们的输入字段中,我们可以在更改处理程序中使用它来识别哪个输入字段触发更改处理程序。输入字段的名称属性值必须与我们要保存该值的状态的名称相同。
处理程序现在如下所示。如果触发处理程序的输入字段是名字字段,则 event.target.name
是 firstName
和键入的值将保存到名为 firstName
的状态。通过这种方式,我们可以使用一个更改处理程序来处理所有输入字段:
以下是该组件的完整源代码:
Packt 还有其他学习 React 的好资源: