0%

react

我也知道有很多工具可以快速搭建 react,甚至只需要写业务代码,但是遇到底层(其实这也不算底层)的东西,或者需要高度自定义的东西的时候,那些脚手架显然是不够用的。

React 设计思想

React 设计思想原文

react 官方推荐全栈课程

npx create-react-app part1 在 part1 文件夹中使用官方脚手架创建一个基础的 react 项目。有一点需要注意,npx 执行产生的 lock文件npmlock文件,如果需要用到 yarn,则使用 yarn create react-app part1

ReactDOM.render(<App />, document.getElementById('root')) 这是将其内容渲染到 div 元素中,其 id 值为 ‘root’,该元素在文件 public/index.html 中定义。

关于babel,在使用 create-React-app 创建的 React 应用中转译是自动配置好的。

与其他语言相反,在 JavaScript 中,this 的值是根据 方法如何调用 来定义的。 当通过引用调用该方法时, this 的值就变成了所谓的全局对象。

通常在 JSX-模板 中定义事件处理程序并不是一个好的实践。 无论如何,让我们将事件处理程序分离成单独的函数。

部件并不会重新渲染。 我们可以通过再次调用 ReactDOM.render 方法让组件重新渲染,当然我们现在有 useState 不需要这样子,而且这样也十分耗性能。

1
2
3
4
5
6
7
8
9
10
11
let counter = 1;

const refresh = () => {
ReactDOM.render(<App counter={counter} />, document.getElementById("root"));
};

refresh();
counter += 1;
refresh();
counter += 1;
refresh();

实际上, { …clicks } 创建了一个新对象,该对象是具有 clicks 对象的所有属性的副本。 当我们向对象添加新属性时,例如 { …clicks, right: 1 },新对象中 right 属性的值将为 1。

【Hook 的规则】 不能从循环、条件表达式或任何不是定义组件的函数的地方调用 useState (同样的还有 useEffect 函数,将在后面的课程中介绍)。 这样做是为了确保 Hook 总是以相同的顺序调用,如果不是这样,应用的行为就会不规则。

onClick 与 setTimeout 一样,接收的是一个函数(事件处理程序)而不是一个函数执行(function call)。
我们的事件处理被定义为 function call,这意味着事件处理程序实际上被分配了函数返回的值,而 console.log 的返回值是 undefined。
当然如果函数的返回值是函数的话,即使接收函数执行也没关系。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 可正常执行
const App = () => {
const [value, setValue] = useState(10);

const hello = (who) => {
const handler = () => console.log(`hello ${who}`);
return handler;
};

return (
<div>
{value}
<button onClick={hello("react")}>button</button>
<button onClick={hello("sheeep")}>button</button>
</div>
);
};

Do Not Define Components Within Components 【不要在组件中定义组件】

列表项,即 map 方法生成的每个元素,都必须有一个唯一的键值: 一个名为 key 的属性。

json-server

您可以使用命令 npm install -g json-server 在您的机器上安装 JSON 服务器。

1
npx json-server --port 3001 --watch db.json

国家信息

REST

在 REST 术语中,我们将单个数据对象(如应用中的便笺)称为 resources。 每个资源都有一个唯一的地址——它的 URL。 根据 json-server 使用的一般约定,我们将能够在资源 URL, 即 notes/3 上定位某个便笺,其中 3 是资源的 id。 另一方面, notes url 指向包含所有便笺的资源集合。

通过 HTTP GET 请求从服务器获取资源。 例如,对 URLnotes/3 的 HTTP GET 请求将返回 id 为 3 的便笺。 对 notes URL 的 HTTP GET 请求将返回所有便笺的列表。

根据 json 服务器遵守的 REST 约定,通过向 notes URL 发出 HTTP POST 请求来创建、存储新的便笺。 新便笺资源的数据在请求的 body 中发送。

Json-server 要求以 JSON 格式发送所有数据。 实际上,这意味着数据必须是格式正确的字符串,并且请求必须包含值为 application/json 的 Content-Type 请求头。

nodemon

如果我们对应用的代码进行更改,我们必须重新启动应用以查看更改。 我们通过键入 ⌃+C 首先关闭应用,然后重新启动应用。 与 React 中方便的工作流程相比,Node 就有点麻烦,在 React 中,浏览器会在进行更改后自动重新加载。

解决这个问题的方法是使用 nodemon :

