沙雕爹爹

Stay foolish, stay humble.


  • Home

  • Archives

React Hooks(一)

Posted on 2019-04-19

Hooks

  • useState
  • useEffect
  • useContext

Rules of Hooks

  • 只在top level调用Hooks,不要在loops、conditions或者嵌套函数中调用
  • 只在React函数组件中调用Hooks,不要在普通Javascript函数中调用(或者在你自定义的Hooks中调用)。

自定义Hooks

可以解决之前需要通过借助heigher-order-components和render props才能解决的组件间状态逻辑的复用。

一个叫useFriendStatus的Hook:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React, { useState, useEffect } from 'react';

function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);

function handleStatusChange(status) {
setIsOnline(status.isOnline);
}

useEffect(() => {
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
};
});

return isOnline;
}

使用useFriendStatus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// FriendStatus.js
function FriendStatus(props) {
const isOnline = useFriendStatus(props.friend.id);

if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}

// FriendListItem.js
function FriendListItem(props) {
const isOnline = useFriendStatus(props.friend.id);

return (
<li style={{ color: isOnline ? 'green' : 'black' }}>
{props.friend.name}
</li>
);
}

这些组件间的状态是完全独立的。Hooks复用状态逻辑,而不是状态本身。每次调用自定义Hook都会生成完全独立的状态。

Typescript-v3.1(转)

Posted on 2019-04-19

原文链接

元组和数组上的映射类型

Typescript 3.1,在元组和数组上的映射对象类型现在会生成新的元组/数组,而非创建一个新的类型并且在这个类型上具有如push(),pop()和length这样的成员:

1
2
3
4
5
type MapToPromise<T> = { [K in keyof T]: Promise<T[K]> };

type Coordinate = [number, number]

type PromiseCoordinate = MapToPromise<Coordinate>; // [Promise<number>, Promise<number>]

MapToPromise接受参数T,当它是个像Coordinate这样的元组时,只有数值型属性会被转换。[number, number]具有两个数值型属性:0和1。针对这样的数组,MapToPromise会创建一个新的元组,0和1属性是原类型的一个Promise。 因此PromiseCoordinate的类型为[Promise<number>, Promise<number>]。

函数上的属性声明

TypeScript 3.1提供了在函数声明上定义属性的能力,还支持const声明的函数。只需要在函数直接给属性赋值就可以了。 这样我们就可以规范JavaScript代码,不必再借助于namespace。 例子:

1
2
3
4
5
6
7
8
function readImage(path: string, callback: (err: any, image: Image) => void) {
// ...
}

readImage.sync = (path: string) => {
const contents = fs.readFileSync(path);
return decodeImageSync(contents);
}

这里,readImage函数异步地读取一张图片。 此外,我们还在readImage上提供了一个便捷的函数readImage.sync。

一般来说,使用ECMAScript导出是个更好的方式,但这个新功能支持此风格的代码能够在TypeScript里执行。 此外,这种属性声明的方式允许我们表达一些常见的模式,例如React无状态函数型组件(SFCs)里的defaultProps和propTpes 。

1
2
3
4
5
6
7
export const FooComponent => ({ name }) => (
<div>Hello! I am {name}</div>
);

FooComponent.defaultProps = {
name: "(anonymous)",
};

[1] 更确切地说,是上面那种同态映射类型。

使用typesVersions选择版本

由社区的反馈还有我们的经验得知,利用最新的TypeScript功能的同时容纳旧版本的用户很困难。 TypeScript引入了叫做typesVersions的新特性来解决这种情况。

在TypeScript 3.1里使用Node模块解析时,TypeScript会读取package.json文件,找到它需要读取的文件,它首先会查看名字为typesVersions的字段。 一个带有typesVersions字段的package.json文件:

1
2
3
4
5
6
7
8
{
"name": "package-name",
"version": "1.0",
"types": "./index.d.ts",
"typesVersions": {
">=3.1": { "*": ["ts3.1/*"] }
}
}

package.json告诉TypeScript去检查当前版本的TypeScript是否正在运行。 如果是3.1或以上的版本,它会找出你导入的包的路径,然后读取这个包里面的ts3.1文件夹里的内容。 这就是{ "*": ["ts3.1/*"] }的意义 - 如果你对路径映射熟悉,它们的工作方式类似。

因此在上例中,如果我们正在从"package-name"中导入,并且正在运行的TypeScript版本为3.1,我们会尝试从[...]/node_modules/package-name/ts3.1/index.d.ts开始解析。 如果是从package-name/foo导入,由会查找[...]/node_modules/package-name/ts3.1/foo.d.ts和[...]/node_modules/package-name/ts3.1/foo/index.d.ts。

