MDH 前端周刊第 70 期:React Router 6.4、初高级程序员、2022 JavaScript、单文件 Deno、函数组合、二维码原理 - 图1
封面图:agathadepine @ unsplash。

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

本周有这些内容想和你分享:

  • React Router 6.4
  • 初级程序员 vs. 高级程序员
  • 2022 JavaScirpt 新特性
  • 单文件 Deno 网站
  • 函数组合
  • 二维码原理

一周新闻

  • preact 发布 10.11,新增 useId Hook,对齐 React 18
  • React Router 发布 6.4,大量新功能,包括数据加载/突变/重新验证、错误/中断/竞争条件处理以及支持 Suspense 的加载/骨架 UI 等
  • dashi 发布 jotai-signal,类 preact signal,但实现方式不同,jotai-signal 底层基于 experiment_use
  • npm 发布 9-pre.0,改进 workspace 的 semver 匹配规则,删除 bin、set-script、birthday 等命令
  • swc 发布 1.3,swc minify 功能已稳定
  • lightningcss 发布 1.15,inline source map,新增 preserveImports 和 transformStyleAttribute 配置项

React Router 6.4

https://github.com/remix-run/react-router/releases/tag/react-router-dom%406.4.0

MDH 前端周刊第 70 期:React Router 6.4、初高级程序员、2022 JavaScript、单文件 Deno、函数组合、二维码原理 - 图2

React Router 发布 6.4,大量新功能,包括数据加载/突变/重新验证、错误/中断/竞争条件处理以及支持 Suspense 的加载/骨架 UI 等。

1、路由创建方式变更,之前用 BrowserRouter + Routes,现在改用 createBrowserRouter 创建路由和 RouterProvider 渲染路由。

  1. <RouterProvider router={createBrowserRouter([
  2. { path: '/', element: <Root /> }
  3. ])} />

2、路由级的数据流,基于 loader + action + Form,在路由配置中声明 loader 和 action,然后如下使用即可。

处理数据加载。

  1. // 声明数据
  2. export async function loader() {}
  3. // 使用数据
  4. useLoaderData();

处理数据提交。

  1. // 使用定制表单元素
  2. <Form />
  3. // 处理表单提交
  4. export async function action() {}

3、延迟数据加载方案,基于 defer + useAsyncValue/Await。由于考虑到 CLS(Content Layout Shift),默认没有做延迟数据加载,开发者可以手动开启。用哪种方式其实是需要权衡的,各有利弊。

  1. // 1、loader 里延迟返回
  2. export async function loader() {
  3. return defer({ count: 0 });
  4. }
  5. // 2、渲染时用 Await 延迟渲染,不阻塞 Suspense 的瀑布流
  6. <Await resolve={data.count} errorElement={<p>error load count</p>}>
  7. {(count) => <p>{count}</p>}
  8. </Await>

4、ScrollRestoration 可以模拟浏览器在加载器完成后位置变化时的滚动恢复,以确保滚动位置恢复到正确的位置,甚至跨域。

  1. <ScrollRestoration />

初级程序员 vs. 高级程序员

https://codewithstyle.info/software-vs-systems/

MDH 前端周刊第 70 期:React Router 6.4、初高级程序员、2022 JavaScript、单文件 Deno、函数组合、二维码原理 - 图3

要分别初级程序员和高级程序员,其中一点是看他们关注的是「软件」还是「系统」。

初级工程师关心编写软件的问题。 他们重视代码质量,采用最佳实践,努力采用最先进的技术。他们在学习新技术方面投入了大量时间。对他们来说,最终的目标是创建优雅的、可执行的、可维护的软件。

高级工程师关心的是建立系统。 对他们来说,创建软件只是其中的一个步骤。首先,他们会质疑这个软件是否需要被建造。他们会问它能解决什么问题,为什么要解决这些问题。他们询问谁将会使用这个软件,在什么规模上使用。他们考虑软件将在哪里运行,以及他们将如何监测它是否正常工作。他们还决定如何衡量该软件是否真正解决了它应该解决的问题。

2022 JavaScirpt 新特性

https://olivernguyen.io/s/js2022/

MDH 前端周刊第 70 期:React Router 6.4、初高级程序员、2022 JavaScript、单文件 Deno、函数组合、二维码原理 - 图4

