React系列笔记学习
中篇笔记地址:【超全】React学习笔记 中:进阶语法与原理机制
下篇笔记地址:【超全】React学习笔记 下:路由与Redux状态管理
React 是一个由 Facebook 开发并维护的用于构建用户界面的 JavaScript 库。它被广泛用于构建单页应用(SPA),尤其是复杂的交互式用户界面。React 允许开发人员构建 Web 应用程序,这些程序可以在数据更改时自动更新和渲染,而无需重新加载页面。
组件化:
声明式编程:
虚拟DOM(Virtual DOM):
单向数据流:
组件生命周期:
状态管理(State & Props):
事件处理:
条件渲染和列表渲染:
import React from 'react';
import ReactDOM from 'react-dom';
// 创建一个组件
class HelloWorld extends React.Component {
render() {
return (
<div>Hello, World!</div>
);
}
}
// 渲染组件到页面
ReactDOM.render(<HelloWorld />, document.getElementById('root'));
在这个示例中,我们创建了一个简单的 HelloWorld
组件,并使用 ReactDOM.render
方法将其渲染到页面上。React通过组件化的方式使得开发者能够以模块化和可维护的方式构建应用程序,同时通过声明式编程、虚拟DOM和单向数据流等特点,使得开发高效、简洁和高性能的应用成为可能。
创建和渲染React元素是React应用的基础。下面是这两个方面的介绍和示例代码:
React元素是构建React应用的最小单位。你可以使用React.createElement
方法来创建一个React元素。此方法接受三个参数:
type
(类型):元素的类型,例如'div'
、'span'
等,或者一个React组件。props
(属性):一个对象,包含传递给该元素的属性和值。children
(子元素):该元素的子元素,可以是文本、React元素或数组。childrens
(更多子元素):这个可以放多个createElement,会被一桶方进入去const element = React.createElement(
'h1',
{ className: 'greeting' },
'Hello, world!'
);
除了React.createElement
,你还可以使用JSX来创建React元素,它是一种JavaScript的语法扩展,看起来更像是XML或HTML。使用JSX通常会使你的代码更易读和编写。
const element = <h1 className="greeting">Hello, world!</h1>;
要将React元素渲染到DOM中,你可以使用ReactDOM.render
方法。此方法接受两个参数:
element
(元素):你想要渲染的React元素。container
(容器):你想要将React元素渲染到的DOM容器。const container = document.getElementById('root');
ReactDOM.render(element, container);
将以下代码放入你的HTML文件中,你会看到一个显示"Hello, world!"的标题元素。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React Exampletitle>
<script src="https://unpkg.com/react@17/umd/react.development.js">script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js">script>
head>
<body>
<div id="root">div>
<script type="text/javascript">
const element = <h1 className="greeting">Hello, world!</h1>;
const container = document.getElementById('root');
ReactDOM.render(element, container);
script>
body>
html>
在这个示例中,我们首先加载了React和ReactDOM库,然后创建了一个名为 JSX是JavaScript XML的缩写,它允许你在JavaScript中写HTML。表示在JavaScript代码中写XML ( HTML)格式的代码。优势︰声明式语法更加直观、与HTML结构相同,降低了学习成本、提升开发效率。这种语法糖可以使你的代码更容易编写和阅读,并且React元素通常是通过JSX创建的。 createElement()的问题 繁琐不简洁。 不直观,无法一眼看出所描述的结构。 不优雅,用户体验不爽。 React的 以下是一个例子,说明通过 使用 在上面的代码中,我们尝试创建一个包含标题、段落和列表的容器。你可以看到,代码非常繁琐和嵌套,很难一眼看出元素的结构。 使用JSX创建相同的复杂节点: This is a complex element. 在上面的JSX版本中,代码更简洁、更直观、更易读。你可以很容易地看出元素的结构,而不需要通过多层嵌套的 驼峰命名法: 特殊属性名: 当您在JSX中创建React元素时,有一些HTML属性名需要以特殊的JSX属性名来代替。这是因为 class -> className: for -> htmlFor: tabindex -> tabIndex: 以上的例子明确了在JSX中使用特殊属性名的重要性,以及如何正确地使用它们。 自闭合标签: 没有子节点的React元素: 具有子节点的React元素: Hello, world! 在上面的例子中, 使用小括号包裹JSX: Hello, world! Hello, world! 以上的细节和规范可以帮助开发者在编写JSX代码时保持清晰和一致,避免常见的错误和陷阱。 使用步骤︰ 为什么脚手架create react-app能使用JSX语法? 你可以在JSX中的大括号内放入任何有效的JavaScript表达式。例如, 语法∶ {JavaScript表达式} 注意∶语法中是单大括号,不是双大括号! 不要与Vue混淆! 在JSX中,可以使用单大括号 在JSX中,您可以在大括号中放置任何JavaScript表达式。例如: 在这个例子中, JSX表达式本身也是JavaScript表达式,这意味着您可以在if语句、for循环、赋值、参数、运算符等JavaScript代码结构中使用JSX。 虽然您可以在JSX中的大括号内放置任何表达式,但直接放置一个对象字面量是个例外。如果您尝试这样做,JSX会将其解释为多个单独的表达式而不是一个对象表达式。所以,如果您想传递一个对象,您应该包裹它在圆括号里。 例如,以下代码是错误的: 正确的做法应该是: 在JSX的大括号内,您不能使用语句,比如 例如,您不能直接在JSX中这样做: 但您可以这样做: 在这个例子中,我们使用了条件(三元)运算符来实现条件渲染。 条件渲染是根据某些条件动态显示不同的UI结构。在React中,你可以使用JavaScript的条件语句(如 在React中,你可以在函数的外部或内部使用 在上述代码中,如果 你也可以使用三元运算符 逻辑与运算符 在上述代码中,如果 列表渲染是在React中很常见的操作。通常你会有一个数组的数据,你需要将其转换为一个由React元素组成的数组,然后将它们显示在UI中。 1. 使用 在React中,你可以使用 注意: 嵌套组件中的列表渲染: 在React和JSX中,可以通过几种不同的方法来处理样式。以下是两种常见的方法。 在React中,行内样式不是作为字符串,而是作为一个对象来使用的。样式属性的名称采用驼峰命名法(camelCase),而不是短划线命名法。此外,属性值作为字符串提供。下面是一个示例: 在上述代码中,我们首先创建了一个名为 可以使用 在上述代码中,我们为 注意 在React的世界里,JSX扮演了非常重要的角色,它为我们提供了一种在JavaScript中书写HTML的方式,降低了学习曲线,同时提升了开发效率。通过对JSX的使用,我们能够快速且直观地创建React元素,使得代码更为简洁和易读。下面是对前面内容的简单总结: 通过上述的详细介绍和示例,应该能够对JSX有一个全面且深入的理解,知道如何在React项目中利用JSX来创建和渲染UI结构,以及如何处理常见的使用细节和常见问题。这为接下来的React学习和开发打下了坚实的基础。 在React的世界中,组件是核心的构建块,它们是React应用的基础。通过组件,我们可以将UI拆分成独立可重用的片段,每个片段都可以单独思考。这种模块化的设计方式不仅提高了代码的可维护性,同时也为复杂的应用开发提供了清晰的结构。 组件是React的一等公民: 使用React就是在用组件: 组件表示页面中的部分功能: 组合多个组件实现完整的页面功能: 特点: 可复用、独立、可组合: 通过理解和运用组件的这些特点,我们可以更好地组织和管理React应用的代码,同时也能更高效地开发和维护复杂的应用程序。 在React中,有两种主要的组件创建方式,分别是通过函数和通过类来创建组件。每种方法都有其特点和用途,下面将分别介绍这两种方法的基本使用和特点。 使用函数来创建组件是React中最常见也最简单的组件创建方式。通过定义一个JavaScript函数,并返回一些 JSX,我们就能创建一个简单的React组件。这种类型的组件通常被称为“函数组件”。 函数组件是React的基础,它们提供了一种简单、清晰和易于理解的方式来创建组件。随着React的发展,函数组件通过Hooks得到了极大的增强,使得它们不仅仅是表现组件,还能拥有状态和其他复杂功能,但这已经超越了基本的函数组件范畴。 特点: 基本语法 类组件是利用ES6的 下面是一个简单的类组件创建示例: 在上述示例中,我们创建了一个名为 这个简单的示例展示了创建和使用类组件的基本步骤。通过继承 随着项目规模的扩大和组件数量的增加,组织和管理这些组件变得至关重要。一种常见的做法是将每个组件放在一个单独的JS文件中,这样做有助于保持代码的清晰和模块化。下面是如何将组件抽离到独立JS文件中的步骤: 创建组件文件: 导入React: 创建组件: 导出组件: 导入组件: 渲染组件: 通过以上步骤,您已经将 在React中,事件处理程序的命名和DOM中稍有不同,但大体相似,主要体现在以下几点: 事件命名: 事件绑定语法: 以下是在类组件和函数组件中绑定事件的例子: 在上述代码中,我们创建了一个名为 在上述代码中,我们在函数组件内部定义了一个名为 通过这些例子,您可以看到在类组件和函数组件中绑定事件的方式是非常相似的。最主要的区别是在类组件中,事件处理函数通常是类的方法,而在函数组件中,事件处理函数通常是组件函数内部的函数。同时,注意React事件的命名和绑定语法,以确保事件能够正确触发。 在React的事件处理程序中,可以通过参数获取到事件对象。React有自己的事件对象系统,称为合成事件(Synthetic Event),**它是对浏览器的原生事件的跨浏览器封装。这意味着React的事件对象具有统一的属性和方法,无论在哪个浏览器中运行,都能保证相同的行为。**这有助于处理跨浏览器兼容性问题,使得在不同浏览器中的事件处理变得更简单、更一致。 以下是一个简单的示例,展示了如何在事件处理函数中访问事件对象,并使用它来阻止默认行为: 在上述代码中,我们创建了一个名为 另外,我们也展示了如何在事件绑定时直接传递事件对象,并在箭头函数中处理事件对象。这种方式可以让我们在事件处理函数中直接访问事件对象,而无需创建一个单独的事件处理函数。这在处理简单事件时可能会很方便。 在React中,组件分为有状态组件和无状态组件两大类。这个分类基于组件是否具有内部状态(state)。状态是React组件中存储数据的地方,它决定了组件的行为和显示。 无状态组件通常使用函数来创建,它仅依赖于外部传入的props来确定渲染结果,没有自己的状态(state),也没有生命周期方法。由于它们只是纯函数,无状态组件通常更简单、更容易理解和维护。以下是一个简单的无状态组件示例: 在上述代码中, 有状态组件通常使用类来创建,并且拥有内部状态(state)和生命周期方法。有状态组件可以在内部管理数据,响应事件,并在数据变化时自动更新UI。所以,有状态的类组件通常用于需要与用户操作进行反馈的组件中去使用。以下是一个简单的计数器,可以作为 有状态组件示例: 在上述代码中, 总结来说,无状态组件和有状态组件是React中两种主要的组件类型,无状态组件用于简单的、纯展示性的任务,而有状态组件用于更复杂的、交互式的任务。在设计React应用时,应根据组件的职责和需求来选择合适的组件类型。 在React组件中, 在上述代码中,我们首先通过 当我们需要修改组件的状态时,不能直接修改 在上述代码中,我们定义了一个事件处理函数 总的来说, 在React中,组件的状态是可以变化的,但是我们不能直接修改 React框架遵循数据驱动视图的思想,即状态( 下面是一个 在这个例子中, 在React的类组件中,事件处理器的 箭头函数不会创建自己的 在上述代码中, 另一种方式是在 在这个例子中,我们在 这两种方式都可以保证事件处理器中 在ES5中, 在上述代码中: 通过使用 在React中,确保事件处理程序中 通过使用箭头函数定义类的实例方法,可以确保 在事件处理属性中直接使用箭头函数也可以确保 通过在构造函数中使用 以上三种方法根据个人和项目的需求可以选择使用,其中使用类的实例方法是比较现代且简洁的方法。 在React中,表单处理可以通过两种主要方式来完成:受控组件和非受控组件。下面我们分别介绍这两种方式: 受控组件是指其表单数据由React组件的state管理的表单元素。在受控组件中,表单元素的值由state决定,并通过事件处理程序更新。 步骤: 通过上述步骤,我们就创建了一个受控组件。在这个例子中, 在受控组件中,表单元素的值由React组件中的state控制。以下是一个完整的实例,包括文本框、下拉框和复选框的操作: 在以上示例中,通过定义状态 文本框、富文本框、下拉框:通过操作 复选框:通过操作 受控组件多表单元素优化: 在处理表单时,如果表单元素很多,为每个表单元素编写单独的处理函数可能会很繁琐。一个更好的方法是编写一个通用的处理函数,它可以处理所有表单元素的变化。以下是如何实现这个优化的示例: 在上面的代码中,我们实现了以下几点优化: 与受控组件不同,非受控组件不通过 state 来保存表单元素的值,而是直接通过 DOM 来操作。非受控组件更接近于传统的 HTML 表单处理方式。 步骤: 完整示例: 下面是一个非受控组件的完整示例,演示了如何通过 ref 来获取表单元素的值。 在这个示例中,我们首先通过 通过上述步骤,我们实现了一个非受控组件。在实际应用中,通常推荐使用受控组件来处理表单数据,因为它们可以更好地集成在 React 组件的状态管理系统中,但在某些情况下,非受控组件可能会更简单或方便,但是React官方不推荐使用非受控组件,因为它会设计到DOM操作,而DOM操作会消耗大量时间和内存,不利于网站系统。 React 是一个用于构建用户界面的 JavaScript 库,其核心思想是通过组件来构建应用。下面,我们将深入探讨 React 组件的基础知识,包括组件的创建、状态管理、事件处理以及表单处理。 在 React 中,组件可以通过两种方式来创建:函数组件和类组件。 1.1 函数组件 1.2 类组件 2.1 无状态组件 2.2 有状态组件 在 React 组件中,事件处理程序中 在上述代码中,我们使用箭头函数来确保 React 中的表单处理可以通过受控组件和非受控组件两种方式来实现。受控组件通过 受控组件示例: 非受控组件示例: React 强调组件化的设计和开发方式,充分利用 JavaScript 语言的能力来创建和组织组件。这种设计思想使得开发者能够构建复杂、可维护和高效的前端应用。 通过以上的介绍和示例,你应该对 React 组件的基础有了更深刻的理解。从组件的创建方式、状态管理、事件处理到表单处理,这些基础知识是掌握 React 开发的重要基础。 React 脚手架是一个用来帮助开发者快速创建和配置一个新的 React 项目的工具。它通过预配置好的工具和默认的项目结构,使得开发者可以立即开始编写 React 代码,而不需要花费时间去配置 Babel、Webpack 等开发工具。其中,最知名的 React 脚手架工具是 Create React App。 xxx脚手架: 用来帮助程序员快速创建一个基于xxx库的模板项目 包含了所有需要的配置(语法检查、jsx编译、devServer…) 下载好了所有相关的依赖 可以直接运行一个简单效果 react提供了一个用于创建react项目的脚手架库: create-react-app 项目的整体技术架构为: react + webpack + es6 + eslint 使用脚手架开发的项目的特点: 模块化, 组件化, 工程化 创建一个新的 React 应用非常简单。React 团队提供了一个叫做 Create React App 的官方脚手架工具,它可以帮助你快速地搭建好基础的项目结构,包括一些基础的配置,比如 Babel 和 Webpack 等。以下是使用 Create React App 创建一个新的 React 应用的步骤: React 应用的开发和构建依赖于 Node.js 和 npm,所以在开始之前,请确保你的系统上已经安装了它们。你可以在命令行中运行以下命令来检查它们是否已经安装: 如果你的系统上还没有安装 Node.js 和 npm,你可以去 Node.js 官网 下载并安装最新版本的 Node.js,npm 会随同 Node.js 一起安装。 打开你的终端或命令提示符,然后运行以下命令来创建一个新的 React 应用: 在这里, 创建完应用后,切换到项目目录,并运行以下命令来启动应用: 现在,你的新 React 应用应该已经在浏览器中打开了,并且你应该能够看到一个简单的欢迎页面。你可以开始编辑 这样,你就成功地使用 Create React App 创建了一个新的 React 应用,并且为开始开发做好了准备。 进入React库内之后你会看到src文件夹,你可以在此之内随便创建一个js文件,并输入 这样,你就可以使用你的ReactApp内的React库了。 public ---- 静态资源文件夹 src ---- 源码文件夹 上述配置主要是一个基础的HTML模板,它为React应用程序提供了一个起始点。在React应用程序中,所有的组件将会被渲染到 逻辑流程: 通过这个文件结构和逻辑流程,可以看出 Create React App 脚手架提供了一个很好的起点,帮助开发者快速开始构建 React 应用。同时,它的配置也可以通过 eject 或其他方法进行定制,以适应更复杂的项目需求。 SPA (Single Page Application, 单页应用程序) 是一种现代的网页应用架构,它通过在客户端动态重写页面内容,而不是从服务器加载新的页面,来提供更接近于原生应用的用户体验。下面是SPA架构的主要特点和组成部分: 主要特点: 组成部分: HTML/CSS/JavaScript: 前端框架/库: 前端路由: 状态管理: 模块打包工具: 网络请求: 后端 API: 工作流程: SPA 架构的优点是用户体验好、响应快速,而缺点则可能包括首屏加载时间较长、SEO 优化困难等。不过,随着服务端渲染 (SSR) 和预渲染 (Prerendering) 等技术的发展,这些问题得到了一定程度的解决。 React 是构建用户界面的库,非常适合用于构建 SPA。下面是在 React 中实现 SPA 的基本概念和步骤: 组件化: 路由: 状态管理: 按需加载: 具体步骤如下: 创建 React 项目: 安装 React Router: 配置路由: 创建页面组件: 启动应用: 通过以上步骤,你就可以创建一个基本的 SPA,并通过 React Router 管理不同的视图。随着项目的增长,你可能还需要考虑状态管理、API 交互、错误处理等其他方面的问题。root
的ReactDOM.render
方法将其渲染到root
元素中。
JSX概念与理解使用
JSX的基本使用:
const element = <h1>Hello, world!</h1>;
为什么学习JSX
React.createElement
函数虽然功能强大,但在创建复杂节点时可能会显得非常繁琐和不直观。React.createElement
创建一个包含多个元素和文本的复杂节点的过程,以及同样的节点如何通过JSX轻松创建。React.createElement
创建复杂节点:const complexElement = React.createElement(
'div',
{ className: 'container' },
React.createElement(
'h1',
null,
'Hello, world!'
),
React.createElement(
'p',
null,
'This is a complex element.'
),
React.createElement(
'ul',
null,
[1, 2, 3, 4, 5].map((number, index) =>
React.createElement(
'li',
{ key: index },
number
)
)
)
);
ReactDOM.render(
complexElement,
document.getElementById('root')
);
const complexElementJSX = (
Hello, world!
{[1, 2, 3, 4, 5].map((number, index) => (
React.createElement
调用来理解。这显示了为什么学习和使用JSX是有用的,它可以大大简化React元素的创建和渲染过程,提高开发效率和代码的可读性。使用细节
在JSX中,所有的React元素属性名应使用驼峰命名法 (camelCase),而不是HTML中的短横线命名法 (kebab-case)。例如,HTML中的tabindex
在JSX中应该写为tabIndex
。// 正确
// 错误
class
,for
,和tabindex
在JavaScript中是保留字。下面是一些例子来说明这点:
在HTML中,我们用class
属性来指定CSS类名,但在JSX中,我们应该用className
来代替。// HTML
在HTML中,for
属性用于将元素关联到
元素。但在JSX中,我们应该用
htmlFor
来代替。// HTML
// JSX
在HTML中,tabindex
属性用于指定元素的tab顺序。但在JSX中,我们应该用tabIndex
来代替。// HTML
// JSX
没有子节点的React元素可以用/>
结束,这与XML和HTML中的自闭合标签类似。
当一个React元素没有子节点时,您可以使用自闭合标签的形式来定义它。这种形式类似于XML和HTML中的自闭合标签,它以/>
结束,而不是使用一个单独的结束标签。// 正确
对于具有子节点的React元素,您应该使用一个开始标签和一个结束标签来定义它,而不是使用自闭合标签的形式。// 正确
,
, 和
元素没有子节点,所以它们是以自闭合标签的形式定义的。而,所以它是以一个开始标签和一个结束标签的形式定义的。在第二个错误的示例中,
是一个自闭合标签,但是它应该包含一个子节点
,所以应该使用一个开始标签和一个结束标签来定义它。
当JSX元素跨越多行时,推荐使用小括号将其包裹起来。这样做可以避免JavaScript的自动分号插入(ASI)机制在意料之外的地方插入分号,导致意想不到的结果。// 推荐
const element = (
小结
const title = <h1>Hello JSX<h1>
ReactDOM.render(title, root);
JSX中使用JavaScript表达式:
2 + 2
、user.firstName
或formatName(user)
都是有效的JavaScript表达式。{}
来包裹JavaScript表达式。在大括号内,您可以放置任何有效的JavaScript表达式。表达式是计算并产生一个值的代码片段。例如,2 + 2
、user.firstName
或 formatName(user)
都是JavaScript表达式。
const element =
Hello, {10 + 20}
;
10 + 20
是一个JavaScript表达式,它的结果是 30
,所以输出的HTML将是
。Hello, 30
const dv =
const element =
Hello World!
;
const element =
Hello World!
;
if
或for
。但您可以在外面的JavaScript代码中使用它们,或者使用JavaScript的表达式语法来实现相同的效果。// 错误
const element =
{if (user) {return user.firstName}}
;
// 正确
const element =
{user ? user.firstName : 'Stranger'}
;
JSX的条件渲染:
if
、else
)或表达式(如三元运算符 ? :
或逻辑与运算符 &&
)来实现条件渲染。
if
/ else
实现条件渲染:if
/ else
语句来决定渲染哪些组件。function LoadingIndicator(props) {
if (props.isLoading) {
return
props.isLoading
为 true
,将渲染显示 “Loading…” 的 div
。否则,将渲染显示 “Content loaded” 的 div
。
? :
在 JSX 内直接进行条件渲染。function LoadingIndicator(props) {
return (
&&
实现条件渲染:&&
是一个简洁的方法,用于在满足某个条件时渲染某些元素。function LoadingIndicator(props) {
return (
props.isLoading
为 true
,则会渲染显示 “Loading…”。否则,如果 props.isLoading
为 false
,则不渲染任何内容(返回 null
)。JSX的列表渲染:
Array.prototype.map()
方法渲染列表:map()
方法是在JavaScript数组中处理列表数据的常用方式。它会遍历数组的每个元素,并返回一个新的数组,该数组由对原数组的每个元素应用某个函数得到的结果组成。map()
方法将一个数据数组转换为一个元素数组,并使用 key
属性来保证每个元素具有稳定的标识。const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number, index) =>
<li key={index.toString()}>
{number}
</li>
);
ReactDOM.render(
<ul>{listItems}</ul>,
document.getElementById('root')
);
// 或则
const user_info = (
{id : 1, name : 'caixy'},
{id : 2, name : 'Caixy!!!'},
{id : 3, name : 'CAIXYPROMISE'}
)
const list = (
<ul>
{user_info.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
)
key
属性是React用来识别哪些元素改变了的重要标识。每个元素的 key
值应该是唯一的。key
值,除非列表不会重新排序、不会过滤、不会删除或添加新元素。因为当元素顺序改变时,索引也会改变,这可能会导致不必要的组件重新渲染和状态丢失。key
属性的值应该是稳定、可预测和唯一的,以便React能够匹配元素与其对应的状态。function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
return (
<ul>{listItems}</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
JSX的样式处理:
const divStyle = {
color: 'blue',
backgroundColor: 'lightgray',
};
function HelloWorldComponent() {
return
divStyle
的对象,该对象包含我们想要应用到 div
元素上的样式属性。然后,我们通过 style
属性将 divStyle
对象传递给 div
元素。
className
属性为React元素指定CSS类。className
属性接受一个字符串,该字符串包含一个或多个类名。下面是一个示例:function HelloWorldComponent() {
return
div
元素指定了一个 className
属性,该属性的值是 hello-world
。然后,我们在CSS中定义了一个 .hello-world
类,该类应用了我们想要的样式。
class
是JavaScript中的保留字,因此在JSX中应使用 className
而不是 class
。backgroundColor
而不是 background-color
。JSX小结
React.createElement
更简洁、直观和优雅,特别是在创建复杂节点时。const element =
Hello, world!
;
class
应写为className
,for
应写为htmlFor
,tabindex
应写为tabIndex
。/>
来结束。
{}
包裹任意的JavaScript表达式。if
和for
等。
if/else
, 三元运算符? :
或逻辑与运算符&&
实现条件渲染。
map()
方法渲染列表,并为每个元素提供唯一的key
属性值。key
值。
className
属性指定CSS类。
create-react-app
脚手架中已经默认包含了这种配置,使得我们能够直接使用JSX语法。React基础组件概念与使用
1. React 组件介绍
1.1 组件的基本概念:
2. React组件的两种创建方式
2.1 使用函数创建组件
null
或false
来表示不渲染任何内容。Hello
组件应该用
标签来使用。function Hello() {
return (
<div>这是我的第一个函数组件!</div>
);
}
ReactDOM.render(
<Hello />,
document.getElementById('root')
);
2.2 使用类创建组件
class
语法创建的组件,它提供了更多的功能和灵活性,特别是在处理组件的状态和生命周期时。下面是创建类组件的基本约定和步骤:
React.Component
父类: 通过继承React.Component
,类组件可以获得React为组件提供的方法和属性,这是创建类组件的基础。render
方法的约定: 3. 类组件必须提供render()
方法: render
方法是类组件的核心,它定义了组件的输出。每当组件的props
或state
发生变化时,render
方法都会被调用。
render()
方法必须有返回值: render
方法应返回一个React元素,该元素描述了组件在页面上的表现。这个返回值可以是JSX表达式、一个React元素、null
或false
(表示不渲染任何内容)。class Hello extends React.Component {
render() {
return <div>Hello class Component!</div>;
}
}
ReactDOM.render(
<Hello />,
document.getElementById('root')
);
Hello
的类组件,该组件继承了React.Component
。我们为Hello
组件定义了一个render
方法,该方法返回了一个简单的JSX表达式。最后,我们使用ReactDOM.render
方法将Hello
组件渲染到页面上。React.Component
和实现render
方法,我们可以创建具有更多功能和灵活性的组件。随着您对React的深入理解,您会发现类组件可以提供更多高级功能,例如状态管理、生命周期方法和错误边界处理等。2.3 抽离为独立JS文件
Hello.js
,用于存放组件的代码。
Hello.js
文件的顶部,导入React库。这是因为组件需要React的支持才能正常工作。import React from 'react';
Hello.js
文件中创建您的组件。您可以选择创建函数组件或类组件,具体取决于您的需求。function Hello() {
return <div>Hello World!</div>;
}
// 或
class Hello extends React.Component {
render() {
return <div>Hello World!</div>;
}
}
Hello.js
文件的底部,导出您刚刚创建的组件。这样其他文件就可以导入和使用它了。export default Hello;
index.js
或您想要使用该组件的文件中,导入Hello
组件。import Hello from './Hello';
ReactDOM.render
方法将Hello
组件渲染到页面上。ReactDOM.render(
<Hello />,
document.getElementById('root')
);
Hello
组件从index.js
文件中抽离出来,并放置在了一个单独的Hello.js
文件中。这种组织方式不仅使代码结构更清晰,也更便于团队协作和代码维护。随着项目的发展,推荐将相关的组件组织到特定的目录和文件中,例如将所有与用户相关的组件放在一个名为users
的目录中,每个组件有其单独的JS文件。3. React 事件处理
3.1 事件绑定
onClick
代替 onclick
,onMouseEnter
代替 onmouseenter
。
on
+ 事件名称
= {事件处理程序}
。例如,onClick={handleClick}
。类组件中的事件绑定:
class App extends React.Component {
handleClick() {
console.log('单击事件触发了');
}
render() {
// 注意:事件名称为onClick,而非onclick
// 并且事件处理函数为this.handleClick,而非this.handleClick()
return (
<button onClick={this.handleClick}></button>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
handleClick
的方法来处理按钮的点击事件,并使用 onClick
属性将其绑定到按钮上。函数组件中的事件绑定:
function App() {
function handleClick() {
console.log('单击事件触发了');
}
// 注意:事件名称为onClick,而非onclick
return (
<button onClick={handleClick}>点我</button>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
handleClick
的函数来处理按钮的点击事件,并使用 onClick
属性将其绑定到按钮上。3.2 事件对象
function handleClick(e) {
// 阻止默认行为,例如阻止链接的跳转
e.preventDefault();
// 输出事件对象
console.log('事件对象:', e);
// 输出事件类型
console.log('事件类型:', e.type);
}
// 注意: 事件名称为onClick,而非onclick
// 事件处理函数为handleClick,而非handleClick()
return (
<a href="#some-link" onClick={handleClick}>点我,不会跳转页面</a>
);
// 也可以直接在事件绑定时传递事件对象
return (
<a href="https://www.baidu.com/" onClick={(e) => {
e.preventDefault();
console.log('事件对象:', e);
}}>点我,不会跳转页面</a>
);
ReactDOM.render(
<a href="#some-link" onClick={handleClick}>点我,不会跳转页面</a>,
document.getElementById('root')
);
handleClick
的函数,该函数接受一个参数 e
,表示事件对象。在函数体内,我们使用 e.preventDefault()
方法阻止了链接的默认跳转行为,并通过 console.log
输出了事件对象和事件类型。最后,我们使用 onClick
属性将 handleClick
函数绑定到了链接元素上。4. 有状态组件和无状态组件
4.1 无状态组件(函数组件)
function Greeting(props) {
return <h1>Hello, {props.name}</h1>;
}
ReactDOM.render(
<Greeting name="World" />,
document.getElementById('root')
);
Greeting
是一个无状态组件,它接受一个 props
对象作为参数,并返回一个React元素。无状态组件是纯函数,它们的输出完全由输入(即props)决定。函数无状态组件通常用在不需要与用户操作反馈的组件当中使用。4.2 有状态组件(类组件)
class Counter extends React.Component {
constructor() {
super();
// 初始化状态
this.state = { count: 0 };
}
// 事件处理函数
handleIncrement = () => {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.handleIncrement}>Increment</button>
</div>
);
}
}
ReactDOM.render(
<Counter />,
document.getElementById('root')
);
Counter
是一个有状态组件,它具有内部状态 state
,并定义了一个事件处理函数 handleIncrement
来处理按钮的点击事件。当按钮被点击时,handleIncrement
函数被调用,它通过 setState
方法更新组件的状态,从而引发组件的重新渲染,以显示新的计数值。5. 组件中的state和setState
5.1 state的基本使用
state
是一个特殊的对象,它存储了组件的状态数据。state
是组件内部私有的,不能从组件外部访问或修改。我们可以通过this.state
来访问组件的状态,如下例所示:class Hello extends React.Component { // 注意: 是 React.Component, 不是 React.component
// 使用构造函数初始化状态
constructor() {
super();
this.state = { count: 0 }; // 注意: 是 0, 不是 o
}
render() {
return (
<div>有状态组件,{this.state.count}</div>
);
}
}
ReactDOM.render(
<Hello />,
document.getElementById('root')
);
constructor
构造函数初始化state
对象,并设置初始状态count
为0。然后,在render
方法中,我们通过this.state.count
访问state
对象中的count
属性,并将其渲染到DOM中。5.2 setState的基本使用
state
对象,而应该使用this.setState
方法。this.setState
是异步的,它接受一个新的状态对象或一个函数作为参数,并安排一个组件更新。以下是一个简单的例子:class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
// 事件处理函数
handleIncrement = () => {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.handleIncrement}>Increment</button>
</div>
);
}
}
ReactDOM.render(
<Counter />,
document.getElementById('root')
);
handleIncrement
,它通过this.setState
方法更新count
状态。每次点击按钮时,handleIncrement
函数都会被调用,count
状态会增加1,并触发组件重新渲染,以显示新的计数值。state
和setState
是React组件中管理和更新状态的核心机制。通过理解和掌握它们的使用,可以有效地管理组件的状态,并实现动态交互功能。5.3 setState()修改状态
state
对象的值,而应该通过this.setState()
方法来修改状态。下面是setState
方法的基本语法:this.setState({
// 要修改的数据
});
注意事项:
state
是错误的做法,可能会导致未预期的结果和难以调试的问题。// 错误的做法!
this.state.count += 1;
setState()
的作用: setState()
方法主要有两个作用:
state
中的数据。state
数据被修改并且组件重新渲染后,更新UI界面。数据驱动视图的思想
state
)的变化会自动驱动视图的更新。这种方式简化了UI编程,我们只需要关注数据的管理,不需要直接操作DOM元素。当数据发生变化时,React会负责计算最小的DOM操作,来保证UI的更新效率。setState
的使用例子,展示了如何通过点击按钮来更新组件的状态,并且显示新的状态值:class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
handleIncrement = () => {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.handleIncrement}>Increment</button>
</div>
);
}
}
ReactDOM.render(
<Counter />,
document.getElementById('root')
);
handleIncrement
方法通过this.setState()
来增加count
的值,每次点击按钮时,count
值会增加1,并且组件会重新渲染,显示新的count
值。这个例子体现了React的数据驱动视图的思想,通过修改数据来自动更新视图。6. 事件绑定和
this
指向this
指向可能会导致一些混淆。在JavaScript中,函数的this
值是由调用它的上下文决定的,而不是由函数自身决定的。因此,当我们在类组件中定义事件处理器时,需要确保this
指向正确。1. 箭头函数
this
值,它会捕获创建时所在的this
值。因此,可以利用箭头函数来保证this
指向的正确。下面是一个示例,展示了如何使用箭头函数来绑定事件处理器:class Hello extends React.Component {
onIncrement = () => {
this.setState(prevState => ({ count: prevState.count + 1 }));
}
render() {
return (
<button onClick={this.onIncrement}>Increment</button>
);
}
}
ReactDOM.render(
<Hello />,
document.getElementById('root')
);
onIncrement
方法是一个箭头函数,它会捕获类实例的this
值。因此,当onIncrement
方法被作为事件处理器调用时,this
指向的是类实例,从而可以正确地调用this.setState
方法来更新状态。2. 在
render
方法中使用箭头函数render
方法中使用箭头函数来创建事件处理器。以下是一个示例:class Hello extends React.Component {
onIncrement() {
this.setState(prevState => ({ count: prevState.count + 1 }));
}
render() {
return (
<button onClick={() => this.onIncrement()}>Increment</button>
);
}
}
ReactDOM.render(
<Hello />,
document.getElementById('root')
);
render
方法中创建了一个新的箭头函数,该箭头函数调用onIncrement
方法。由于箭头函数捕获了render
方法的this
值(也就是类实例的this
值),因此onIncrement
方法中的this
指向是正确的。this
的正确指向,但是第一种方式(在类属性中使用箭头函数)通常更为推荐,因为它可以避免在每次渲染时创建新的函数对象,从而提高性能。3. 使用
Function.prototype.bind
bind
方法可以创建一个新的函数,该函数的this
值被绑定到提供的值,以及可选的参数列表。在React的类组件中,可以在构造函数中使用bind
方法,将事件处理程序的this
值绑定到类实例上。以下是一个示例:class Hello extends React.Component {
constructor() {
super();
this.onIncrement = this.onIncrement.bind(this);
}
onIncrement() {
this.setState(prevState => ({ count: prevState.count + 1 }));
}
render() {
return (
<button onClick={this.onIncrement}>Increment</button>
);
}
}
ReactDOM.render(
<Hello />,
document.getElementById('root')
);
Hello
组件的构造函数中,通过调用this.onIncrement.bind(this)
将onIncrement
方法的this
值绑定到类实例上,并将绑定结果赋值回this.onIncrement
。render
方法中,通过onClick={this.onIncrement}
属性将onIncrement
方法绑定到按钮的点击事件上。onIncrement
方法会被调用,并且this
值指向的是类实例,从而可以正确地调用this.setState
方法来更新状态。bind
方法,可以确保事件处理程序中this
的正确指向,但是这种方式需要在构造函数中编写额外的代码。为了减少样板代码,很多开发者倾向于使用箭头函数来绑定事件处理程序。4. 事件绑定和
this
指向总结this
的正确指向是非常重要的,特别是在类组件中。下面是三种常见的处理this
指向的方法,并给出了相应的代码示例。
this
指向类的实例。这是因为箭头函数不会创建自己的this
上下文,而是从外围作用域继承this
值。这是一种简洁且推荐的方法。class Hello extends React.Component {
onIncrement = () => {
this.setState(prevState => ({ count: prevState.count + 1 }));
}
render() {
return (
<button onClick={this.onIncrement}>Increment</button>
);
}
}
ReactDOM.render(
<Hello />,
document.getElementById('root')
);
this
的正确指向,但可能会导致每次组件渲染时都创建新的函数实例,这可能会影响性能。class Hello extends React.Component {
onIncrement() {
this.setState(prevState => ({ count: prevState.count + 1 }));
}
render() {
return (
<button onClick={() => this.onIncrement()}>Increment</button>
);
}
}
ReactDOM.render(
<Hello />,
document.getElementById('root')
);
bind
方法bind
方法,可以将事件处理程序的this
值绑定到类实例上。这是一种传统的方法,但可能会增加样板代码的数量。class Hello extends React.Component {
constructor() {
super();
this.onIncrement = this.onIncrement.bind(this);
}
onIncrement() {
this.setState(prevState => ({ count: prevState.count + 1 }));
}
render() {
return (
<button onClick={this.onIncrement}>Increment</button>
);
}
}
ReactDOM.render(
<Hello />,
document.getElementById('root')
);
7. React 表单处理
7.1 受控组件
在组件的state中添加一个状态项,该状态项将作为表单元素的value值。state = { txt: '' }
给表单元素绑定一个change事件,当表单元素的值发生变化时,更新state的值。<input
type="text"
value={this.state.txt}
onChange={e => this.setState({ txt: e.target.value })}
/>
元素的值始终由
this.state.txt
决定,每当用户输入时,onChange
事件处理程序会被触发,从而更新this.state.txt
的值。
import React, { Component } from 'react';
class FormExample extends Component {
state = {
textValue: '',
selectedOption: '',
isChecked: false
};
handleTextChange = (event) => {
this.setState({ textValue: event.target.value });
}
handleSelectChange = (event) => {
this.setState({ selectedOption: event.target.value });
}
handleCheckboxChange = (event) => {
this.setState({ isChecked: event.target.checked });
}
render() {
return (
<div>
{/* 文本框 */}
<input
type="text"
value={this.state.textValue}
onChange={this.handleTextChange}
/>
{/* 下拉框 */}
<select
value={this.state.selectedOption}
onChange={this.handleSelectChange}
>
<option value="option1">Option 1</option>
<option value="option2">Option 2</option>
</select>
{/* 复选框 */}
<input
type="checkbox"
checked={this.state.isChecked}
onChange={this.handleCheckboxChange}
/>
</div>
);
}
}
export default FormExample;
state
和事件处理函数,我们实现了对文本框、下拉框和复选框的受控操作。每当用户对表单元素进行操作时,对应的onChange
事件处理函数就会被调用,从而更新state
中的值,实现了数据与视图的同步更新。
value
属性并绑定onChange
事件处理函数,将表单元素的值设置为state
的值,实现受控操作。checked
属性并绑定onChange
事件处理函数,将复选框的选中状态设置为state
的值,实现受控操作。import React, { Component } from 'react';
class FormExample extends Component {
state = {
txt: '',
checkboxValue: false
};
handleForm = (event) => {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
render() {
return (
<div>
{/* 文本框 */}
<input
type="text"
name="txt"
value={this.state.txt}
onChange={this.handleForm}
/>
{/* 复选框 */}
<input
type="checkbox"
name="checkboxValue"
checked={this.state.checkboxValue}
onChange={this.handleForm}
/>
</div>
);
}
}
export default FormExample;
name
属性:为每个表单元素添加了name
属性,并且name
属性的值与state
中的属性名相同。type
属性,我们可以确定是获取value
属性还是checked
属性的值。handleForm
事件处理函数,它可以处理所有表单元素的onChange
事件。在这个函数中,我们使用了计算属性名称([name]
)来动态更新state
中对应的值。这样,无论我们有多少表单元素,只需要一个handleForm
函数就可以处理所有的表单元素变化。7.2 非受控组件 (DOM方式)
使用 React.createRef()
方法创建一个 ref 对象。constructor() {
super();
this.txtRef = React.createRef();
}
在表单元素的 ref
属性中传入创建好的 ref 对象。<input type="text" ref={this.txtRef} />
在事件处理程序中,通过 ref 对象的 current
属性来获取表单元素的值。console.log(this.txtRef.current.value);
import React, { Component } from 'react';
class UncontrolledForm extends Component {
constructor(props) {
super(props);
// 1. 创建一个 ref 对象
this.txtRef = React.createRef();
}
handleSubmit = (event) => {
event.preventDefault();
// 3. 通过 ref 对象获取文本框的值
console.log('Text field value:', this.txtRef.current.value);
}
render() {
return (
<form onSubmit={this.handleSubmit}>
{/* 2. 将创建好的 ref 对象添加到文本框中 */}
<input type="text" ref={this.txtRef} />
<button type="submit">Submit</button>
</form>
);
}
}
export default UncontrolledForm;
React.createRef()
创建了一个 ref 对象 this.txtRef
,然后将它传给了 input
元素的 ref
属性。在 handleSubmit
方法中,我们通过 this.txtRef.current.value
获取到了文本框的值,并在控制台中打印出来。8. React组件的总结
1. 组件的两种创建方式: 函数组件和类组件
函数组件是最简单的组件类型,它是一个接收 props
参数并返回 React 元素的 JavaScript 函数。function Hello() {
return <div>Hello, World!</div>;
}
类组件则是使用 ES6 类来创建的,它可以包含局部状态(state)和生命周期方法等更多功能。class Hello extends React.Component {
render() {
return <div>Hello, World!</div>;
}
}
2. 无状态(函数)组件与有状态(类)组件
无状态组件主要负责展示数据,它通常没有自己的状态,只接收外部传入的 props
。function UserInfo(props) {
return <div>User: {props.name}</div>;
}
有状态组件可以有自己的局部状态,它们负责数据的处理和交互。class Counter extends React.Component {
state = { count: 0 };
handleIncrement = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
Count: {this.state.count}
<button onClick={this.handleIncrement}>Increment</button>
</div>
);
}
}
3. 事件处理和
this
指向问题this
的指向是一个常见的问题。以下是解决 this
指向问题的常见方法:class Hello extends React.Component {
handleClick = () => {
console.log('Button clicked:', this);
};
render() {
return <button onClick={this.handleClick}>Click me</button>;
}
}
handleClick
方法中的 this
指向组件实例。4. 受控组件与非受控组件
state
来控制表单元素的值,而非受控组件则通过 ref
来直接操作 DOM 元素。class FormExample extends React.Component {
state = { textValue: '' };
handleTextChange = (event) => {
this.setState({ textValue: event.target.value });
}
render() {
return (
<input
type="text"
value={this.state.textValue}
onChange={this.handleTextChange}
/>
);
}
}
class UncontrolledForm extends React.Component {
txtRef = React.createRef();
handleSubmit = (event) => {
event.preventDefault();
console.log('Text field value:', this.txtRef.current.value);
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input type="text" ref={this.txtRef} />
<button type="submit">Submit</button>
</form>
);
}
}
5. React 的设计思想
React脚手架的使用
1. 使用create-react-app创建react应用
2. react脚手架
3.创建第一个React脚手架应用
1. 确保你的系统已经安装了 Node.js 和 npm:
node -v
npm -v
2. 创建新的 React 应用:
npx create-react-app my-react-app
my-react-app
是你的应用的名称,你可以用任何你喜欢的名称来替换它。npx
是一个 npm 包运行器,它会自动下载并运行 create-react-app
脚本,以创建一个新的 React 应用。3. 切换到项目目录并启动应用:
cd my-react-app
npm start
src
目录下的文件,来开发你的应用了。4. 使用React库
// 1.导入React
import React from 'react'
import ReactDOM from 'react-dom'
// 2.创建React元素
const title = React.createElement('h1', null, 'Hello World');
// 3. 渲染ReactDOM
ReactDOM.render(title, document.getElementById('root'));
4. react脚手架项目结构
5.React 文件内容详解
DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>React Apptitle>
head>
<body>
<noscript>You need to enable JavaScript to run this app.noscript>
<div id="root">div>
body>
html>
这个元素中。其他的元数据和链接有助于提供一些基本的、常见的网页特性和设置,例如字符编码、视口设置、网页图标等。同时,
%PUBLIC_URL%
是一个特殊的占位符,它在构建过程中会被替换成实际的公共URL路径,这样,无论应用程序是部署在根路径还是子路径,都能正确地引用到资源文件。
npm start
或 yarn start
时,项目会启动,执行 src/index.js
文件。index.js
文件负责渲染 App
组件到 index.html
文件中的 #root
元素上。App.js
和其他组件中,可以导入 CSS、图片和其他资源,用于构建应用的界面。App.js
和其他组件文件中,可以编写 React 组件和业务逻辑,构建应用的功能。6. SPA文件架构
什么是SPA
React下的SPA
npx create-react-app my-spa
cd my-spa
npm install react-router-dom
在 src
目录下创建一个 routes.js
文件,配置不同的路由路径和组件。import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Home from './components/Home';
import About from './components/About';
const Routes = () => (
在 src/components
目录下创建 Home.js
和 About.js
文件,每个文件代表一个页面。
在 src/index.js
文件中导入 Routes
组件,并将其渲染到页面上。import React from 'react';
import ReactDOM from 'react-dom';
import Routes from './routes';
import './index.css';
ReactDOM.render(