那如果当前运行的TypeScript版本不是3.1呢? 如果typesVersions里没有能匹配上的版本,TypeScript将回退到查看types字段,因此TypeScript 3.0及之前的版本会重定向到[...]/node_modules/package-name/index.d.ts。

匹配行为

TypeScript使用Node的semver ranges去决定编译器和语言版本。

多个字段

typesVersions支持多个字段,每个字段都指定了一个匹配范围。

1
2
3
4
5
6
7
8
9
{
"name": "package-name",
"version": "1.0",
"types": "./index.d.ts",
"typesVersions": {
">=3.2": { "*": ["ts3.2/*"] },
">=3.1": { "*": ["ts3.1/*"] }
}
}

因为范围可能会重叠,因此指定的顺序是有意义的。 在上例中,尽管>=3.2和>=3.1都匹配TypeScript 3.2及以上版本,反转它们的顺序将会有不同的结果,因此上例与下面的代码并不等同。

1
2
3
4
5
6
7
8
9
10
{
"name": "package-name",
"version": "1.0",
"types": "./index.d.ts",
"typesVersions": {
// 注意,这样写不生效
">=3.1": { "*": ["ts3.1/*"] },
">=3.2": { "*": ["ts3.2/*"] }
}
}

深入理解TypeScript(一)(转)

Posted on 2019-04-19

原文链接

编译上下文

用来给文件分组,告诉TS哪些文件是有效的,哪些是无效的。
包含了有哪些编译选项正在使用。
定义这种逻辑分组,一个比较好的方式是使用tsconfig.json文件。

tsconfig.json

在项目根目录下创建一个空json文件,通过这种方式,TS会将此目录下的所有.ts文件作为编译上下文的一部分,还会包含一部分默认的编译选项。

编译选项

通过compilerOptions来定制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
{
"compilerOptions": {

/* 基本选项 */
"target": "es5", // 指定 ECMAScript 目标版本: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'
"module": "commonjs", // 指定使用模块: 'commonjs', 'amd', 'system', 'umd' or 'es2015'
"lib": [], // 指定要包含在编译中的库文件
"allowJs": true, // 允许编译 javascript 文件
"checkJs": true, // 报告 javascript 文件中的错误
"jsx": "preserve", // 指定 jsx 代码的生成: 'preserve', 'react-native', or 'react'
"declaration": true, // 生成相应的 '.d.ts' 文件
"sourceMap": true, // 生成相应的 '.map' 文件
"outFile": "./", // 将输出文件合并为一个文件
"outDir": "./", // 指定输出目录
"rootDir": "./", // 用来控制输出目录结构 --outDir.
"removeComments": true, // 删除编译后的所有的注释
"noEmit": true, // 不生成输出文件
"importHelpers": true, // 从 tslib 导入辅助工具函数
"isolatedModules": true, // 将每个文件做为单独的模块 (与 'ts.transpileModule' 类似).

/* 严格的类型检查选项 */
"strict": true, // 启用所有严格类型检查选项
"noImplicitAny": true, // 在表达式和声明上有隐含的 any类型时报错
"strictNullChecks": true, // 启用严格的 null 检查
"noImplicitThis": true, // 当 this 表达式值为 any 类型的时候,生成一个错误
"alwaysStrict": true, // 以严格模式检查每个模块,并在每个文件里加入 'use strict'

/* 额外的检查 */
"noUnusedLocals": true, // 有未使用的变量时,抛出错误
"noUnusedParameters": true, // 有未使用的参数时,抛出错误
"noImplicitReturns": true, // 并不是所有函数里的代码都有返回值时,抛出错误
"noFallthroughCasesInSwitch": true, // 报告 switch 语句的 fallthrough 错误。(即,不允许 switch 的 case 语句贯穿)

/* 模块解析选项 */
"moduleResolution": "node", // 选择模块解析策略: 'node' (Node.js) or 'classic' (TypeScript pre-1.6)
"baseUrl": "./", // 用于解析非相对模块名称的基目录
"paths": {}, // 模块名到基于 baseUrl 的路径映射的列表
"rootDirs": [], // 根文件夹列表,其组合内容表示项目运行时的结构内容
"typeRoots": [], // 包含类型声明的文件列表
"types": [], // 需要包含的类型声明文件名列表
"allowSyntheticDefaultImports": true, // 允许从没有设置默认导出的模块中默认导入。

/* Source Map Options */
"sourceRoot": "./", // 指定调试器应该找到 TypeScript 文件而不是源文件的位置
"mapRoot": "./", // 指定调试器应该找到映射文件而不是生成文件的位置
"inlineSourceMap": true, // 生成单个 soucemaps 文件,而不是将 sourcemaps 生成不同的文件
"inlineSources": true, // 将代码与 sourcemaps 生成到一个文件中,要求同时设置了 --inlineSourceMap 或 --sourceMap 属性

/* 其他选项 */
"experimentalDecorators": true, // 启用装饰器
"emitDecoratorMetadata": true // 为装饰器提供元数据的支持
}
}