nodemon 将监视启动 nodemon 的目录中的文件,如果任何文件发生更改,nodemon 将自动重启 node 应用。

cors

请记住,同源策略和 CORS 并不是特定于 React 或 Node 的。 它们实际上是 web 应用操作的通用原则。

我们可以通过使用 Node 的 cors 中间件来允许来自其他源的请求。

eslint 配置

npm install eslint –save-dev

npx eslint –init

许多公司定义了通过 ESlint 配置文件在整个组织中执行的编码标准。 建议不要一遍又一遍地使用重造轮子,从别人的项目中采用现成的配置到自己的项目中可能是一个好主意。 最近,很多项目都采用了 Airbnb 的 Javascript 风格指南,使用了 Airbnb 的 ESlint

mongo

pwd: lsy…

为什么要用 TypeScript?

在不同的论坛上,你可能会遇到很多支持或反对 TypeScript 的争论。 事实很可能是模糊的: 这取决于你的需求和对 TypeScript 所提供函数的使用。 但无论如何,这里解释了我们为什么认为使用 TypeScript 有一些优势,以及这背后的一些原因。

首先,TypeScript 提供了类型检查和静态代码分析。 我们可以要求值具有某种类型,并让编译器警告不要使用错误的值。 这可以减少运行时错误,甚至可以减少项目中所需的单元测试数量,至少在涉及纯类型测试时是这样。

静态程序分析不仅警告错误的类型使用,还有其他错误,比如拼错变量或函数名,或者试图使用超出范围的变量。

TypeScript 的第二个优点是代码中的类型注解可以作为代码级文档 的类型发挥作用。

通过函数签名可以很容易地检查函数可以使用哪种类型的参数,以及它将返回哪种类型的数据。 这种类型的类型注解绑定文档将始终是最新的,并且它使新的程序员更容易开始处理现有的项目。 当返回到一个旧的项目时,这也是有帮助的。

类型可以在整个代码库中重用,对类型定义的更改将自动反映所有使用该类型的地方。 有人可能会说,你可以用 JSDoc 实现类似的代码级文档,但是它与代码的连接不像 TypeScript 的类型那样紧密,因此更有可能不同步,而且也更加冗长。

TypeScript 的第三个优点是,当 IDE 确切知道您正在处理的数据类型时,它们可以提供更具体、更智能的智能感知。

当您需要重构代码时,所有这些特性都非常有用。 静态程序分析会警告你代码中的任何错误,智能感知可以提示你可用的属性,甚至可能的重构选项。 代码级文档可以帮助您理解现有的代码。

在 TypeScript 的帮助下,在早期阶段仅仅通过改变配置就可以很容易地开始使用最新的 JavaScript 语言特性。

TypeScript 不能解决什么问题?

如上所述,TypeScript 类型注解和类型检查仅在编译时存在,在运行时不再存在。 即使编译器没有抛出任何错误,运行时仍然是有可能抛出错误的。

这些运行时错误在处理外部输入(如从网络请求接收的数据)时特别常见。

最后,下面我们列举了一些 TypeScript 中存在的问题,这些问题值得注意:

  • Incomplete, invalid or missing types in external libraries【外部库中不完整、无效或缺少的类型】

    在使用外部库时,您可能会发现某些库缺少或以某种方式存在无效的类型声明。 大多数情况下,这是因为库不是用 TypeScript 编写的,而且手动添加类型声明的人并没有很好地处理它。 在这些情况下,您可能需要自己定义类型声明。

    但是,很有可能已经有人为您正在使用的包添加了类型。 因此总是先检查 DefinitelyTyped 或他们的 GitHub 页面。 它们可能是最常用的类型声明文件源。

    否则,你可能需要从熟悉 TypeScript 自己关于类型声明的文档开始。

  • Sometimes type inference needs assistance【有时候类型推断需要帮助】

    TypeScript 中的类型推断非常好,但还不够完美。

    有时候你可能觉得你已经完美的声明了你的类型,但是编译器仍然告诉你这个属性不存在或者这种用法是不允许的。 在这些情况下,您可能需要通过类似“外挂”类型检查来帮助编译器,但是要小心类型强制转换和类型保护。

    使用类型强制转换或类型保护,基本上就是向编译器说明值确实是您声明的类型。

    你可能想看看 TypeScript 关于 Type Assertions 和 Type Guards 的文档。

  • Mysterious type errors【神秘的类型错误】

    类型系统给出的错误有时可能很难理解,特别是当您使用复杂类型时。

    按照经验法则,TypeScript 错误消息在消息末尾具有最有用的信息

    当你遇到长长的令人困惑的信息时,从最后开始阅读。

