MDH 前端周刊第 47 期:React 18、Chrome 100、TypeScript String Literal、Case Police、异步代码 Lint 规则 - 图1
封面图:欧洲叠石头大赛 2019 冠军。

Hi,我是云谦,欢迎打开新一期的「MDH:前端周刊」,这是第 0047 期,发表于 2022/04/04。

本期主要内容有这些:

  • React 18
  • Chrome 100
  • TypeScript 字符串字面量类型
  • Case Police
  • 异步代码 Lint 规则
  • GitLanding
  • 20 个程序员高效贴士

React 18

https://reactjs.org/blog/2022/03/29/react-v18.html

MDH 前端周刊第 47 期:React 18、Chrome 100、TypeScript String Literal、Case Police、异步代码 Lint 规则 - 图2

React 18 真的发布了。注意,这不是演习!

React 18 带来了自动批处理、Transitions、新 Suspense、新的客户端和服务端 API、新的严格模式。

自动批处理是指将多个状态的更新,处理到单一的渲染工作中,以获得更好的性能。之前只支持 React 事件处理程序内的更新;现在支持 Promise、setTimeout、native event handlers 等。

Transitions 区分紧急更新和非紧急(过渡、Transition)更新,减少由于 rerender 引起的页面卡顿,这里有个 DEMO。通过 useTransition 或 startTransition 可切换到非紧急模式,前者可额外获取 pending 状态,后者可在非 hooks 环境下使用。从 DX 角度考虑,一个输入应该同时触发一个紧急更新和一个非紧急更新。比如下拉列表的筛选器,单击后,筛选器按钮立即响应,实际结果走 Transition。

Suspense 在上个版本就可以和 React.lazy 结合使用做 code splitting,React 18 起开始支持任意异步操作,比如代码、数据、图像等的加载。同时 Suspense 支持与 Transition 结合使用,如果 Transition 暂停,已可见的内容不会被 fallback 取代,而是做延迟的渲染,等有足够数据时才渲染。

API 变更部分。client 部分从 react-dom/client 导出,用 createRoot 和 hydrateRoot 代替之前的 render 和 hydrate,render 和 hydrate 虽然能用,但会抛警告,并且不会具备并发功能;server 部分从 react-dom/server 导出,支持 streaming Suspense。API 包含 renderToPipeableStream 和 renderToReadableStream。renderToString 继续工作,但不鼓励使用。

新的严格模式是为未来支持 Offscreen 组件准备,由于 Offscreen,所以组件需要支持多次挂载和销毁。比如大家在写 useEffect 时通常会假设他们只被挂载或销毁一次。开启新严格模式后将自动卸载并挂载每个组件。

Chrome 100

https://developer.chrome.com/en/blog/new-in-chrome-100/

MDH 前端周刊第 47 期:React 18、Chrome 100、TypeScript String Literal、Case Police、异步代码 Lint 规则 - 图3

Chrome 迎来 100 的三位数版本号,两个重要变化。

1、支持 Multi-Screen Window Placement API,可以检测是否有接多个屏幕,获取屏幕详细信息,请求开启全屏等,适用场景比如文稿演示。

  1. // 特性检测
  2. 'getScreenDetails' in window;
  3. // 获取权限
  4. const { state } = await navigator.permissions.query({ name: 'window-placement' });
  5. state === 'granted';
  6. // 是否有接入多个屏幕
  7. window.screen.isExtended;
  8. // 获取屏幕详情
  9. const screens = await window.getScreenDetails();
  10. // 请求全屏
  11. elem.requestFullscreen({ screen: screens[0] });
  12. // 监听屏幕变化
  13. screens.addEventListener('screenschange', (e) => {});

2、Chrome 100 是最后一个试验 User Agent 缩减的版本,Chrome 101 开始将逐渐正式缩减 UserAgent,减少信息量,保护用户隐私。

TypeScript 字符串字面量类型

https://lihautan.com/extract-parameters-type-from-string-literal-types-with-typescript/

MDH 前端周刊第 47 期:React 18、Chrome 100、TypeScript String Literal、Case Police、异步代码 Lint 规则 - 图4

这篇文章教你如何从字符串字面量类型一步步推导出请求参数类型,即从 /users/[userId]/[postId]/[...args] 推导出 req.params.userId 等,从而成为合格的「类型体操运动员」。

真实场景比如 react-router,其中 Route 的 render 方法也有类似实现,

  1. <Route path="/user/:username" render={(props) => {
  2. // Type 'foo' does not exist on type '{ username: string }'
  3. const { foo } = props.match.params;
  4. }} />