1、私有属性,class 里以 # 开头的即私有属性或方法。

  1. class Foo {
  2. name: 'foo';
  3. #count = 0;
  4. inc() { this.#count += 1 }
  5. }

2、用 in 检测私有属性。

  1. class Foo {
  2. #count = 0;
  3. static isFoo(obj) {
  4. return #count in obj;
  5. }
  6. }

3、数组和字符串的 at 方法,相比用 [] 访问,at 可以用负数。

  1. [1,2,3].at(-1);
  2. '123'.at(-1);

在 at 之前我们通常会用 .slice(index)[0] 访问可能存在负数的 index,但性能看起来就不够好。

4、数组的 findLast 和 findLastIndex 方法用于从后往前找。

  1. [1,2,3,4].findLast(v => v%2 === 1);
  2. [1,2,3,4].findLastIndex(v => v%2 === 1);

5、用 hasOwn 代替 hasOwnProperty。

  1. - const hasOwnProperty = Object.prototype.hasOwnProperty;
  2. - hasOwnProperty.call(object, 'foo');
  3. + Object.hasOwn(object, 'foo');

6、error 有个新属性叫 cause,用于把 error 传给新的 error。

  1. fetch('/foo').catch(e => {
  2. throw new Error('failed to fetch', { cause: e });
  3. });

单文件 Deno 网站

https://deno.com/blog/a-whole-website-in-a-single-js-file-continued

MDH 前端周刊第 70 期:React Router 6.4、初高级程序员、2022 JavaScript、单文件 Deno、函数组合、二维码原理 - 图5

Deno 更新了一篇文档,介绍如何在一个文件中完成网站。并且功能齐全,包含动态 API、动态渲染、动态路由、表单等。

函数组合

https://medium.com/javascript-scene/why-every-react-developer-should-learn-function-composition-23f41d4db3b1

MDH 前端周刊第 70 期:React Router 6.4、初高级程序员、2022 JavaScript、单文件 Deno、函数组合、二维码原理 - 图6

函数组合有很多场景,这篇文章介绍了如何把他用在 React 项目中,换一种代码组织方式,让代码更简洁、优雅和可扩展。

假如你有一个项目,项目里有这样的需求,1)检查用户登录状态,2)特性检测按需渲染,3)埋点日志需求,4)layout 渲染。你可能会这么写。

  1. const App = () => {
  2. useEffect(() => { if (!user.isLogin) signIn() }, []);
  3. useEffect(() => { log({ pageName, uid }) }, []);
  4. return user.isAdmin ? <AdminComponent />
  5. : <>{ features.includes('foo') && <Foo /> }<Conent /></>;
  6. }

这里的 问题是,如果有多个组件都需要类似的逻辑,你可能就要复制粘贴了。解是用 Provider + HOC + Composition + Currying。

  1. const App = withProviders({ showFooter: false })(() => {
  2. return <Content />;
  3. });

withProviders 如下。

  1. const withProviders = (options) =>
  2. compose(
  3. withUser,
  4. withFeatures,
  5. withLogger,
  6. withLayout(options)
  7. );

withLogger 如下。

  1. const withLogger = (WrappedComponent) => {
  2. return (props) => {
  3. useEffect(() => { log({ pageName, uid }) }, []);
  4. return <WrappedComponent {...props} />;
  5. };
  6. }

二维码原理

https://typefully.com/DanHollick/qr-codes-T7tLlNi

MDH 前端周刊第 70 期:React Router 6.4、初高级程序员、2022 JavaScript、单文件 Deno、函数组合、二维码原理 - 图7

这篇文章介绍了二维码的构成。

1、Finder pattern 用于定位二维码
2、Alignment pattern 用于决定二维码的方向,即哪个方向是朝上的
3、Timing pattern 用于决定二维码的大小
4、Format info 保存二维码的格式信息,包括错误纠正等级、掩码类型、错误纠正格式
5、Data 是二维码的字符数据,从右边开始
6、Error correction 是 Data 用剩下的空间,用于存储纠正信息

周刊一锅端

小结

如果你喜欢 MDH 前端周刊,请转发给你的朋友,告诉他们到这里来订阅,这是对我最大的帮助。下期见!
MDH,让开发者有笑容 :)