@types/{npm_package}

通常,现有包的类型可以在 npm 中的 @types-organization 中找到,您可以通过安装一个名为@types /-prefix 的 npm 包将相关类型添加到项目中。 例如: npm install –save-dev @types/react @types/express @types/lodash @types/jest @types/mongoose 等等。 @types/* 由 Definitely typed 维护,这是一个社区项目,其目标是将所有的类型维护在一个地方。

tsconfig

基本的 TSConfig

根据你要在其中运行代码的不同的 JavaScript 运行时环境,你可以在 github.com/tsconfig/bases 上寻找一个合适的基本配置。 你可以通过扩展这些已经处理过不同的 JavaScript 运行时环境的 tsconfig.json 文件来简化你项目中的 tsconfig.json。

举个例子,如果你的项目是基于 Node.js 12.x 写的,那么你可以使用 npm 模块:@tsconfig/node12:

1
2
3
4
5
6
7
8
{
"extends": "@tsconfig/node12/tsconfig.json",
"compilerOptions": {
"preserveConstEnums": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "**/*.spec.ts"]
}

eslint

如果我们想要阻止开发人员使用 any 类型,该怎么办? 幸运的是,除了 tsconfig.json 之外,我们还有其他方法来强制执行编码样式。 我们能做的就是用 eslint 来管理我们的代码。

让我们安装 eslint 和它的 TypeScript 扩展:

npm install –save-dev eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser

我们将 eslint 配置为 disallow explicit any, 将如下规则写入 .eslintrc:

1
2
3
4
5
6
7
8
9
10
11
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 11,
"sourceType": "module"
},
"plugins": ["@typescript-eslint"],
"rules": {
"@typescript-eslint/no-explicit-any": 2
}
}

在推荐的设置之上,我们应该尝试熟悉这一章节所需的编码风格,并将每行代码末尾的分号设置为 required。

所以我们将使用下面的 .eslintrc

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
{
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking"
],
"plugins": ["@typescript-eslint"],
"env": {
"node": true,
"es6": true
},
"rules": {
"@typescript-eslint/semi": ["error"],
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/restrict-template-expressions": "off",
"@typescript-eslint/restrict-plus-operands": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{ "argsIgnorePattern": "^_" }
],
"no-case-declarations": "off"
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
}
}

https://fullstackopen.com/zh/part9/%E7%89%88%E7%9A%84express%E5%BA%94%E7%94%A8

除非没有其他方法,否则我们永远不应该使用类型断言,因为我们总是有可能断言对象的类型不合适,从而导致严重的运行时错误。

1
2
3
4
5
6
7
8
9
10
11
12
$ npx eslint --init
√ How would you like to use ESLint? · style
√ What type of modules does your project use? · commonjs
√ Which framework does your project use? · none
√ Does your project use TypeScript? · Yes
√ Where does your code run? · browser
√ How would you like to define a style for your project? · prompt
√ What format do you want your config file to be in? · JavaScript
√ What style of indentation do you use? · 4
√ What quotes do you use for strings? · single
√ What line endings do you use? · unix
√ Do you require semicolons? · No / Yes

ts react

依旧是 npx create-react-app 但是加了一些参数,让它创建(下载)的模板使用的是 typescript

1
2
3
npx create-react-app my-app --template typescript

yarn create react-app my-app --template typescript

如果你浏览这些文件和文件夹,你会发现这个应用和你用纯 JavaScript 初始化的应用没什么不同。 基本上,唯一的区别是 .js 和我.jsx 文件现在改名为 .ts 和 .tsx 文件,它们包含一些类型注解,根文件夹还包含一个 tsconfig.json 文件。

让我们看看为我们创建的 tsconfig.json 文件。 文件中的所有内容都应该差不多正常,只是目前的配置还允许编译 JavaScript 文件,因为 allowJs 被设置为 true。 如果你需要混合使用 TypeScript 和 JavaScript (例如,如果你正在将一个 JavaScript 项目转换成 TypeScript 或者其他原因) ,那么这样做是可以的,但是我们希望我们的应用是纯粹的 TypeScript,所以让我们把这个设置改为 false。