编译

好的IDE支持即时编译,也可以从命令行手动运行编译器。

  • 运行tsc,会在当前目录或者父级目录寻找tsconfig.json文件
  • 运行tsc -p ./path-to-project-directory。这个路径可以是绝对路径,也可以是相对路径。

使用tsc -w启用TS编译器的观测模式,在检测到文件改动后,将重新编译。

指定文件

也可以显式指定需要编译的文件:

1
2
3
4
5
{
"files": [
"./some/file.ts"
]
}

或者使用include和exclude选项来指定需要包含的文件和排除的文件:

1
2
3
4
5
6
7
8
9
{
"include": [
"./folder"
],
"exclude": [
"./folder/**/*.spec.ts",
"./folder/someSubFolder"
]
}

声明空间

两种声明空间:类型声明空间和变量声明空间。

类型声明空间

当作类型注解的内容:

1
2
3
class Foo {}
interface Bar {}
type Bas = {};

这里可以将Foo,Bar,Bas当作类型注解使用:

1
2
3
let foo: Foo;
let bar: Bar;
let bas: Bas;

注意,下面尽管定义了interface Bar,但不能将它作为变量使用,因为它没有定义在变量声明空间中:

1
2
interface Bar {}
const bar = Bar; // Error: "cannot find name 'Bar'"

变量声明空间

变量声明空间包括可用作变量的内容,在前面class Foo提供了类型Foo到类型声明空间,同时提供了一个变量Foo到变量声明空间:

1
2
3
class Foo {}
const someVar = Foo;
const someOtherVar = 123;

Markdown语法说明(简体中文版)(转)

Posted on 2019-04-17

原文链接

概述

宗旨

易读易写

兼容HTML

目标是:成为一种适用于网络的书写语言。

特殊字符自动转换

在HTML文件中,<和&需要特殊处理,如果想显示这两个字符的原型,需要使用实体的形式,如&lt;和&amp;。
如果要插入版权©,需要写成&copy;。

区块元素

段落和换行

一个段落是文本行组成的,前后需要一个以上的空行。
如果某一行只包含空格和制表符,也会被视为空行。
Markdown允许段落内插入换行符,只需要在插入处按入两个以上的空格,然后回车。相当于插入一个<br />标签。

标题

类Setext形式是用底线的形式,=(最高阶标题)-(第二阶标题),例如:

1
2
3
4
5
This is an H1
==============

This is an H2
-------------

任何数量的=和-都可以有这个效果。

类Atx形式则是在行首插入1到6个#,对应H1~H6,例如:

1
2
3
# 这是 H1
## 这是 H2
###### 这是 H6`

区块引用 Blockquotes

类似于email中用>的引用方式。

1
2
3
4
5
> This is a blockquote with two paragraphs. I
> have
> a dream today.
>
> by Martin Luther King

也可以只在第一行最前面加>:

1
2
3
4
5
> This is a blockquote with two paragraphs. I
have
a dream today.

> by Martin Luther King

引用的区块内也可以使用其它的Markdown语法,包括标题、列表、代码区块等:

1
2
3
4
5
6
7
> ## 这是一个标题。
>
> 1. 这是第一行列表项
> 2. 这是第二行列表项
> 给出一些例子代码:
>
> return shell_exec("echo $input | $markdown_script");

列表

Markdown支持有序列表和无序列表。
无序列表使用星号、加号或是减号作为标记:

1
2
3
* Red
* Green
* Blue

等同于:

1
2
3
4
5
6
7
+ Red
+ Green
+ Blue

- Red
- Green
- Blue

有序列表则使用数字接着一个英文句点:

1
2
3
1. Bird
2. Mchale
3. Parish

很重要的一点:列表标记上使用的数字不会影响HTML结果。

1
2
3
4
5
6
7
1. Bird
1. Mchale
1. Parish

3. Bird
1. Mchale
8. Parish