以下是加了简单注释的最终版本,

  1. // '[userId]' > 'userId'
  2. type IsParameter<Part> = Part extends `[${infer ParamName}]`
  3. ? ParamName
  4. : never;
  5. // 'a/b/c' > 'a' | 'b' | 'c'
  6. type FilteredParts<Path> = Path extends `${infer PartA}/${infer PartB}`
  7. ? IsParameter<PartA> | FilteredParts<PartB>
  8. : IsParameter<Path>;
  9. // ...args ? string[] : number
  10. type ParamValue<Key> = Key extends `...${infer Anything}` ? string[] : number;
  11. // ...args > args
  12. type RemovePrefixDots<Key> = Key extends `...${infer Name}` ? Name : Key;
  13. // 'a' | 'b' | 'c' > { a, b, c }
  14. type Params<Path> = {
  15. [Key in FilteredParts<Path> as RemovePrefixDots<Key>]: ParamValue<Key>;
  16. };
  17. type CallbackFn<Path> = (req: { params: Params<Path> }) => void;
  18. function get<Path extends string>(path: Path, callback: CallbackFn<Path>) {
  19. // TODO: implement
  20. }
  21. get('/docs/[chapter]/[section]/args/[...args]', (req) => {
  22. // 👍🏻,拥有类型提示了
  23. req.params.chapter;
  24. });

注意:字符串字面量类型是从 TypeScript 4.1 开始支持的。

Case Police

https://github.com/antfu/case-police

站住别动!你的大小写需要纠正下。

GitHub, not Github
TypeScript, not Typescript
macOS, not MacOS
VS Code, not Vscode

异步代码 Lint 规则

https://maximorlov.com/linting-rules-for-asynchronous-code-in-javascript/

摘录其中一些规则和错误用法。

  1. // Promise executor 不要加 async,原因是 async 内的错误会被吃掉
  2. new Promise(async (resolve, reject) => {});
  3. // 迭代 + await 是串行的,通常可以改用 Promise.all 做并行处理
  4. for (const url of urls) {
  5. const response = await fetch(url);
  6. }
  7. // Promise 构造器中不要用 return,改用 resolve,因为前者无效
  8. new Promise((resolve, reject) => {
  9. return result;
  10. });
  11. // 不要把 await 和赋值一起用,因为可能导致 Race Condition,。
  12. let totalPosts = 0;
  13. totalPosts += await getPosts(userId);
  14. // reject 里始终用 new Error 包起来,Error 会包含堆栈信息,这样就可以知道错误来自那里
  15. Promise.reject('An error occurred');

GitLanding

https://github.com/thieryw/gitlanding

MDH 前端周刊第 47 期:React 18、Chrome 100、TypeScript String Literal、Case Police、异步代码 Lint 规则 - 图5

适用于 Landing Page 的垂类 React 组件库。

20 个程序员高效贴士

https://medium.com/actiresults/20-productivity-tips-from-developers-to-developers-138f8ec6200c

虽然有些不是和高效相关,而且后面几条有凑的成分,但很多建议都是不错的。我整理了下标题如下。

1、学习 IDE
2、学习命令行
3、不要着急写代码,送给身边的好多朋友,哈哈,有时候拦都拦不住
4、避开金锤子,不要因为熟悉而用一个工具、语言、平台去解所有的问题,应该调研,然后选择最合适的
5、Push 代码前记得 Review,你会自己发现很多 Bug
6、学工作需要的知识,不追热点,因为你不可能精通所有事
7、搞搞业余项目,可以加速学习,培养创造力,把社区新技术全部用进去
8、写可读性好的代码,而不是复杂、花哨的代码,以后你会感谢自己的
9、记录时间,尤其是你觉得效率不够高的时候
10、评估工作时加 Buffer,别把自己搞太累,同时增加项目风险
11、培养软技能,只会写代码是不够的
12、尽可能多地自动化,写博客前先写个博客系统不是丢脸的事
13、长期主义,眼光放远点,有些近期可能拖累你的工具,长期可能是有益的
14、在办公用品上舍得花钱,比如降噪耳机、站立式办公桌、人体工学椅
15、知道自己什么时候累了,累了就休息,疲劳驾驶可能给未来留坑
16、写日记
17、适时休息,长时间工作效率反而更低
18、记录日常成就
19、别害怕犯错
20、不要跳过文档

发布

以下是上周社区的重要发布。

周刊一锅端

小结

以上就是本期我的分享。如果需要文内资讯的链接,请点击「查看原文」进入语雀查看。持续更新不易,如果你喜欢本周刊,请转发给你的朋友,告诉他们到这里来订阅,这是对我最大的帮助。下期见!

MDH,让开发者有笑容 :)