blog: 添加React学习笔记

This commit is contained in:
xugaoyi 2021-03-25 20:24:44 +08:00
parent d9384449a5
commit 108e7973bf
150 changed files with 2369 additions and 964 deletions

View File

@ -20,6 +20,7 @@ module.exports = [
{ text: '《JavaScript高级程序设计》笔记', link: '/note/js/' },
{ text: '《ES6 教程》笔记', link: '/note/es6/' },
{ text: '《Vue》笔记', link: '/note/vue/' },
{ text: '《React》笔记', link: '/note/react/' },
{
text: '《TypeScript 从零实现 axios》',
link: '/note/typescript-axios/',

View File

@ -7,7 +7,7 @@ pageComponent:
description: 本章内容为博主在原教程基础上添加学习笔记,教程版权归原作者所有。来源:<a href='https://es6.ruanyifeng.com/' target='_blank'>ES6教程</a>
title: 《ES6 教程》笔记
date: 2020-01-12 15:49:22
permalink: /note/es6
permalink: /note/es6/
article: false
comment: false
editLink: false

View File

@ -4,10 +4,10 @@ pageComponent:
data:
key: 《Vue》笔记
imgUrl: https://cdn.jsdelivr.net/gh/xugaoyi/image_store/blog/20200204143633.png
description: 本章内容是博主的Vue学习笔记以官方文档为准。
description: 本章内容是博主的Vue学习笔记非教程文档,请以官方文档为准。
title: 《Vue》笔记
date: 2020-02-04 12:16:12
permalink: /note/vue
permalink: /note/vue/
article: false
comment: false
editLink: false

View File

@ -0,0 +1,17 @@
---
pageComponent:
name: Catalogue
data:
key: 《React》笔记
imgUrl: data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii0xMS41IC0xMC4yMzE3NCAyMyAyMC40NjM0OCI+CiAgPHRpdGxlPlJlYWN0IExvZ288L3RpdGxlPgogIDxjaXJjbGUgY3g9IjAiIGN5PSIwIiByPSIyLjA1IiBmaWxsPSIjNjFkYWZiIi8+CiAgPGcgc3Ryb2tlPSIjNjFkYWZiIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiPgogICAgPGVsbGlwc2Ugcng9IjExIiByeT0iNC4yIi8+CiAgICA8ZWxsaXBzZSByeD0iMTEiIHJ5PSI0LjIiIHRyYW5zZm9ybT0icm90YXRlKDYwKSIvPgogICAgPGVsbGlwc2Ugcng9IjExIiByeT0iNC4yIiB0cmFuc2Zvcm09InJvdGF0ZSgxMjApIi8+CiAgPC9nPgo8L3N2Zz4K
description: 本章内容是博主的React学习笔记非教程文档请以官方文档为准。
title: 《React》笔记
date: 2021-03-25 19:50:12
permalink: /note/react/
article: false
comment: false
editLink: false
author:
name: xugaoyi
link: https://github.com/xugaoyi
---

View File

@ -6,7 +6,7 @@ categories:
- 前端
- 学习笔记
tags:
-
- TypeScript
---
# TypeScript 学习笔记

View File

@ -3,7 +3,7 @@ title: 小程序笔记
date: 2019-12-25 14:27:01
permalink: /note/wx-miniprogram
tags:
- null
- 小程序
categories:
- 前端
- 学习笔记
@ -2749,14 +2749,3 @@ router.get('/list', async (ctx, next) => {
#### 后端上传图片到云存储
[文件上传](https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/storage/uploadFile.html)

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
> 说明:本章内容为博主在原教程基础上添加自己的学习笔记,来源<http://es6.ruanyifeng.com/>,教程版权归原作者所有。

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# let 和 const 命令
@ -643,4 +643,3 @@ var getGlobal = function () {
[ES2020](https://github.com/tc39/proposal-global) 在语言标准的层面,引入`globalThis`作为顶层对象。也就是说,任何环境下,`globalThis`都是存在的,都可以从它拿到顶层对象,指向全局环境下的`this`。
垫片库[`global-this`](https://github.com/ungap/global-this)模拟了这个提案,可以在所有环境拿到`globalThis`。

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# 变量的解构赋值

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# 字符串的扩展

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# 字符串的新增方法
@ -338,4 +338,3 @@ s.trimEnd() // " abc"
## 实例方法matchAll()
`matchAll()`方法返回一个正则表达式在当前字符串的所有匹配,详见《正则的扩展》的一章。

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# 正则的扩展

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# 数值的扩展
@ -967,4 +967,3 @@ BigInt 与字符串混合运算时,会先转为字符串,再进行运算。
```javascript
'' + 123n // "123"
```

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# 函数的扩展
@ -1372,4 +1372,3 @@ try {
// ...
}
```

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# 数组的扩展
@ -997,4 +997,3 @@ arr.sort(unstableSorting)
常见的排序算法之中,插入排序、合并排序、冒泡排序等都是稳定的,堆排序、快速排序等是不稳定的。不稳定排序的主要缺点是,多重排序时可能会产生问题。假设有一个姓和名的列表,要求按照“姓氏为主要关键字,名字为次要关键字”进行排序。开发者可能会先按名字排序,再按姓氏进行排序。如果排序算法是稳定的,这样就可以达到“先姓氏,后名字”的排序效果。如果是不稳定的,就不行。
早先的 ECMAScript 没有规定,`Array.prototype.sort()`的默认排序算法是否稳定,留给浏览器自己决定,这导致某些实现是不稳定的。[ES2019](https://github.com/tc39/ecma262/pull/1340) 明确规定,`Array.prototype.sort()`的默认排序算法必须稳定。这个规定已经做到了,现在 JavaScript 各个主要实现的默认排序算法都是稳定的。

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# 对象的扩展
@ -932,4 +932,3 @@ lhs || (middle ?? rhs);
(lhs ?? middle) || rhs;
lhs ?? (middle || rhs);
```

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# 对象的新增方法

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# Symbol

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# Set 和 Map 数据结构

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# Proxy

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# Reflect

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# Promise 对象

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# Iterator 和 for...of 循环

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# Generator 函数的语法

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# Generator 函数的异步应用

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# async 函数
@ -867,4 +867,3 @@ console.log("Z");
上面代码有三个模块,最后的`z.js`加载`x.js`和`y.js`,打印结果是`X1`、`Y`、`X2`、`Z`。这说明,`z.js`并没有等待`x.js`加载完成,再去加载`y.js`。
顶层的`await`命令有点像,交出代码的执行权给其他的模块加载,等异步操作完成后,再拿回执行权,继续向下执行。

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# Class 的基本语法

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# Class 的继承

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# Module 的语法
@ -810,4 +810,3 @@ async function main() {
}
main();
```

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# Module 的加载实现
@ -840,4 +840,3 @@ $ node
> m.even(10)
TypeError: even is not a function
```

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# 编程风格

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# 读懂 ECMAScript 规格

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# 异步遍历器
@ -482,4 +482,3 @@ async function* gen2() {
// a
// b
```

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# ArrayBuffer

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# 最新提案
@ -641,4 +641,3 @@ new URL('data.txt', import.meta.url)
import.meta.scriptElement.dataset.foo
// "abc"
```

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# 装饰器
@ -811,4 +811,3 @@ class MyClass {}
@traits(TExample::as({excludes:['foo', 'bar'], alias: {baz: 'exampleBaz'}}))
class MyClass {}
```

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# 函数式编程

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# Mixin

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# SIMD

View File

@ -6,7 +6,7 @@ author: 阮一峰
categories:
- 《ES6 教程》笔记
tags:
-
- ES6
---
# 参考链接

View File

@ -5,7 +5,7 @@ permalink: /pages/8292d8/
categories:
- 《Git》学习笔记
tags:
-
- Git
---
# 常用Git命令清单

View File

@ -5,7 +5,7 @@ permalink: /pages/c10281/
categories:
- 《Git》学习笔记
tags:
-
- Git
---
# rebase分支合并

View File

@ -5,6 +5,6 @@ permalink: /pages/4cbc21/
categories:
- 《Git》学习笔记
tags:
-
- Git
---
![Git命令思维导图](/img/git.png)

View File

@ -5,7 +5,7 @@ permalink: /pages/635088/
categories:
- 《Git》学习笔记
tags:
-
- Git
---
# Git基础与命令
@ -528,6 +528,3 @@ Date: Tue Aug 26 19:48:51 2008 +0800
```sh
$ git config --global alias.visual '!gitk'
```

View File

@ -5,7 +5,7 @@ permalink: /pages/1832fe/
categories:
- 《Git》学习笔记
tags:
-
- Git
---
# Git 工具 - 重写历史

View File

@ -5,7 +5,7 @@ permalink: /pages/d9e9c6/
categories:
- 《Git》学习笔记
tags:
-
- Git
---
# Git 工具 - 重置揭密

View File

@ -5,7 +5,7 @@ permalink: /pages/4bef1a/
categories:
- 《Git》学习笔记
tags:
-
- Git
---
# Git分支-分支原理

View File

@ -5,7 +5,7 @@ permalink: /pages/ea5a8c/
categories:
- 《Git》学习笔记
tags:
-
- Git
---
# Git分支的新建与合并-分支操作
@ -128,4 +128,3 @@ Automatic merge failed; fix conflicts and then commit the result.
你需要**手动解决冲突**,解决了所有文件里的冲突之后,对每个文件**使用 `git add` 命令**来将其标记为冲突已解决。 **一旦暂存这些原本有冲突的文件Git 就会将它们标记为冲突已解决**
如果你对结果感到满意,并且确定之前有冲突的的文件都已经暂存了,这时你可以输入 `git commit` 来完成合并提交。

View File

@ -5,7 +5,7 @@ permalink: /pages/a399b3/
categories:
- 《Git》学习笔记
tags:
-
- Git
---
# Git分支管理-查看分支

View File

@ -5,7 +5,7 @@ permalink: /pages/49ee30/
categories:
- 《Git》学习笔记
tags:
-
- Git
---
# Git分支开发工作流

View File

@ -5,7 +5,7 @@ permalink: /pages/574d62/
categories:
- 《Git》学习笔记
tags:
-
- Git
---
# Git分支-远程分支

View File

@ -5,7 +5,7 @@ permalink: /pages/3a3247/
categories:
- 《Git》学习笔记
tags:
-
- Git
---
# Git分支-变基

View File

@ -5,7 +5,7 @@ permalink: /pages/c984d1/
categories:
- 《Git》学习笔记
tags:
-
- Git
---
# Git工具-查看修订版本

View File

@ -5,7 +5,7 @@ permalink: /pages/76d859/
categories:
- 《Git》学习笔记
tags:
-
- Git
---
# Git工具-交互式暂存

View File

@ -5,7 +5,7 @@ permalink: /pages/0796ba76b4b55368
categories:
- 《JavaScript教程》笔记
tags:
- null
- JavaScript
author:
name: xugaoyi
link: https://github.com/xugaoyi

View File

@ -5,7 +5,7 @@ permalink: /pages/74d2ab3fbfeaaa68
categories:
- 《JavaScript教程》笔记
tags:
- null
- JavaScript
author:
name: xugaoyi
link: https://github.com/xugaoyi

View File

@ -5,7 +5,7 @@ permalink: /pages/659b5af5e2e704e0
categories:
- 《JavaScript教程》笔记
tags:
- null
- JavaScript
author:
name: xugaoyi
link: https://github.com/xugaoyi
@ -2587,8 +2587,3 @@ function copyObject(orig) {
## 文档
学习文档:<https://wangdoc.com/javascript/>

View File

@ -5,7 +5,7 @@ permalink: /pages/d61b1cb4cdac1f63
categories:
- 《JavaScript教程》笔记
tags:
- null
- JavaScript
author:
name: xugaoyi
link: https://github.com/xugaoyi

View File

@ -5,7 +5,7 @@ permalink: /pages/7d961b8030c6099e
categories:
- 《JavaScript教程》笔记
tags:
- null
- JavaScript
author:
name: xugaoyi
link: https://github.com/xugaoyi

View File

@ -5,7 +5,7 @@ permalink: /pages/10b2761db5a8e089
categories:
- 《JavaScript教程》笔记
tags:
- null
- JavaScript
author:
name: xugaoyi
link: https://github.com/xugaoyi

View File

@ -5,7 +5,7 @@ permalink: /pages/bab4930124ad2c10
categories:
- 《JavaScript教程》笔记
tags:
- null
- JavaScript
author:
name: xugaoyi
link: https://github.com/xugaoyi

View File

@ -0,0 +1,106 @@
---
title: JSX简介
date: 2021-03-24 17:56:40
permalink: /pages/5df969/
categories:
- 《React》笔记
- 核心概念
tags:
- React
---
# 01. JSX简介
## 什么是JSX
```js
const element = <h1>Hello, world!</h1>;
```
以类似模板语法的方式描述UI的一种语法。它是JS的**语法糖****本质上也是JS**。可以在其中使用**变量或表达式、函数等**。
## 为什么使用JSX
将*标记与逻辑* 共同存放在称之为“组件”的松散耦合单元之中,来实现[*关注点分离*](https://en.wikipedia.org/wiki/Separation_of_concerns)。
React不强制使用JSX但在 JavaScript 代码中将 JSX 和 UI 放在一起时,会在**视觉上有辅助作用**。
## 在 JSX 中嵌入表达式
```js
const element = <h1>Hello, {2+2}</h1>;
```
在 JSX 语法中,你可以在大括号内放置任何有效的 [JavaScript 表达式](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions)。
## JSX 也是一个表达式
在编译之后JSX 表达式会被转为普通 JavaScript 函数调用,并且对其取值后**得到 JavaScript 对象**
> 可以把JSX当初一个对象来对待可以使用它赋值给变量、当参数输入函数、返回JSX等。
## JSX 特定属性
通过使用引号,来将属性值指定为字符串字面量:
```js
const element = <div tabIndex="0"></div>;
```
> JSX中的属性名使用camelCase(小驼峰)命名。如上面例子中的`tabIndex`
使用大括号,来在属性值中插入一个 JavaScript 表达式:
```js
const element = <img src={user.avatarUrl}></img>;
```
## 使用 JSX 指定子元素
JSX 标签里能够包含很多子元素:
```jsx
const element = (
<div>
<h1>Hello!</h1>
<h2>Good to see you here.</h2>
</div>
);
```
## JSX 防止注入攻击
React DOM 在渲染所有输入内容之前,默认会进行[转义](https://stackoverflow.com/questions/7381974/which-characters-need-to-be-escaped-on-html)。它可以确保在你的应用中,**永远不会注入那些并非自己明确编写的内容**。所有的内容在渲染之前都被转换成了字符串。这样可以有效地防止 [XSScross-site-scripting, 跨站脚本)](https://en.wikipedia.org/wiki/Cross-site_scripting)攻击。
## JSX 表示对象
Babel 会把 JSX 转译成一个名为 `React.createElement()` 函数调用。
以下两种示例代码完全等效:
```jsx
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
const element = React.createElement(
'h1', // 标签名
{className: 'greeting'}, // 属性对象
'Hello, world!' // 内容
);
```

View File

@ -0,0 +1,68 @@
---
title: 元素渲染
date: 2021-03-24 17:56:40
permalink: /pages/b5d372/
categories:
- 《React》笔记
- 核心概念
tags:
- React
---
# 02. 元素渲染
元素是构成 React 应用的最小砖块,描述了你在屏幕上想看到的内容。
```js
const element = <h1>Hello, world</h1>;
```
与浏览器的 DOM 元素不同,**React 元素是创建开销极小的普通对象**。React DOM 会负责更新 DOM 来与 React 元素保持一致。
## 将一个元素渲染为 DOM
假设你的 HTML 文件某处有一个 `<div>`
```html
<div id="root"></div>
```
根节点React应用只有单一根DOM节点
> 但一个html页面可以有多个React应用每个应用对应一个独立根节点。
```jsx
const el = <h1>Hello</h1>
ReactDOM.render(el, document.getElementById('root'))
```
## 更新已渲染的元素
React 元素是[不可变对象](https://en.wikipedia.org/wiki/Immutable_object)。一旦被创建,你就无法更改它的子元素或者属性。一个元素就像电影的单帧:它代表了某个特定时刻的 UI。
根据我们已有的知识,更新 UI 唯一的方式是创建一个全新的元素,并将其传入 [`ReactDOM.render()`](https://zh-hans.reactjs.org/docs/react-dom.html#render)。
考虑一个计时器的例子:
```jsx
function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is {new Date().toLocaleTimeString()}.</h2>
</div>
);
ReactDOM.render(element, document.getElementById('root'));}
setInterval(tick, 1000);
```
注意:在实践中,**大多数 React 应用只会调用一次 [`ReactDOM.render()`](https://zh-hans.reactjs.org/docs/react-dom.html#render)**。在下一个章节,我们将学习如何将这些代码封装到**[有状态组件](https://zh-hans.reactjs.org/docs/state-and-lifecycle.html)**中。
## React 只更新它需要更新的部分
上个例子中,尽管每一秒我们都会新建一个描述整个 UI 树的元素但React DOM **只会更新实际改变了的内**容。

View File

@ -0,0 +1,203 @@
---
title: 组件&Props
date: 2021-03-24 17:56:40
permalink: /pages/9ac43a/
categories:
- 《React》笔记
- 核心概念
tags:
- React
---
# 03. 组件 & Props
## 函数组件与 class 组件
### 1.函数组件
```jsx
function Welcome(props){
return <h1>Hello, {props.name}</h1>
}
```
该函数是一个有效的React组件。接收唯一带有数据的props参数并返回一个React元素。
### 2.class组件
使用ES6的class来定义
```jsx
class Welcome extends React.Component{
render() {
return <h1>Hello, {this.props.name}</h1>
}
}
```
以上两个组件是等效的。
## 渲染组件(父子组件传值)
React 元素也可以是用户自定义的组件:
```jsx
const element = <Welcome name="Sara" />;
```
通过属性attributes来传递值给子组件
```jsx
function Welcome(props) { // 通过props接收传入值
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Sara" />; // 通过attributes传入值
ReactDOM.render(
element,
document.getElementById('root')
);
```
**注意:** **组件名称必须以大写字母开头。**
React 会将以小写字母开头的组件视为原生 DOM 标签。例如,`<div />` 代表 HTML 的 div 标签,而 `<Welcome />` 则代表一个组件,并且需在作用域内使用 `Welcome`
## 组合组件(复用组件)
```jsx
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
// 复用Welcome组件
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
```
> 通常来说,每个新的 React 应用程序的顶层组件都是 `App` 组件
## 提取组件(拆分组件)
参考如下 `Comment` 组件:
```jsx
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<img className="Avatar"
src={props.author.avatarUrl}
alt={props.author.name}
/>
<div className="UserInfo-name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
```
该组件由于嵌套的关系,变得难以维护,且很难复用它的各个部分。因此,让我们从中提取一些组件出来。
首先,提取 `Avatar` 组件:
```jsx
function Avatar(props) {
return (
<img className="Avatar"
src={props.user.avatarUrl}
alt={props.user.name}
/>
);
}
```
### props命名原则
`Avatar` 不需知道它在 `Comment` 组件内部是如何渲染的。因此,我们给它的 props 起了一个更通用的名字:`user`,而不是 `author`
我们**建议从组件自身的角度命名 props而不是依赖于调用组件的上下文命名**。
接下来,我们将提取 `UserInfo` 组件,该组件在用户名旁渲染 `Avatar` 组件:
```jsx
function UserInfo(props) {
return (
<div className="UserInfo">
<Avatar user={props.user} />
<div className="UserInfo-name">
{props.user.name}
</div>
</div>
);
}
```
最终的 `Comment` 组件:
```jsx
function Comment(props) {
return (
<div className="Comment">
<UserInfo user={props.author} />
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
```
最初看上去,提取组件可能是一件繁重的工作,但是,在大型应用中,构建可复用组件库是完全值得的。
### 提取原则
- UI中多次被使用的部分
- 一个足够复杂的组件(页面)
## Props 的只读性不能修改Props
组件无论是使用[函数声明还是通过 class 声明](https://zh-hans.reactjs.org/docs/components-and-props.html#function-and-class-components),都决不能修改自身的 props。
> 当然,应用程序的 UI 是动态的,并会伴随着时间的推移而变化。在[下一章节](https://zh-hans.reactjs.org/docs/state-and-lifecycle.html)中,我们将介绍一种新的概念,称之为 “state”。在不违反上述规则的情况下state 允许 React 组件随用户操作、网络响应或者其他变化而动态更改输出内容

View File

@ -0,0 +1,215 @@
---
title: State&生命周期
date: 2021-03-24 17:56:40
permalink: /pages/1e3ca2/
categories:
- 《React》笔记
- 核心概念
tags:
- React
---
# 04. State & 生命周期
State 与 props 类似,但是 **state 是私有的,并且完全受控于当前组件.**
> State类似于vue中的data选项
## 将函数组件转换成 class 组件
> 在没有useState钩子函数之前是通过class组件管理State
```jsx
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world</h1>
<h2>It is {this.props.date.toLocalTimeString()}</h2>
</div>
)
}
}
```
每次组件更新时 `render` 方法都会被调用,但只要在相同的 DOM 节点中渲染 `<Clock />` ,就**仅有一个 `Clock` 组件的 class 实例被创建使用**。这就使得我们可以使用如 state 或生命周期方法等很多其他特性。
> 单例模式?
## 向 class 组件中添加局部的 state
```jsx
class Clock extends React.Component {
// 第二步:添加构造函数,并给 this.state 赋初始值
constructor(props) {
super(props) // 通过super将props传递到父类构造函数中
this.state = {date: new Date()}
}
render() {
// 第一步render 方法内,将 this.props 替换成 this.state
return (
<div>
<h1>Hello, world</h1>
<h2>It is {this.state.date.toLocalTimeString()}</h2>
</div>
)
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
```
## 将生命周期方法添加到 Class 中
在具有许多组件的应用程序中,当组件被销毁时释放所占用的资源是非常重要的。
`Clock` 组件第一次被渲染到 DOM 中的时候,就为其[设置一个计时器](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval)。这在 React 中被称为“**挂载mount**”。
同时,当 DOM 中 `Clock` 组件被删除的时候,应该[清除计时器](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearInterval)。这在 React 中被称为“**卸载unmount**”。
```jsx
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
// 挂载 - 挂载完成后执行
componentDidMount() {
// 组件挂载后开启定时器
this.timerID = serInterval( // 可以向this添加任意属性字段
() => this.tick(), 1000
)
}
// 卸载
componentWillUnmount() {
// 组件卸载后清除定时器,释放内存
clearInterval(this.timerID)
}
tick() {
this.setState({
date: new Date()
})
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
```
## 正确地使用 State
关于 `setState()` 你应该了解三件事:
### 不要直接修改 State
```jsx
// Wrong 不要直接修改state
this.state.comment = 'Hello'
// Correct 应使用 setState() 方法
this.setState({comment: 'Hello'})
```
**构造函数是唯一可以给 `this.state` 直接赋值的地方**
> setState是React内部方法使state更新具有响应式
### State 的更新可能是异步的
出于性能考虑React 可能会把多个 `setState()` 调用合并成一个调用。
因为 `this.props``this.state` 可能会异步更新,所以你**不要依赖他们的值来更新下一个状态**。
要**解决这个问题,可以让 `setState()` 接收一个函数而不是一个对象**。这个函数用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数:
```jsx
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
```
### State 的更新会被合并
当你调用 `setState()` 的时候React 会把你提供的对象合并到当前的 state
```jsx
constructor(props) {
super(props);
this.state = {
posts: [],
comments: []
};
}
// 分别调用setState单独更新state下的属性
componentDidMount() {
fetchPosts().then(response => {
this.setState({
posts: response.posts
});
});
fetchComments().then(response => {
this.setState({
comments: response.comments
});
});
}
```
这里的合并是浅合并,所以 `this.setState({comments})` 完整保留了 `this.state.posts` 但是完全替换了 `this.state.comments`
## 数据是向下流动的(单向数据流)
不管是父组件或是子组件都无法知道某个组件是有状态的还是无状态的,并且它们也并不关心它是函数组件还是 class 组件。
这就是为什么称 **state 为局部的**或是封装的的原因。除了拥有并设置了它的组件,**其他组件都无法访问**
组件可以选择把它的 state 作为 props 向下传递到它的子组件中:
```jsx
<FormattedDate date={this.state.date} />
```
`FormattedDate` 组件会在其 props 中接收参数 `date`,但是**组件本身无法知道它是来自于 `Clock` 的 state或是 `Clock` 的 props还是手动输入的**。
这通常会被叫做“自上而下”或是**“单向”的数据流**。任何的 **state 总是所属于特定的组件**,而且从该 state 派生的任何数据或 UI 只能影响树中“低于”它们的组件。
如果你把一个以组件构成的树想象成一个 props 的数据瀑布的话,那么每一个组件的 state 就像是在任意一点上给瀑布增加额外的水源,但是它只能向下流动。
#### 每个组件都是真正独立的。

View File

@ -0,0 +1,162 @@
---
title: 事件处理
date: 2021-03-24 17:56:40
permalink: /pages/f27775/
categories:
- 《React》笔记
- 核心概念
tags:
- React
---
# 05. 事件处理
## 与传统HTML绑定事件的区别
传统的 HTML
```html
<button onclick="activateLasers()">
Activate Lasers
</button>
```
在 React 中略微不同:
```jsx
// 1.事件名为小驼峰; 2.传入函数以大括号包裹函数名形式
<button onClick={activateLasers}>
Activate Lasers
</button>
```
- React 事件的命名采用小驼峰式camelCase而不是纯小写。
- 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。
### 阻止默认事件 (合成事件对象)
在 React 中,你需要这样阻止默认事件:
```jsx
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}
```
在这里,`e` 是一个**合成事件**。React 根据 [W3C 规范](https://www.w3.org/TR/DOM-Level-3-Events/)来定义这些合成事件所以你不需要担心跨浏览器的兼容性问题。React 事件与原生事件不完全相同。如果想了解更多,请查看 [`SyntheticEvent`](https://zh-hans.reactjs.org/docs/events.html) 参考指南。
## 绑定事件的方式
使用 React 时,你一般不需要使用 `addEventListener` 为已创建的 DOM 元素添加监听器。事实上,你只需要在该元素初始渲染的时候添加监听器即可。
当你使用 [ES6 class](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes) 语法定义一个组件的时候,通常的做法是将事件处理函数声明为 class 中的方法。例如,下面的 `Toggle` 组件会渲染一个让用户切换开关状态的按钮:
```jsx
class Toggle extends React.Component {
constructor(props){
super(props)
this.state = {isToggleOn: true};
// 为了在回调中使用 `this`,这个绑定是必不可少的
this.handleClick = this.handleClick.bind(this)
}
hadleClick(){
this.setState(state => ({
isToggleOn: !state.isToggleOn
}));
}
render(){
return(
// 为了能在这里使用 this.handleClick调用方法因此需要在构造函数内添加handleChick属性指向回调方法
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
)
}
}
ReactDOM.render(
<Toggle />,
document.getElementById('root')
)
```
你必须谨慎对待 JSX 回调函数中的 `this`,在 JavaScript 中class 的方法默认不会[绑定](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind) `this`。如果你忘记绑定 `this.handleClick` 并把它传入了 `onClick`,当你调用这个函数的时候 `this` 的值为 `undefined`
这并不是 React 特有的行为;这其实与 [JavaScript 函数工作原理](https://www.smashingmagazine.com/2014/01/understanding-javascript-function-prototype-bind/)有关。通常情况下,如果你没有在方法后面添加 `()`,例如 `onClick={this.handleClick}`,你应该**为这个方法绑定 `this`**。
如果觉得使用 `bind` 很麻烦,这里有两种方式可以解决。如果你正在使用实验性的 [public class fields 语法](https://babeljs.io/docs/plugins/transform-class-properties/),你可以使用 class fields 正确的绑定回调函数:
```jsx
class LoggingButton extends React.Component {
// 此语法确保 `handleClick` 内的 `this` 已被绑定。
// 注意: 这是 *实验性* 语法。
handleClick = () => {
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}>
Click me
</button>
);
}
}
```
[Create React App](https://github.com/facebookincubator/create-react-app) 默认启用此语法。
如果你没有使用 class fields 语法,你可以在回调中使用[箭头函数](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
```jsx
class LoggingButton extends React.Component {
handleClick() {
console.log('this is:', this);
}
render() {
// 此语法确保 `handleClick` 内的 `this` 已被绑定。
return (
<button onClick={() => this.handleClick()}>
Click me
</button>
);
}
}
```
此语法问题在于每次渲染 `LoggingButton` 时都会创建不同的回调函数。在大多数情况下,这没什么问题,但如果该回调函数作为 prop 传入子组件时,这些组件可能会进行额外的重新渲染。**我们通常建议在构造器中绑定或使用 class fields 语法来避免这类性能问题**。
## 向事件处理程序传递参数
在循环中,通常我们会为事件处理函数传递额外的参数。例如,若 `id` 是你要删除那一行的 ID以下两种方式都可以向事件处理函数传递参数
```jsx
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
```
上述两种方式是等价的,分别通过[箭头函数](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)和 [`Function.prototype.bind`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind) 来实现。
在这两种情况下,**React 的事件对象 `e` 会被作为第二个参数传递**。如果通过箭头函数的方式,事件对象必须显式的进行传递,而通过 `bind` 的方式,事件对象以及更多的参数将会被隐式的进行传递。

View File

@ -0,0 +1,229 @@
---
title: 条件渲染
date: 2021-03-24 17:56:40
permalink: /pages/8fcda8/
categories:
- 《React》笔记
- 核心概念
tags:
- React
---
# 06. 条件渲染
React 中的条件渲染和 JavaScript 中的一样,使用 JavaScript 运算符 [`if`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else) 或者[条件运算符](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Conditional_Operator)去创建元素来表现当前的状态,然后让 React 根据它们来更新 UI。
观察这两个组件:
```jsx
function UserGreeting(props) {
return <h1>Welcome back!</h1>;
}
function GuestGreeting(props) {
return <h1>Please sign up.</h1>;
}
```
再创建一个 `Greeting` 组件,它会根据用户是否登录来决定显示上面的哪一个组件。
```jsx
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
// 根据条件来渲染组件(UI)
if (isLoggedIn) {
return <UserGreeting />;
}
return <GuestGreeting />;
}
ReactDOM.render(
// Try changing to isLoggedIn={true}:
<Greeting isLoggedIn={false} />,
document.getElementById('root')
);
```
## 元素变量
你可以使用变量来储存元素。 它可以帮助你有条件地渲染组件的一部分,而其他的渲染部分并不会因此而改变。
```jsx
class LoginControl extends React.Component {
constructor(props) {
super(props);
this.handleLoginClick = this.handleLoginClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
this.state = {isLoggedIn: false};
}
handleLoginClick() {
this.setState({isLoggedIn: true});
}
handleLogoutClick() {
this.setState({isLoggedIn: false});
}
render() {
const isLoggedIn = this.state.isLoggedIn;
let button;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
return (
<div>
<Greeting isLoggedIn={isLoggedIn} />
{button}
</div>
);
}
}
ReactDOM.render(
<LoginControl />,
document.getElementById('root')
);
```
[**在 CodePen 上尝试**](https://codepen.io/gaearon/pen/QKzAgB?editors=0010)
> 此方式有些复杂~
## 与运算符 &&
通过花括号包裹代码,你可以[在 JSX 中嵌入表达式](https://zh-hans.reactjs.org/docs/introducing-jsx.html#embedding-expressions-in-jsx)。这也包括 JavaScript 中的逻辑与 (&&) 运算符。它可以很方便地进行元素的条件渲染:
```jsx
function Mailbox(props){
const unreadMeg = props.unreadMeg
return (
<div>
{
unreadMeg.length &&
<h2>You have {unreadMeg.length} unread messages</h2>
}
</div>
)
}
const meg = ['1','22','33']
ReactDOM.render(
<Mailbox unreadMeg={meg} />,
document.getElementById('root')
)
```
如果条件是 `true``&&` 右侧的元素就会被渲染,如果是 `false`React 会忽略并跳过它。
请**注意**,返回 false 的表达式会使 `&&` 后面的元素被跳过,但会返回 false 表达式。在下面示例中render 方法的返回值是 `<div>0</div>`
```jsx
render() {
const count = 0;
return (
<div>
// 这里会渲染count的值
{ count && <h1>Messages: {count}</h1>}
</div>
);
}
```
## 三目运算符
```jsx
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
</div>
);
}
```
```jsx
render() {
const isLoggedIn = this.state.isLoggedIn;
return (
<div>
{isLoggedIn
? <LogoutButton onClick={this.handleLogoutClick} />
: <LoginButton onClick={this.handleLoginClick} />
}
</div>
);
}
```
> 可通过三目运算符来条件渲染相应组件。
## 阻止组件渲染
通过让 `render` 方法直接返回 `null`阻止渲染:
```jsx
function WarningBanner(props) {
if (!props.warn) {
// 返回null则不渲染此组件
return null;
}
return (
<div className="warning">
Warning!
</div>
);
}
class Page extends React.Component {
constructor(props) {
super(props);
this.state = {showWarning: true};
this.handleToggleClick = this.handleToggleClick.bind(this);
}
handleToggleClick() {
this.setState(state => ({
showWarning: !state.showWarning
}));
}
render() {
return (
<div>
<WarningBanner warn={this.state.showWarning} />
<button onClick={this.handleToggleClick}>
{this.state.showWarning ? 'Hide' : 'Show'}
</button>
</div>
);
}
}
ReactDOM.render(
<Page />,
document.getElementById('root')
);
```
在组件的 `render` 方法中返回 `null` 并不会影响组件的生命周期。例如,上面这个示例中,`componentDidUpdate` 依然会被调用。

View File

@ -0,0 +1,220 @@
---
title: 列表&Key
date: 2021-03-24 17:56:40
permalink: /pages/88f4b0/
categories:
- 《React》笔记
- 核心概念
tags:
- React
---
# 07. 列表 & Key
如下代码,我们使用 [`map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) 函数让数组中的每一项变双倍,然后我们得到了一个新的列表 `doubled` 并打印出来:
```js
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((number) => number * 2);
console.log(doubled);
```
在 React 中,把数组转化为[元素](https://zh-hans.reactjs.org/docs/rendering-elements.html)列表的过程是相似的。
## 渲染多个组件
```jsx
const numbers = [1,2,3]
// 通过map方法将数值放入li形成一个li标签组成的数值在一次性放入ul
const listItems = numbers.map(number => {
<li>{numbers}</li>
})
ReactDOM.render(
<ul>{listItems}</ul>
document.getElementById('root')
)
```
## 基础列表组件
将列表组合成一个组件:
```jsx
function NumberList(props){
const numbers = props.numbers
const listItems = numbers.map(number => {
// 记得给列表元素添加key
<li key={number.toString()}>
{number}
</li>
})
return (
<ul>{listItems}</ul>
)
}
const numbers = [1,2,3]
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
)
```
## key
**key 帮助 React 识别哪些元素改变了**,比如被添加或删除。因此你应当给数组中的每一个元素赋予一个确定的标识。
一个元素的 key 最好是这个元素在列表中拥有的**一个独一无二的字符串**。**通常,我们使用数据中的 id 来作为元素的 key**
```jsx
const todoItems = todos.map((todo) =>
<li key={todo.id}>
{todo.text}
</li>
);
```
当元素没有确定 id 的时候,**万不得已你可以使用元素索引 index 作为 key**
```jsx
const todoItems = todos.map((item, index) =>
// 只有item中没有id 才用index代替
<li key={index}>
{item.text}
</li>
);
```
**如果列表项目的顺序可能会变化,我们不建议使用索引来用作 key 值,因为这样做会导致性能变差,还可能引起组件状态的问题。**
如果你选择不指定显式的 key 值,那么 React 将默认使用索引用作为列表项目的 key 值
## 用 key 提取组件 (在map方法内设置key)
元素的 key 只有放在就近的数组上下文中才有意义。
**例子:不正确的使用 key 的方式**
```jsx
function ListItem(props) {
const value = props.value;
return (
// 错误!你不需要在这里指定 key
<li key={value.toString()}>
{value}
</li>
);
}
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
// 错误!元素的 key 应该在这里指定:
<ListItem value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
<NumberList numbers={numbers} />,
document.getElementById('root')
);
```
一个好的经验法则是:**在 `map()` 方法中的元素需要设置 key 属性**。
##
## key 只是在兄弟节点之间必须唯一
数组元素中使用的 key 在其兄弟节点之间应该是独一无二的。然而,它们**不需要是全局唯一的**。当我们生成两个不同的数组时,我们可以使用相同的 key 值。
```jsx
function Blog(props) {
const sidebar = ( <ul>
{props.posts.map((post) =>
<li key={post.id}> {post.title}
</li>
)}
</ul>
);
const content = props.posts.map((post) => <div key={post.id}> <h3>{post.title}</h3>
<p>{post.content}</p>
</div>
);
return (
<div>
{sidebar} <hr />
{content} </div>
);
}
const posts = [
{id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
{id: 2, title: 'Installation', content: 'You can install React from npm.'}
];
ReactDOM.render(
<Blog posts={posts} />,
document.getElementById('root')
);
```
### 不能用`key`当props名传给子组件
key 会传递信息给 React ,但不会传递给你的组件。如果你的组件中需要使用 `key` 属性的值,请用其他属性名显式传递这个值:
```jsx
const content = posts.map((post) =>
<Post
key={post.id}
id={post.id}
title={post.title} />
);
```
上面例子中,`Post` 组件可以读出 `props.id`,但是**不能读出 `props.key`**。
## 在 JSX 中嵌入 map()
JSX 允许在大括号中[嵌入任何表达式](https://zh-hans.reactjs.org/docs/introducing-jsx.html#embedding-expressions-in-jsx),所以我们可以内联 `map()` 返回的结果:
```jsx
function NumberList(props) {
const numbers = props.numbers;
return (
<ul>
{
numbers.map((number) =>
<ListItem key={number.toString()} value={number} />
)
}
</ul>
);
}
```
这么做有时可以使你的代码更清晰,但有时这种风格也会被滥用。
就像在 JavaScript 中一样,何时需要为了可读性提取出一个变量,这完全取决于你。但请记住,如果一个 `map()` 嵌套了太多层级,那可能就是你[提取组件](https://zh-hans.reactjs.org/docs/components-and-props.html#extracting-components)的一个好时机。

View File

@ -0,0 +1,269 @@
---
title: 表单
date: 2021-03-24 17:56:40
permalink: /pages/002db7/
categories:
- 《React》笔记
- 核心概念
tags:
- React
---
# 08. 表单
## 受控组件(双向数据绑定)
在 HTML 中,表单元素(如`<input>`、 `<textarea>``<select>`)通常自己维护 state并根据用户输入进行更新。而在 React 中可变状态mutable state通常保存在组件的 state 属性中,并且只能通过使用 [`setState()`](https://zh-hans.reactjs.org/docs/react-component.html#setstate)来更新。
我们可以把两者结合起来,使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。
例如,如果我们想让前一个示例在提交时打印出名称,我们可以将表单写为受控组件:
```jsx
class Name extends React.Component {
constructor(props){
super(props);
this.state = {value: ''}
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange(event){
this.setState({value: event.target.value})
}
handleSubmit(event){
alert(this.state.value)
event.preventDefault();
}
render(){
return(
<form onSubmit={this.handleSubmit}>
<label>
名字:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="提交" />
</form>
)
}
}
```
> 类似于vue中的双向绑定v-model
## textarea 标签使用value定义值
在 HTML 中, `<textarea>` 元素通过其子元素定义其文本:
```html
<textarea>
你好, 这是在 text area 里的文本
</textarea>
```
**在 React 中,`<textarea>` 使用 `value` 属性赋值**。这样,可以使得使用 `<textarea>` 的表单和使用单行 input 的表单非常类似:
```jsx
class EssayForm extends React.Component {
constructor(props) {
super(props);
this.state = {
value: '请撰写一篇关于你喜欢的 DOM 元素的文章.'
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('提交的文章: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
文章:
<textarea value={this.state.value} onChange={this.handleChange} /> </label>
<input type="submit" value="提交" />
</form>
);
}
}
```
**注意,`this.state.value` 初始化于构造函数中,因此文本区域默认有初值**
## select 标签 value代替选中属性
**React 在根 `select` 标签上使用 `value` 属性代替`option`元素上的`selected` 属性(选中属性)**
在 HTML 中,`<select>` 创建下拉列表标签。例如,如下 HTML 创建了水果相关的下拉列表:
```jsx
<select>
<option value="grapefruit">葡萄柚</option>
<option value="lime">酸橙</option>
<option selected value="coconut">椰子</option>
<option value="mango">芒果</option>
</select>
```
请注意,由于 `selected` 属性的缘故,椰子选项默认被选中。**React 并不会使用 `selected` 属性,而是在根 `select` 标签上使用 `value` 属性**。这在受控组件中更便捷,因为您只需要在根标签中更新它。例如:
```jsx
class FlavorForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: 'coconut'};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('你喜欢的风味是: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
选择你喜欢的风味:
<select value={this.state.value} onChange={this.handleChange}>
<option value="grapefruit">葡萄柚</option>
<option value="lime">酸橙</option>
<option value="coconut">椰子</option>
<option value="mango">芒果</option>
</select>
</label>
<input type="submit" value="提交" />
</form>
);
}
}
```
### select多选
你可以将数组传递到 `value` 属性中,以支持在 `select` 标签中选择多个选项:
```jsx
<select multiple={true} value={['B', 'C']}>
```
### 小总结
总的来说,这使得 `<input type="text">`, `<textarea>``<select>` 之类的标签都非常相似—它们都接受一个 `value` 属性,你可以使用它来实现受控组件。
## 文件 input 标签 (非受控组件)
在 HTML 中,`<input type="file">` 允许用户从存储设备中选择一个或多个文件,将其上传到服务器,或通过使用 JavaScript 的 [File API](https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications) 进行控制。
```html
<input type="file" />
```
因为它的 value 只读,所以它是 React 中的一个**非受控**组件。将与其他非受控组件[在后续文档中](https://zh-hans.reactjs.org/docs/uncontrolled-components.html#the-file-input-tag)一起讨论。
## 处理多个输入
当需要处理多个 `input` 元素时,我们可以给每个元素添加 `name` 属性,并让处理函数根据 `event.target.name` 的值选择要执行的操作。
```jsx
class Reservation extends React.Component {
constructor(props) {
super(props);
this.state = {
isGoing: true,
numberOfGuests: 2
};
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
// ES6 计算属性名称
[name]: value
});
}
render() {
return (
<form>
<label>
参与:
<input
name="isGoing"
type="checkbox"
checked={this.state.isGoing}
onChange={this.handleInputChange} />
</label>
<br />
<label>
来宾人数:
<input
name="numberOfGuests"
type="number"
value={this.state.numberOfGuests}
onChange={this.handleInputChange} />
</label>
</form>
);
}
}
```
## 受控输入空值
在[受控组件](https://zh-hans.reactjs.org/docs/forms.html#controlled-components)上指定 value 的 prop 会阻止用户更改输入。如果你指定了 `value`,但输入仍可编辑,则可能是你意外地将`value` 设置为 `undefined``null`
下面的代码演示了这一点。(输入最初被锁定,但在短时间延迟后变为可编辑。)
```jsx
ReactDOM.render(<input value="hi" />, mountNode);
setTimeout(function() {
ReactDOM.render(<input value={null} />, mountNode);
}, 1000);
```
## 受控组件的替代品 (非受控组件)
有时使用受控组件会很麻烦,因为**你需要为数据变化的每种方式都编写事件处理函数,并通过一个 React 组件传递所有的输入 state**。当你将之前的代码库转换为 React 或将 React 应用程序与非 React 库集成时,这可能会令人厌烦。在这些情况下,你可能希望使用[非受控组件](https://zh-hans.reactjs.org/docs/uncontrolled-components.html), 这是实现输入表单的另一种方式。
## 成熟的解决方案
如果你想寻找包含验证、追踪访问字段以及处理表单提交的完整解决方案,使用 [Formik](https://jaredpalmer.com/formik) 是不错的选择。然而,它也是建立在受控组件和管理 state 的基础之上 —— 所以不要忽视学习它们。

View File

@ -0,0 +1,12 @@
---
title: 状态提升
date: 2021-03-24 17:56:40
permalink: /pages/f0e3d2/
categories:
- 《React》笔记
- 核心概念
tags:
- React
---
# 09. 状态提升

View File

@ -0,0 +1,12 @@
---
title: 组合vs继承
date: 2021-03-24 17:56:40
permalink: /pages/9ae8e8/
categories:
- 《React》笔记
- 核心概念
tags:
- React
---
# 10.组合vs继承

View File

@ -0,0 +1,12 @@
---
title: React哲学
date: 2021-03-24 17:56:40
permalink: /pages/c689bf/
categories:
- 《React》笔记
- 核心概念
tags:
- React
---
# 11.React哲学

View File

@ -0,0 +1,11 @@
---
title: 高级指引
date: 2021-03-25 19:46:01
permalink: /pages/b7ec27/
categories:
- 《React》笔记
- 高级指引
tags:
- React
---
# 01.高级指引

View File

@ -0,0 +1,11 @@
---
title: Hook
date: 2021-03-25 19:46:03
permalink: /pages/4c13b9/
categories:
- 《React》笔记
- Hook
tags:
- React
---
# 01. Hook

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- 初识 TypeScript
tags:
-
- TypeScript
---
# 简介
@ -36,5 +36,3 @@ TypeScript 提供最新的和不断发展的 JavaScript 特性,包括那些来
## 总结
TypeScript 在社区的流行度越来越高,它非常适用于一些大型项目,也非常适用于一些基础库,极大地帮助我们提升了开发效率和体验。如果你还没有开始学习 TypeScript那么你可能要落后了哟所以还等什么快来和我一起学习并使用 TypeScript 吧,来感受一下它为我们带来的奇妙体验。

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- 初识 TypeScript
tags:
-
- TypeScript
---
# 安装 TypeScript

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- 初识 TypeScript
tags:
-
- TypeScript
---
# 编写第一个 TypeScript 程序
@ -146,7 +146,3 @@ console.log(greeter(user))
## 总结
到这里,你已经对 TypeScript 有了一个大致的印象,那么下一章让我们来一起学习 TypeScript 的一些常用语法吧。

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- TypeScript 常用语法
tags:
-
- TypeScript
---
# 基础类型
@ -250,7 +250,3 @@ let strLength: number = (someValue as string).length
```
两种形式是等价的。 至于使用哪个大多数情况下是凭个人喜好;然而,当你在 TypeScript 里使用 JSX 时,只有 `as` 语法断言是被允许的。

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- TypeScript 常用语法
tags:
-
- TypeScript
---
# 变量声明

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- TypeScript 常用语法
tags:
-
- TypeScript
---
# 接口
@ -493,4 +493,3 @@ class ImageC implements SelectableControl {
在上面的例子里,`SelectableControl` 包含了 `Control` 的所有成员,包括私有成员 `state`。 因为 `state` 是私有成员,所以只能够是 `Control` 的子类们才能实现 `SelectableControl` 接口。 因为只有 `Control` 的子类才能够拥有一个声明于`Control` 的私有成员 `state`,这对私有成员的兼容性是必需的。
`Control` 类内部,是允许通过 `SelectableControl` 的实例来访问私有成员 `state` 的。 实际上,`SelectableControl` 接口和拥有 `select` 方法的 `Control` 类是一样的。`Button`和 `TextBox` 类是 `SelectableControl` 的子类(因为它们都继承自`Control` 并有 `select` 方法),但 `ImageC` 类并不是这样的。

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- TypeScript 常用语法
tags:
-
- TypeScript
---
# 类
@ -513,5 +513,3 @@ interface Point3d extends Point {
let point3d: Point3d = {x: 1, y: 2, z: 3}
```

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- TypeScript 常用语法
tags:
-
- TypeScript
---
# 函数

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- TypeScript 常用语法
tags:
-
- TypeScript
---
# 泛型
@ -252,4 +252,3 @@ let x = {a: 1, b: 2, c: 3, d: 4}
getProperty(x, 'a') // okay
getProperty(x, 'm') // error
```

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- TypeScript 常用语法
tags:
-
- TypeScript
---
# 类型推断

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- TypeScript 常用语法
tags:
-
- TypeScript
---
# 高级类型
@ -377,6 +377,3 @@ Argument of type '"uneasy"' is not assignable to parameter of type '"ease-in" |
那么到这里,我们的 TypeScript 常用语法学习就告一段落了,当然 TypeScript 还有其他的语法我们并没有讲,我们只是讲了 TypeScript 的一些常用语法,你们把这些知识学会已经足以开发一般的应用了。如果你在使用 TypeScript 开发项目中遇到了其他的 TypeScript 语法知识,你可以通过 TypeScript 的[官网文档](https://www.typescriptlang.org/docs/home.html)学习。因为学基础最好的方法还是去阅读它的官网文档,敲上面的小例子。其实我们课程的基础知识结构也是大部分参考了官网文档,要记住学习一门技术的基础官网文档永远是最好的第一手资料。
但是 TypeScript 的学习不能仅仅靠看官网文档,你还需要动手实践,在实践中你才能真正掌握 TypeScript。相信很多同学学习到这里已经迫不及待想要大展身手了那么下面我们就开始把理论转换为实践一起来用 TypeScript 重构 axios 吧!

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- ts-axios 项目初始化
tags:
-
- TypeScript
---
# 需求分析
@ -26,4 +26,3 @@ tags:
此外,我们还会支持一些 axios 库支持的一些其它的 feature。这里要注意的我们这次重构不包括 axios 在 Node 中的实现,因为这部分我们在平时项目中应用的很少,还涉及到很多 Node.js 的知识,如果都讲的话,一是比较占用时间,另一个可能会喧宾夺主了。当然,这部分知识点我会根据同学们学习的反馈,如果大家很感兴趣想学习的话,我就作为课程的补充内容加到后期视频的扩展中,也当做课程的福利送给大家,所以大家务必要支持一下正版课程喔~
那么接下来我们就开始初始化项目吧!

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- ts-axios 项目初始化
tags:
-
- TypeScript
---
# 初始化项目
@ -146,5 +146,3 @@ git push origin master
接着我们去 GitHub 仓库中就可以看到刚才这条提交记录了。
至此,我们项目已经初始化完毕,接下来我们就开始编写源码实现 axios 了。

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- ts-axios 项目初始化
tags:
-
- TypeScript
---
# 编写基础请求代码

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- ts-axios 基础功能实现
tags:
-
- TypeScript
---
# 处理请求 url 参数

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- ts-axios 基础功能实现
tags:
-
- TypeScript
---
# 处理请求 body 数据
@ -152,5 +152,3 @@ router.post('/base/buffer', function(req, res) {
实际上是因为我们虽然执行 `send` 方法的时候把普通对象 `data` 转换成一个 `JSON` 字符串,但是我们请求`header` 的 `Content-Type``text/plain;charset=UTF-8`,导致了服务端接受到请求并不能正确解析请求 `body` 的数据。
知道这个问题后,下面一节课我们来实现对请求 `header` 的处理。

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- ts-axios 基础功能实现
tags:
-
- TypeScript
---
# 处理请求 header

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- ts-axios 基础功能实现
tags:
-
- TypeScript
---
# 获取响应数据
@ -162,5 +162,3 @@ axios({
我们打开浏览器运行 demo看一下结果发现我们可以正常 log 出这个 `res` 变量,它包含 `AxiosResponse` 类型中定义的那些属性,不过我们发现 2 个小问题:第一个是 `headers` 属性是一个字符串,我们需要把它解析成对象类型;第二个是在第一个请求中,得到的数据是一个 JSON 字符串,我们也需要把它转换成对象类型。
那么下一小节,我们将来解决第一个问题,对于响应的 `header` 做处理。

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- ts-axios 基础功能实现
tags:
-
- TypeScript
---
# 处理响应 header

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- ts-axios 基础功能实现
tags:
-
- TypeScript
---
# 处理响应 data

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- ts-axios 异常情况处理
tags:
-
- TypeScript
---
# 错误处理

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- ts-axios 异常情况处理
tags:
-
- TypeScript
---
# 错误信息增强

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- ts-axios 接口扩展
tags:
-
- TypeScript
---
# 扩展接口

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- ts-axios 接口扩展
tags:
-
- TypeScript
---
# axios 函数重载

View File

@ -7,7 +7,7 @@ categories:
- 《TypeScript 从零实现 axios》
- ts-axios 接口扩展
tags:
-
- TypeScript
---
# 响应数据支持泛型

Some files were not shown because too many files have changed in this diff Show More