都会得到完全相同的HTML输出。
列表项目标记通常是放在最左边,后面一定要接着至少一个空格或制表符。
列表项目可以包含多个段落,每个项目下的段落都必须缩进4个空格或者1个制表符:

1
2
3
1. This is a list item with two paragraphs.
This is the other paragraph.
2. Another item.

如果要在列表项目内放进引用,那>就需要缩进:

1
2
3
* A list item with a blockquote:
> This is a blockquote
> inside a list item.

如果要放代码区块的话,该区块需要缩进8个空格或者2个制表符:

1
2
* A list item with code block
function foo() {}

首行出现数字-句点-空白就会被视为有序列表,可以用\来转义:

1
1986\. What a great season.

代码区块

只要简单的缩进4个空格或者1个制表符就可以在Markdown中建立代码区块。

1
2
3
A normal paragraph.

function foo() {}

一个代码区块会一直持续到没有缩进的那一行(或是文件末尾)。
在代码区块里面,&、<和>都会自动转成HTML实体。
代码区块中,一般的Markdown语法不会被转换,像星号就是星号,可以很容易的用Markdown语法撰写Markdown语法相关文件。

分隔线

用三个以上的星号、减号、底线来建立分隔线。行内不能有其它东西。可以在星号或减号中间插入空格。

1
2
3
4
5
6
***
* * *
******
___
_ _ _
_____________

区段元素

链接

链接文字用[方括号]来标记。
要建立一个行内式的链接,只要在方括号后面紧跟插入网址链接的圆括号即可。如果想添加title文字,只要在网址后,用双引号把title文字包起来即可。

1
2
This is [an example](http://example.com/ "Title") inline link.
[This link](http://example.net/) has no title attribute.

也可以使用相对路径:

1
See my [About](/about/) page for details.

参考式的链接是在链接文字的括号后再加上一个方括号,并填入用以辨识链接的标记:

1
This is [an example][id] reference-style link.

接着,在文件的任意处,可以把这个标记的链接内容定义出来:

1
[id]: http://example.com/ "Optional Title Here"

链接内容定义的形式为:

  • 方括号(前面可以选择性的加上至多3个空格来缩进)和链接文字
  • 冒号
  • 一个以上的空格或制表符
  • 链接地址,可以用尖括号包起来
  • title,可以用单引号、双引号或者括号包起来(可以放到下一行,也可以加一些缩进来美化)

以下五种的定义是相同的:

1
2
3
4
5
6
[foo]: http://example.com/  "Optional Title Here"
[foo]: http://example.com/ 'Optional Title Here'
[foo]: http://example.com/ (Optional Title Here)
[foo]: <http://example.com/> "Optional Title Here"
[foo]: http://example.com/longish/path/to/resource/here
"Optional Title Here"

链接辨识标签可以由字母、数字、空白和标点符号组成,不区分大小写。[link text][a]和[link text][A]是相同的。
隐式链接标记功能可以省略指定链接辨识标签,这时,链接辨识id等同于链接文字:

1
2
3
4
5
6
7
[Google][]

[Google]: https://google.com/

Visit [Daring Fireball][] for more information.

[Daring Fireball]: http://daringfireball.net/

强调

用星号(*)和底线(_)作为强调符号,一个符号相当于<em>,两个符号相当于<strong>:

1
2
3
4
5
6
7
*single asterisks*

_single asterisks_

**single asterisks**

__single asterisks__

可以用\转义。

代码

如果要标记行内代码,可以用反引号包起来(`)。
如果要在代码区段内插入反引号,可以用多个反引号来开启和结束代码区段。

1
`` A paragraph with (`) in it. ``

图片

行内式

1
2
![Alt text](/path/to/img.jpg)
![Alt text](/path/to/img.jpg "Optional title")
  • 一个感叹号!
  • 接着一个方括号,填入图片的替代文本alt
  • 接着一个普通括号,填入图片的地址,并加上选填的title

参考式

1
2
3
![Alt text][id]

[id]: url/to/image "Optional title"

到目前为止,没有办法指定图片的宽高,如果需要的话,可以使用普通的<img>标签。

其它

自动链接

<http://example.com/>

反斜杠

Markdown支持转义的符号:

1
2
3
4
5
6
7
8
9
10
11
12
\
`
*
_
{}
[]
()
#
+
-
.
!

我的新post

Posted on 2019-03-29

使用hexo new命令创建

1…56

沙雕爹爹

Personal tech blog.

55 posts
45 tags
© 2019 沙雕爹爹
Powered by Hexo
|
Theme — NexT.Muse v5.1.4