├── .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 | --------------------------------------------------------------------------------