├── .github
└── ISSUE_TEMPLATE
│ └── 提交勘误.md
├── .gitignore
├── README.md
├── assets
├── source.md
└── 书中的流程图.zip
└── data.md
/.github/ISSUE_TEMPLATE/提交勘误.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 提交勘误
3 | about: 提交本书的勘误信息
4 | title: "[页数][行数] 勘误简介"
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | 详细的勘误内容
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .history
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-design
2 |
3 | 《React 设计原理》勘误与资料与交流
4 |
5 | - [勘误请提 issue](https://github.com/BetaSu/react-design/issues)
6 |
7 | - [资料](./data.md)
8 |
9 | - [书的部分配套流程图](./assets/%E4%B9%A6%E4%B8%AD%E7%9A%84%E6%B5%81%E7%A8%8B%E5%9B%BE.zip)
10 |
11 | - 交流请加卡颂微信(kasong555),(**备注:书**),拉你进群
12 |
13 |
14 |
15 | - [配套视频课程:](https://qux.xet.tech/s/3N0RM)
16 |
17 |
18 |
--------------------------------------------------------------------------------
/assets/source.md:
--------------------------------------------------------------------------------
1 | 了解了源码的文件目录,本节我们学习两种调试源码的方式,一种是官方方式,一种是为本书读者定制的方式。
2 |
3 | ## 推荐方式
4 |
5 | 官方方式主要是为**想为 React 贡献代码的人**准备的,整体步骤比较繁琐。对于以“学习源码”为目的的读者,推荐的调试方式:[仓库地址](https://github.com/BetaSu/react18-demo)
6 |
7 | 这种方式有如下特点:
8 |
9 | 1. 调试信息清晰,`React`内的关键步骤都以**日志**的形式打印在控制台,并根据调用阶段不同会有不同颜色区分
10 |
11 | 2. 方便调试源码,采用`Vite`构建,对源码的修改会热更新
12 |
13 | 3. 丰富的示例,对多种场景提供示例
14 |
15 | ## 官方方式
16 |
17 | 构建`React`项目最常见的方式是使用`create-react-app`(后文简称`CRA`),但是`facebook/react`项目`main`分支的代码和我们使用`CRA`创建的项目`node_modules`下的`react`项目代码还是有些区别。
18 |
19 | 因为`React`的新代码都是直接提交到`main`分支,而`CRA`内的`React`使用的是稳定版的包。所以,为了调试最新的`React`代码,需遵循以下步骤:
20 |
21 | 1. 从`facebook/react`项目`main`分支拉取最新源码
22 |
23 | 2. 基于最新源码构建`react`、`scheduler`、`react-dom`三个包
24 |
25 | 3. 通过`CRA`创建测试项目,并使用步骤 2 创建的包作为项目依赖的包
26 |
27 | ### 拉取源码
28 |
29 | 拉取`facebook/react`代码:
30 |
31 | ```sh
32 | # 拉取代码
33 | git clone https://github.com/facebook/react.git
34 |
35 | # 如果拉取速度很慢,可以考虑如下2个方案:
36 |
37 | # 1. 使用cnpm代理
38 | git clone https://github.com.cnpmjs.org/facebook/react
39 |
40 | # 2. 使用码云的镜像(一天会与react同步一次)
41 | git clone https://gitee.com/mirrors/react.git
42 |
43 | ```
44 |
45 | 安装依赖
46 |
47 | ```sh
48 | # 切入到react源码所在文件夹
49 | cd react
50 |
51 | # 安装依赖
52 | yarn
53 | ```
54 |
55 | 打包`react`、`scheduler`、`react-dom`三个包为 dev 环境可以使用的`cjs`包。
56 |
57 | > 我们的步骤只包含具体做法,对每一步更详细的介绍可以参考`React`文档[源码贡献章节](https://zh-hans.reactjs.org/docs/how-to-contribute.html#development-workflow)
58 |
59 | ```sh
60 |
61 | # 执行打包命令
62 | yarn build react/index,react/jsx,react-dom/index,scheduler --type=NODE
63 |
64 | ```
65 |
66 | 现在源码目录`build/node_modules`下会生成最新代码的包。我们为`react`、`react-dom`创建`yarn link`。
67 |
68 | > 通过`yarn link`可以改变项目中依赖包的目录指向
69 |
70 | ```sh
71 | cd build/node_modules/react
72 | # 声明react指向
73 | yarn link
74 | cd build/node_modules/react-dom
75 | # 声明react-dom指向
76 | yarn link
77 | ```
78 |
79 | ### 创建项目
80 |
81 | 接下来我们通过`CRA`在其他地方创建新项目。这里我们随意起名,比如“a-react-demo”。
82 |
83 | ```sh
84 | npx create-react-app a-react-demo
85 | ```
86 |
87 | 在新项目中,将`react`与`react-dom`2 个包指向`facebook/react`下我们刚才生成的包。
88 |
89 | ```sh
90 | # 将项目内的react react-dom指向之前声明的包
91 | yarn link react react-dom
92 | ```
93 |
94 | 现在试试在`react/build/node_modules/react-dom/cjs/react-dom.development.js`中随意打印些东西。
95 |
96 | 在`a-react-demo`项目下执行`yarn start`。现在浏览器控制台已经可以打印出我们输入的内容了。
97 |
98 | 通过以上方法,我们项目中的`React`就和`main`分支代码一致了。
99 |
--------------------------------------------------------------------------------
/assets/书中的流程图.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BetaSu/react-design/909e2c05fad02f86a1cfc58e827aaf869b90feed/assets/书中的流程图.zip
--------------------------------------------------------------------------------
/data.md:
--------------------------------------------------------------------------------
1 | ## 《React 设计原理》纸质书全部示例
2 |
3 | 注:所有示例使用各框架的官方`repl`或者`codesandbox`编辑,如果无法打开请考虑科学上网
4 |
5 | ### 示例 1-1
6 |
7 | 细粒度更新实现
8 |
9 | [地址](https://codesandbox.io/s/happy-khayyam-cyfri?file=/index.html)
10 |
11 | ### 示例 1-2
12 |
13 | `Svelte`示例的基础组件
14 |
15 | [地址](https://svelte.dev/repl/9945d189204a4168b4c23890f1d92a3a?version=3.19.1)
16 |
17 | ### 示例 1-3
18 |
19 | `Svelte`示例,`count`可变化的基础组件
20 |
21 | [地址](https://svelte.dev/repl/bf22a31a0eff4875b5b3084aa2b85fc3?version=3.19.1)
22 |
23 | ### 示例 1-4
24 |
25 | `Vue3`示例,`count`可变化的基础组件
26 |
27 | [地址](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cD5cbmltcG9ydCB7IHJlZiB9IGZyb20gJ3Z1ZSdcbmxldCBjb3VudCA9IHJlZigwKVxuPC9zY3JpcHQ+XG5cbjx0ZW1wbGF0ZT5cbiAgPGgxIEBjbGljaz1cImNvdW50KytcIj57e2NvdW50fX08L2gxPlxuPC90ZW1wbGF0ZT4iLCJpbXBvcnQtbWFwLmpzb24iOiJ7XG4gIFwiaW1wb3J0c1wiOiB7XG4gICAgXCJ2dWVcIjogXCJodHRwczovL3NmYy52dWVqcy5vcmcvdnVlLnJ1bnRpbWUuZXNtLWJyb3dzZXIuanNcIlxuICB9XG59In0=)
28 |
29 | ### 示例 1-5
30 |
31 | `Vue3`模版编译
32 |
33 | [地址](https://vue-next-template-explorer.netlify.app/#%7B%22src%22%3A%22%3Cdiv%3E%5Cn%20%20%3Ch3%3Ehello%3C%2Fh3%3E%5Cn%20%20%3Cp%3E%7B%7Bname%7D%7D%3C%2Fp%3E%5Cn%3C%2Fdiv%3E%5Cn%22%2C%22options%22%3A%7B%22mode%22%3A%22module%22%2C%22filename%22%3A%22Foo.vue%22%2C%22prefixIdentifiers%22%3Afalse%2C%22hoistStatic%22%3Afalse%2C%22cacheHandlers%22%3Atrue%2C%22scopeId%22%3Anull%2C%22inline%22%3Atrue%2C%22ssrCssVars%22%3A%22%7B%20color%20%7D%22%2C%22compatConfig%22%3A%7B%22MODE%22%3A3%7D%2C%22whitespace%22%3A%22condense%22%2C%22bindingMetadata%22%3A%7B%22TestComponent%22%3A%22setup-const%22%2C%22setupRef%22%3A%22setup-ref%22%2C%22setupConst%22%3A%22setup-const%22%2C%22setupLet%22%3A%22setup-let%22%2C%22setupMaybeRef%22%3A%22setup-maybe-ref%22%2C%22setupProp%22%3A%22props%22%2C%22vMySetupDir%22%3A%22setup-const%22%7D%7D%7D)
34 |
35 | ### 示例 2-1
36 |
37 | 我们有个更新很耗时的大列表,让我们看看**同步更新**和**异步更新**时,输入框的响应速度
38 |
39 | 可以从 Demo 看到,当牺牲了列表的更新速度,`React`大幅提高了输入响应速度,使交互更自然。
40 |
41 | [地址](https://codesandbox.io/s/concurrent-3h48s?file=/src/index.js)
42 |
43 | ### 示例 2-2
44 |
45 | `count`默认为 0,每次点击按钮`count++`
46 |
47 | 列表中 3 个`li`的值分别为 1,2,3 乘以`count`的结果
48 |
49 | [地址](https://codesandbox.io/s/spring-wave-3jvv6)
50 |
51 | ### 示例 2-3
52 |
53 | `count`默认为 0,每次点击按钮`count = count + 1`,观察使用`并发特性`(useTransition)后开启的`并发更新`
54 |
55 | [地址](https://codesandbox.io/s/react-concurrent-mode-demo-forked-z7r0j?file=/src/index.js)
56 |
57 | ### 示例 2-4
58 |
59 | `count`默认为 0,每次点击按钮`count = count + 1`
60 |
61 | [地址](https://codesandbox.io/s/floral-bash-2dhnb?file=/src/App.js)
62 |
63 | ### 示例 2-5
64 |
65 | 本书推荐方式和官方方式
66 |
67 | [地址](./assets/source.md)
68 |
69 | ### 示例 3-1
70 |
71 | 运行`本书推荐方式`对应项目,使用`src/demo/RenderPhaseDemo.tsx`调试`render阶段`工作流程
72 |
73 | ### 示例 3-2
74 |
75 | 自制`ReactDOM Renderer`
76 |
77 | [地址](https://codesandbox.io/s/quiet-feather-05gvk?file=/src/index.js)
78 |
79 | ### 示例 4-1
80 |
81 | 运行`本书推荐方式`对应项目,使用`src/demo/CommitPhaseDemo.tsx`调试`commit阶段`工作流程
82 |
83 | ### 示例 4-2
84 |
85 | `Suspense`在新旧版本行为的区别
86 |
87 | 官方讨论见[Behavioral changes to Suspense in React 18 #7](https://github.com/reactwg/react-18/discussions/7)
88 |
89 | 改变示例中的`CREATE_ROOT`常量,打开控制台,审查元素,对比**是否开启并发更新**带来的区别
90 |
91 | [地址](https://codesandbox.io/s/epic-sea-omumbh?file=/src/App.js)
92 |
93 | ### 示例 4-3
94 |
95 | 运行`本书推荐方式`对应项目,使用`src/demo/ErrorCatchDemo.tsx`调试`错误处理`工作流程
96 |
97 | ### 示例 5-1
98 |
99 | `Scheduler`实现调度流程,提供两种使用方式:
100 |
101 | 1. [在线 Demo 地址](https://codesandbox.io/s/xenodochial-alex-db74g?file=/src/index.ts)
102 |
103 | 2. 运行`本书推荐方式`对应项目,使用`src/demo/MiniSchedulePhase`调试
104 |
105 | ### 示例 5-2
106 |
107 | 点击`Demo`中的`CLICK ME`,观察请求途中数字是否能继续变化
108 |
109 | [老模型下有 bug 版本的地址](https://codesandbox.io/s/usetransition-stop-reacting-passed-props-updates-forked-5e7lh)
110 | [新模型下没 bug 版本的地址](https://codesandbox.io/s/usetransition-stop-reacting-passed-props-updates-zoqm2?file=/src/index.js)
111 |
112 | ### 示例 5-3
113 |
114 | 即使在**未开启并发特性**时,触发更新后也无法立刻获取更新后的值
115 |
116 | [地址](https://codesandbox.io/s/inspiring-pond-poi2o?file=/src/App.js)
117 |
118 | ### 示例 5-4
119 |
120 | `Batched Updates`
121 |
122 | [地址](https://codesandbox.io/s/react-concurrent-mode-demo-forked-fecyne?file=/src/index.js)
123 |
124 | ### 示例 5-5
125 |
126 | 用三款框架实现`Batched Updates`,打印结果不同:
127 |
128 | [React](https://codesandbox.io/s/react-concurrent-mode-demo-forked-t8mil?file=/src/index.js)
129 |
130 | [Vue3](https://codesandbox.io/s/crazy-rosalind-wqj0c?file=/src/App.vue)
131 |
132 | [Svelte](https://svelte.dev/repl/1e4e4e44b9ca4e0ebba98ef314cfda54?version=3.44.1)
133 |
134 | ### 示例 6-1
135 |
136 | `事件系统`简易实现,提供 2 种使用方式:
137 |
138 | 1. [在线 Demo 地址](https://codesandbox.io/s/optimistic-torvalds-9ufc5?file=/src/index.js)
139 |
140 | 2. 运行`本书推荐方式`对应项目,使用`src/demo/MiniEventSystem`调试
141 |
142 | ### 示例 6-2
143 |
144 | 性能优化示例:[在线 Demo 地址](https://codesandbox.io/s/frosty-cerf-mg64o5?file=/src/App.js:46-318)
145 |
146 | ### 示例 6-3
147 |
148 | `Context`面对`bailout策略`的示例:[在线 Demo 地址](https://codesandbox.io/s/crazy-morning-5keghq?file=/src/App.js)
149 |
150 | ### 示例 6-4
151 |
152 | [应用 1](https://codesandbox.io/s/proud-wildflower-zmc02e?file=/src/App.js)
153 |
154 | [应用 1 优化后](https://codesandbox.io/s/strange-carlos-74yl2g?file=/src/App.js)
155 |
156 | [应用 2](https://codesandbox.io/s/recursing-cdn-sgozen?file=/src/App.js)
157 |
158 | [应用 2 优化后](https://codesandbox.io/s/nostalgic-chatelet-yc7n2f?file=/src/App.js)
159 |
160 | ### 示例 7-1
161 |
162 | 1. [在线 Demo 地址](https://codesandbox.io/s/naughty-matan-6fq7n6?file=/src/diff.ts)
163 |
164 | 2. 运行`本书推荐方式`对应项目,使用`src/demo/MiniDiff`调试
165 |
166 | ### 示例 8-1
167 |
168 | 1. [在线 Demo 地址](https://codesandbox.io/s/little-shape-nohj59?file=/src/index.js)
169 |
170 | 2. 运行`本书推荐方式`对应项目,使用`src/demo/SuspenseDemo/demo2.tsx`调试
171 |
172 | ### 示例 8-2
173 |
174 | 1. [在线 Demo 地址](https://codesandbox.io/s/cranky-pare-rk7e0d?file=/src/index.ts:530-533)
175 |
176 | 2. 运行`本书推荐方式`对应项目,使用`src/demo/MiniUseState/index.ts`调试
177 |
178 | ### 示例 8-3
179 |
180 | [在线 Demo 地址](https://codesandbox.io/s/admiring-violet-50dz94?file=/src/App.tsx)
181 |
182 | ### 示例 8-4
183 |
184 | [在线 Demo 地址](https://codesandbox.io/s/sandpack-project-forked-s33q3c?file=/App.js:67-70)
185 |
186 | ### 示例 8-5
187 |
188 | [在线 Demo 地址](https://codesandbox.io/s/sandpack-project-forked-7zqgmd?file=/App.js)
189 |
190 | ### 示例 8-6
191 |
192 | 1. [在线 Demo 地址](https://codesandbox.io/s/hidden-grass-w5qe54?file=/src/App.js:78-428)
193 |
194 | 2. 运行`本书推荐方式`对应项目,使用`src/demo/TransitionDemo/demo1.tsx`调试
195 |
196 | ### 示例 8-7
197 |
198 | 1. [在线 Demo 地址](https://codesandbox.io/s/immutable-glade-u0m6vv?file=/src/App.js)
199 |
200 | 2. 运行`本书推荐方式`对应项目,使用`src/demo/TransitionDemo/demo2.tsx`调试
201 |
202 | ### 示例 8-8
203 |
204 | 1. [在线 Demo 地址](https://codesandbox.io/s/youthful-antonelli-qnorue?file=/src/App.js:210-231)
205 |
206 | 2. 运行`本书推荐方式`对应项目,使用`src/demo/TransitionDemo/demo3.tsx`调试
207 |
208 | ### 示例 8-9
209 |
210 | 1. [在线 Demo 地址](https://codesandbox.io/s/angry-mountain-xstgj4?file=/src/App.js)
211 |
212 | 2. 运行`本书推荐方式`对应项目,切换分支到`use-error-boundary`调试,在[Comparing changes](https://github.com/BetaSu/react18-demo/compare/use-error-boundary)中查看改动的代码
213 |
--------------------------------------------------------------------------------