<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>博客</title><description>No description</description><link>https://www.asherxh.top/</link><language>zh_CN</language><item><title>docker.md</title><link>https://www.asherxh.top/posts/docker/</link><guid isPermaLink="true">https://www.asherxh.top/posts/docker/</guid><pubDate>Thu, 02 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;docker原理&lt;/h3&gt;
&lt;h3&gt;1. 什么是docker&lt;/h3&gt;
&lt;p&gt;Docker是一种容器化平台，它将应用程序及其依赖项打包成轻量级、可移植的容器。与虚拟机不同，容器共享宿主机内核，启动速度快、资源占用低。Docker通过镜像实现应用的一致性交付，让开发、测试、生产环境保持一致，解决了&quot;在我机器上能运行&quot;的难题，大幅提升了部署效率和环境一致性。&lt;/p&gt;
&lt;h3&gt;2. 镜像与容器的类比&lt;/h3&gt;
&lt;h4&gt;📦 镜像（Image）= 蛋糕模具&lt;/h4&gt;
&lt;p&gt;镜像就像是一个蛋糕模具——它包含了制作蛋糕所需的所有配方（代码、运行环境、依赖库、配置文件等），是一个静态的、只读的模板。一次制作，多次使用，不会自己&quot;动&quot;，只是一个蓝图，体积小、可复制、可分享。&lt;/p&gt;
&lt;h4&gt;🥧 容器（Container）= 烤好的蛋糕&lt;/h4&gt;
&lt;p&gt;容器是基于镜像&quot;烤&quot;出来的实际蛋糕——它是镜像的运行时实例，拥有独立的文件系统、进程空间和网络配置。可以启动、停止、暂停、删除，运行时状态是动态变化的，多个容器可以同时运行，互不干扰。&lt;/p&gt;
&lt;h4&gt;⚖️ 核心区别&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;镜像 (Image)&lt;/th&gt;
&lt;th&gt;容器 (Container)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;状态&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;静态、只读&lt;/td&gt;
&lt;td&gt;动态、可读写&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;作用&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;定义&quot;做什么&quot;&lt;/td&gt;
&lt;td&gt;实际&quot;运行什么&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;生命周期&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;持久保存&lt;/td&gt;
&lt;td&gt;随用随创建/销毁&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;类比&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;蛋糕模具&lt;/td&gt;
&lt;td&gt;烤好的蛋糕&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;🎯 一句话总结&lt;/h4&gt;
&lt;p&gt;镜像就是&quot;说明书&quot;，容器就是&quot;按说明书生产出来的产品&quot;。一个镜像可以启动成百上千个容器，就像一个模具可以烤出无数个蛋糕一样！&lt;/p&gt;
&lt;h3&gt;3. Dockerfile与多阶段构建&lt;/h3&gt;
&lt;p&gt;Dockerfile是构建镜像的脚本文件，通过一系列指令（FROM、RUN、COPY、CMD等）定义镜像的构建过程。多阶段构建是Docker 17.05引入的特性，允许在一个Dockerfile中使用多个FROM指令，每个阶段可以使用不同的基础镜像。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;优势：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;减小镜像体积&lt;/strong&gt;：只保留最终运行所需的文件，丢弃构建过程中的临时文件&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提高安全性&lt;/strong&gt;：构建环境和运行环境分离，避免将敏感信息带入生产镜像&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;示例：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 构建阶段
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# 运行阶段
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD [&quot;nginx&quot;, &quot;-g&quot;, &quot;daemon off;&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. Docker Compose编排&lt;/h3&gt;
&lt;p&gt;Docker Compose是用于定义和运行多容器Docker应用的工具。通过一个YAML文件（docker-compose.yml）配置应用的服务、网络、卷等，使用一条命令即可启动整个应用栈。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心概念：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Service&lt;/strong&gt;：定义一个容器服务&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Network&lt;/strong&gt;：容器间的网络通信&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Volume&lt;/strong&gt;：数据持久化存储&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;示例（docker-compose.yml）：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;version: &apos;3.8&apos;
services:
  web:
    build: .
    ports:
      - &quot;80:80&quot;
    depends_on:
      - db
  db:
    image: mysql:8
    volumes:
      - mysql-data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: password
volumes:
  mysql-data:
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5. 数据卷与持久化&lt;/h3&gt;
&lt;p&gt;容器的文件系统是临时的，容器删除后数据会丢失。数据卷（Volume）是Docker提供的持久化存储方案。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;三种数据持久化方式：&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方式&lt;/th&gt;
&lt;th&gt;特点&lt;/th&gt;
&lt;th&gt;适用场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Named Volume&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Docker管理，存储在宿主机特定目录&lt;/td&gt;
&lt;td&gt;数据库、配置文件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bind Mount&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;挂载宿主机任意目录&lt;/td&gt;
&lt;td&gt;开发时代码热更新&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;tmpfs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;内存中的临时文件系统&lt;/td&gt;
&lt;td&gt;敏感数据、临时缓存&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;数据卷优势：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据独立于容器生命周期&lt;/li&gt;
&lt;li&gt;便于容器间共享数据&lt;/li&gt;
&lt;li&gt;支持备份、恢复和迁移&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;6. Docker网络模式&lt;/h3&gt;
&lt;p&gt;Docker提供多种网络模式，满足不同场景的网络需求：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;模式&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;bridge&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;默认模式，容器间通过虚拟网桥通信&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;host&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;共享宿主机网络栈，性能最高&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;none&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;完全隔离，无网络连接&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;container&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;共享另一个容器的网络命名空间&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;自定义网络&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;用户创建的隔离网络，推荐用于多容器通信&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;最佳实践：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用自定义网络隔离不同应用&lt;/li&gt;
&lt;li&gt;通过服务名进行容器间通信&lt;/li&gt;
&lt;li&gt;避免使用host网络模式&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>nginx.md</title><link>https://www.asherxh.top/posts/nginx/</link><guid isPermaLink="true">https://www.asherxh.top/posts/nginx/</guid><pubDate>Tue, 30 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;nginx原理&lt;/h3&gt;
&lt;h3&gt;1. 什么是Nginx&lt;/h3&gt;
&lt;p&gt;Nginx是一款高性能的HTTP和反向代理服务器，由俄罗斯工程师Igor Sysoev开发。它以轻量级、高并发、低内存消耗著称，采用事件驱动模型处理请求，能够在单机上轻松应对数万级并发连接。Nginx不仅可以作为Web服务器直接提供静态资源服务，还广泛用于反向代理、负载均衡、缓存加速等场景，是现代Web架构中不可或缺的核心组件。&lt;/p&gt;
&lt;h3&gt;2. Nginx的核心类比&lt;/h3&gt;
&lt;h4&gt;🏨 Nginx = 五星级酒店前台&lt;/h4&gt;
&lt;p&gt;把Nginx想象成一家五星级酒店的前台接待员，这个类比能帮你理解它的核心功能：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;客人进门（客户端请求）：&lt;/strong&gt;
所有客人（HTTP请求）都必须经过前台（Nginx），前台不会直接提供客房服务，而是负责引导和分配。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;询问需求（请求解析）：&lt;/strong&gt;
前台会询问客人的需求——是要办理入住（静态资源请求）、用餐（API请求），还是会议服务（WebSocket连接）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;分配房间（请求路由）：&lt;/strong&gt;
根据需求，前台将客人引导到对应的楼层和房间：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;静态资源 → 直接从前台旁边的储物架拿取（本地文件）&lt;/li&gt;
&lt;li&gt;API请求 → 转交给客房服务员（后端应用服务器）&lt;/li&gt;
&lt;li&gt;负载均衡 → 根据房间占用情况分配（轮询、权重等策略）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;处理突发情况（高并发）：&lt;/strong&gt;
即使同时来了大量客人，前台也能高效处理，因为它采用&quot;非阻塞&quot;方式——不需要每个客人都单独占用一个前台人员。&lt;/p&gt;
&lt;h4&gt;⚖️ 核心区别：正向代理 vs 反向代理&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;代理类型&lt;/th&gt;
&lt;th&gt;类比场景&lt;/th&gt;
&lt;th&gt;作用对象&lt;/th&gt;
&lt;th&gt;典型用途&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;正向代理&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;旅行社帮游客订机票&lt;/td&gt;
&lt;td&gt;代表客户端&lt;/td&gt;
&lt;td&gt;翻墙、缓存、隐藏客户端IP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;反向代理&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;酒店前台代表酒店&lt;/td&gt;
&lt;td&gt;代表服务端&lt;/td&gt;
&lt;td&gt;负载均衡、安全防护、SSL终止&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;3. 负载均衡策略&lt;/h3&gt;
&lt;p&gt;Nginx支持多种负载均衡算法，适用于不同场景：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;算法&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;th&gt;适用场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;round_robin&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;默认轮询，依次分配&lt;/td&gt;
&lt;td&gt;后端服务器性能相近&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;least_conn&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;分配给连接数最少的服务器&lt;/td&gt;
&lt;td&gt;请求处理时间差异大&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ip_hash&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;根据客户端IP哈希分配&lt;/td&gt;
&lt;td&gt;需要会话保持&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;weight&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;按权重分配，权重越高分配越多&lt;/td&gt;
&lt;td&gt;服务器性能差异大&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;配置示例：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;upstream backend {
    server 192.168.1.10 weight=3;
    server 192.168.1.11 weight=2;
    server 192.168.1.12 backup;
}

server {
    location /api/ {
        proxy_pass http://backend;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. Nginx配置文件结构&lt;/h3&gt;
&lt;p&gt;Nginx配置文件（nginx.conf）采用模块化结构，主要包含以下层级：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;main        # 全局配置（user、worker_processes、error_log）
├── events  # 事件驱动配置（worker_connections、use epoll）
└── http    # HTTP协议配置
    ├── upstream  # 上游服务器配置（负载均衡）
    └── server    # 虚拟主机配置
        └── location  # 路径匹配与处理规则
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;核心指令说明：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;worker_processes&lt;/code&gt;: 工作进程数，通常设为CPU核心数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;worker_connections&lt;/code&gt;: 每个进程最大连接数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;proxy_pass&lt;/code&gt;: 反向代理到上游服务器&lt;/li&gt;
&lt;li&gt;&lt;code&gt;root&lt;/code&gt;: 设置静态文件根目录&lt;/li&gt;
&lt;li&gt;&lt;code&gt;try_files&lt;/code&gt;: 尝试按顺序查找文件&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;5. 性能优化技巧&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1. 调整工作进程和连接数：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;worker_processes auto;
worker_connections 10240;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2. 开启gzip压缩：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gzip on;
gzip_types text/plain text/css application/json;
gzip_min_length 1000;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;3. 配置缓存：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;location ~* \.(jpg|png|css|js)$ {
    expires 7d;
    add_header Cache-Control &quot;public, no-transform&quot;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;4. 启用sendfile和tcp_nopush：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sendfile on;
tcp_nopush on;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;6. 高可用方案&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;主备模式（Keepalived + Nginx）：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;两台Nginx服务器，一台主服务器提供服务，一台备用&lt;/li&gt;
&lt;li&gt;Keepalived通过VRRP协议实现自动故障切换&lt;/li&gt;
&lt;li&gt;当主服务器宕机时，备用服务器自动接管VIP&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;集群模式（Nginx + Consul）：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;多台Nginx组成集群，通过Consul实现服务发现&lt;/li&gt;
&lt;li&gt;动态感知后端服务器状态，自动剔除故障节点&lt;/li&gt;
&lt;li&gt;支持水平扩展，应对更高并发&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>React 18 并发特性：让你的应用像奶茶店一样高效运转</title><link>https://www.asherxh.top/posts/react-concurrency-deep-dive/</link><guid isPermaLink="true">https://www.asherxh.top/posts/react-concurrency-deep-dive/</guid><pubDate>Wed, 24 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;React 18 并发特性：让你的应用像奶茶店一样高效运转&lt;/h1&gt;
&lt;p&gt;想象一下：你去奶茶店点单，店员告诉你要等20分钟。你可能会想：&quot;这么久？那我去隔壁买个面包再来？&quot;&lt;/p&gt;
&lt;p&gt;但如果奶茶店采用了&quot;并发处理&quot;的方式呢？店员先给你点单，然后在做奶茶的同时，也接待其他顾客。等你买完面包回来，奶茶刚好做好。这样是不是效率高多了？&lt;/p&gt;
&lt;p&gt;React 18引入的并发特性，就相当于给你的应用装上了这样一个智能的&quot;奶茶店系统&quot;。&lt;/p&gt;
&lt;h2&gt;什么是React并发？&lt;/h2&gt;
&lt;p&gt;简单来说，并发就是React可以&quot;同时&quot;处理多个任务，但这里的&quot;同时&quot;不是真的并行执行（毕竟JavaScript是单线程的），而是一种&quot;交替处理&quot;的艺术。&lt;/p&gt;
&lt;p&gt;就像奶茶店的店员，虽然一次只能做一杯奶茶，但他可以在等待奶茶煮好的间隙，去接待其他顾客。&lt;/p&gt;
&lt;h2&gt;并发特性的核心：可中断渲染&lt;/h2&gt;
&lt;p&gt;在React 18之前，一旦React开始渲染，它就会&quot;霸占&quot;主线程，直到整个组件树渲染完成。这就像奶茶店的店员一旦开始做你的奶茶，就拒绝接待其他所有顾客，直到你的奶茶做好为止——这显然效率很低。&lt;/p&gt;
&lt;p&gt;而React 18的并发特性允许渲染过程被&quot;中断&quot;。当有更重要的任务（比如用户点击按钮）进来时，React可以暂停当前的渲染，先处理用户的操作，然后再回来继续渲染。&lt;/p&gt;
&lt;h2&gt;实际应用：Suspense 和 lazy 加载&lt;/h2&gt;
&lt;p&gt;让我们看一个生活化的例子：你打开一个社交媒体应用，首先看到的是好友列表，然后是动态流。&lt;/p&gt;
&lt;p&gt;在React 18之前，如果动态流加载很慢，整个页面都会卡住，直到动态流加载完成。&lt;/p&gt;
&lt;p&gt;但使用React 18的Suspense和lazy加载，我们可以这样处理：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import React, { Suspense, lazy } from &apos;react&apos;;

// 懒加载动态流组件
const Feed = lazy(() =&amp;gt; import(&apos;./Feed&apos;));

function SocialApp() {
  return (
    &amp;lt;div className=&quot;social-app&quot;&amp;gt;
      &amp;lt;h1&amp;gt;我的社交应用&amp;lt;/h1&amp;gt;
      {/* 好友列表立即渲染 */}
      &amp;lt;FriendsList /&amp;gt;
      
      {/* 动态流加载时显示占位符 */}
      &amp;lt;Suspense fallback={&amp;lt;div className=&quot;loading&quot;&amp;gt;正在加载动态流...&amp;lt;/div&amp;gt;}&amp;gt;
        &amp;lt;Feed /&amp;gt;
      &amp;lt;/Suspense&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这样，用户可以先看到好友列表并与之交互，而不必等待整个页面加载完成。就像你去餐厅吃饭，先上凉菜，热菜慢慢上——总比饿着肚子等所有菜一起上要舒服得多。&lt;/p&gt;
&lt;h2&gt;并发更新：优先级管理&lt;/h2&gt;
&lt;p&gt;React 18还引入了&quot;优先级管理&quot;的概念。不同的任务有不同的优先级：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用户交互（点击、输入）：高优先级&lt;/li&gt;
&lt;li&gt;数据加载：中优先级&lt;/li&gt;
&lt;li&gt;后台更新：低优先级&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;就像奶茶店会优先处理&quot;马上要赶火车&quot;的顾客，React也会优先处理用户的即时操作，确保应用响应迅速。&lt;/p&gt;
&lt;h2&gt;useTransition：让缓慢的操作&quot;优雅降级&quot;&lt;/h2&gt;
&lt;p&gt;有时候，我们需要执行一个比较耗时的操作，但又不想阻塞用户界面。这时候就可以使用&lt;code&gt;useTransition&lt;/code&gt;钩子：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { useState, useTransition } from &apos;react&apos;;

function SearchBox() {
  const [query, setQuery] = useState(&apos;&apos;);
  const [searchResults, setSearchResults] = useState([]);
  const [isPending, startTransition] = useTransition();

  function handleSearch(e) {
    const newQuery = e.target.value;
    setQuery(newQuery);
    
    // 使用transition包装耗时操作
    startTransition(() =&amp;gt; {
      // 模拟搜索API调用
      const results = performSearch(newQuery);
      setSearchResults(results);
    });
  }

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;input
        type=&quot;text&quot;
        value={query}
        onChange={handleSearch}
        placeholder=&quot;搜索...&quot;
      /&amp;gt;
      {isPending &amp;amp;&amp;amp; &amp;lt;div&amp;gt;正在搜索...&amp;lt;/div&amp;gt;}
      &amp;lt;ul&amp;gt;
        {searchResults.map(result =&amp;gt; (
          &amp;lt;li key={result.id}&amp;gt;{result.title}&amp;lt;/li&amp;gt;
        ))}
      &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用&lt;code&gt;useTransition&lt;/code&gt;后，当用户输入时，输入框会立即更新（高优先级），而搜索结果的更新会被标记为低优先级，不会阻塞用户的输入体验。&lt;/p&gt;
&lt;p&gt;就像你在奶茶店点了一杯复杂的奶茶，店员会先给你一个号码牌（立即响应），然后慢慢做奶茶（后台处理）——这样你就不会感觉被忽视了。&lt;/p&gt;
&lt;h2&gt;useDeferredValue：延迟更新非关键UI&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;useDeferredValue&lt;/code&gt;是另一个并发钩子，它可以延迟更新UI的一部分，直到其他更重要的更新完成：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { useState, useDeferredValue } from &apos;react&apos;;

function SearchResults({ query }) {
  // 延迟查询的更新
  const deferredQuery = useDeferredValue(query);
  
  // 只有当deferredQuery稳定后才重新计算结果
  const results = useMemo(() =&amp;gt; {
    return searchItems(deferredQuery);
  }, [deferredQuery]);

  return (
    &amp;lt;ul&amp;gt;
      {results.map(item =&amp;gt; (
        &amp;lt;li key={item.id}&amp;gt;{item.name}&amp;lt;/li&amp;gt;
      ))}
    &amp;lt;/ul&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就像你在超市购物，收银员会先扫描你的商品（关键任务），然后再慢慢整理小票和找零（非关键任务）——这样可以让你更快地完成主要流程。&lt;/p&gt;
&lt;h2&gt;并发特性的未来：Server Components&lt;/h2&gt;
&lt;p&gt;React团队还在开发Server Components（服务端组件），这是并发特性的一个重要延伸。&lt;/p&gt;
&lt;p&gt;简单来说，Server Components允许组件在服务器上渲染，然后将结果发送到客户端。这可以减少客户端的JavaScript体积，提高应用性能。&lt;/p&gt;
&lt;p&gt;想象一下：你去餐厅吃饭，餐厅已经提前准备好了大部分食材（服务端渲染），厨师只需要在你点单后快速烹饪（客户端交互）——这样可以大大缩短等待时间。&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;React 18的并发特性不是一个单一的API，而是一整套让应用更高效、更响应的机制。它让React应用可以像一个管理良好的奶茶店一样：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;高效处理多个任务&lt;/li&gt;
&lt;li&gt;优先响应重要请求&lt;/li&gt;
&lt;li&gt;让用户感觉流畅、不卡顿&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;虽然并发特性听起来很高级，但它的核心思想其实很简单：&lt;strong&gt;让应用更懂用户，更在乎用户的体验&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;所以，下次当你使用React 18开发应用时，不妨想想那个高效的奶茶店——你的用户会感谢你为他们提供的流畅体验。&lt;/p&gt;
</content:encoded></item><item><title>React并发模式：让应用像手机APP一样流畅</title><link>https://www.asherxh.top/posts/react-concurrent-mode-deep-dive/</link><guid isPermaLink="true">https://www.asherxh.top/posts/react-concurrent-mode-deep-dive/</guid><pubDate>Wed, 25 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;React并发模式：让应用像手机APP一样流畅&lt;/h1&gt;
&lt;p&gt;你有没有遇到过这种情况？当你在手机上刷朋友圈时，即使图片还在加载，你依然可以顺畅地上下滑动；或者在使用高德地图时，即使路线还在计算，你也能继续缩放查看地图。这种「不卡」的体验，其实就是并发处理的功劳。&lt;/p&gt;
&lt;p&gt;而React 18推出的&lt;strong&gt;并发模式&lt;/strong&gt;（Concurrent Mode），就是要把这种手机APP级别的流畅体验，带到Web应用中。&lt;/p&gt;
&lt;h2&gt;什么是并发模式？&lt;/h2&gt;
&lt;p&gt;简单来说，并发模式就是让React能够「一心多用」。在传统模式下，React处理渲染任务时是「一根筋」的——一旦开始渲染，就必须完成，中间不能被打断。如果遇到复杂的计算或大量数据渲染，页面就会「卡」住，用户的点击、滚动等操作都会没有响应。&lt;/p&gt;
&lt;p&gt;而并发模式下，React可以&lt;strong&gt;中断渲染&lt;/strong&gt;，优先处理用户的交互操作，等用户操作完成后，再继续之前的渲染任务。就像你在写代码时，突然收到一条微信消息，你可以先回消息，然后再继续写代码一样。&lt;/p&gt;
&lt;h2&gt;Suspense：让异步加载更优雅&lt;/h2&gt;
&lt;p&gt;说到并发模式，就不得不提Suspense。这个功能可以让我们&lt;strong&gt;以同步的方式写异步代码&lt;/strong&gt;，听起来是不是很神奇？&lt;/p&gt;
&lt;p&gt;比如，以前我们加载图片或数据时，通常需要这样写：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 传统的异步加载方式
function ImageComponent({ src }) {
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);
  
  useEffect(() =&amp;gt; {
    const img = new Image();
    img.onload = () =&amp;gt; setIsLoading(false);
    img.onerror = () =&amp;gt; setError(&apos;加载失败&apos;);
    img.src = src;
  }, [src]);
  
  if (isLoading) return &amp;lt;div&amp;gt;加载中...&amp;lt;/div&amp;gt;;
  if (error) return &amp;lt;div&amp;gt;{error}&amp;lt;/div&amp;gt;;
  
  return &amp;lt;img src={src} alt=&quot;&quot; /&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;代码看起来很繁琐，要处理加载中、错误等各种状态。而使用Suspense后，代码可以变得非常简洁：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 使用Suspense的异步加载方式
const LazyImage = lazy(() =&amp;gt; import(&apos;./ImageComponent&apos;));

function App() {
  return (
    &amp;lt;Suspense fallback={&amp;lt;div&amp;gt;加载中...&amp;lt;/div&amp;gt;}&amp;gt;
      &amp;lt;LazyImage src=&quot;https://example.com/large-image.jpg&quot; /&amp;gt;
    &amp;lt;/Suspense&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Suspense帮我们处理了所有的加载状态，我们只需要关注核心逻辑即可。&lt;/p&gt;
&lt;h2&gt;并发模式的实际应用场景&lt;/h2&gt;
&lt;h3&gt;1. 流畅的列表滚动&lt;/h3&gt;
&lt;p&gt;想象一下，你有一个包含上千条数据的列表，当用户快速滚动时，如果每条数据都需要复杂的计算和渲染，传统模式下页面肯定会卡顿。&lt;/p&gt;
&lt;p&gt;而在并发模式下，React可以根据用户的滚动速度，&lt;strong&gt;动态调整渲染优先级&lt;/strong&gt;。当用户快速滚动时，React会先渲染可见区域的内容，跳过不可见区域；当用户停止滚动时，再渲染剩余的内容。&lt;/p&gt;
&lt;h3&gt;2. 智能的表单输入&lt;/h3&gt;
&lt;p&gt;在复杂的表单中，我们经常需要实时验证用户输入。传统模式下，如果验证逻辑很复杂，用户在输入时可能会感到卡顿。&lt;/p&gt;
&lt;p&gt;并发模式下，React可以将验证逻辑的优先级调低，确保用户的输入操作始终是流畅的。即使用户快速输入，界面也能及时响应，验证结果会在后台慢慢计算并更新。&lt;/p&gt;
&lt;h3&gt;3. 优雅的页面切换&lt;/h3&gt;
&lt;p&gt;使用React Router时，传统模式下页面切换是「瞬间替换」的。如果新页面需要加载大量数据，用户会看到一个空白页或加载动画。&lt;/p&gt;
&lt;p&gt;而在并发模式下，我们可以实现「无缝切换」：旧页面保持显示，新页面在后台加载数据和渲染，加载完成后再平滑过渡。&lt;/p&gt;
&lt;h2&gt;如何开启并发模式？&lt;/h2&gt;
&lt;p&gt;在React 18中，并发模式已经成为默认选项。我们只需要使用&lt;code&gt;createRoot&lt;/code&gt; API来替代原来的&lt;code&gt;ReactDOM.render&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 传统模式
import ReactDOM from &apos;react-dom&apos;;
ReactDOM.render(&amp;lt;App /&amp;gt;, document.getElementById(&apos;root&apos;));

// 并发模式
import { createRoot } from &apos;react-dom/client&apos;;
const root = createRoot(document.getElementById(&apos;root&apos;));
root.render(&amp;lt;App /&amp;gt;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;就是这么简单！开启并发模式后，React会自动为我们处理很多性能优化。&lt;/p&gt;
&lt;h2&gt;注意事项&lt;/h2&gt;
&lt;p&gt;虽然并发模式很强大，但也有一些需要注意的地方：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;副作用管理&lt;/strong&gt;：在并发模式下，组件可能会被多次渲染或中断，所以要确保副作用（如API调用、DOM操作）的逻辑是「幂等」的，即多次执行不会产生不同的结果。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;第三方库兼容性&lt;/strong&gt;：有些旧的React库可能还没有适配并发模式，使用时需要注意测试。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;性能测试&lt;/strong&gt;：并发模式不是万能的，还是需要结合性能分析工具（如React DevTools的Profiler）来找出真正的瓶颈。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;React并发模式就像是给我们的Web应用装了一个「智能调度器」，它能根据用户的操作，动态调整渲染优先级，让应用变得更加流畅和响应迅速。&lt;/p&gt;
&lt;p&gt;虽然并发模式的概念听起来有点复杂，但使用起来其实很简单——大多数情况下，我们只需要把&lt;code&gt;ReactDOM.render&lt;/code&gt;换成&lt;code&gt;createRoot&lt;/code&gt;，就能享受到并发模式带来的好处。&lt;/p&gt;
&lt;p&gt;如果你还没有尝试过并发模式，不妨在你的下一个React项目中试试看，相信你会被它的流畅体验所惊艳！&lt;/p&gt;
</content:encoded></item><item><title>React Hooks 入门指南</title><link>https://www.asherxh.top/posts/react-hooks-guide/</link><guid isPermaLink="true">https://www.asherxh.top/posts/react-hooks-guide/</guid><pubDate>Mon, 23 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;React Hooks 入门指南&lt;/h1&gt;
&lt;p&gt;React Hooks 是 React 16.8 引入的新特性，它允许你在不编写 class 组件的情况下使用 state 和其他 React 特性。Hooks 让函数组件拥有了类组件的能力，同时代码更加简洁和易于维护。&lt;/p&gt;
&lt;h2&gt;什么是 Hooks&lt;/h2&gt;
&lt;p&gt;Hooks 是一些可以让你在函数组件里&quot;钩入&quot; React state 及生命周期等特性的函数。React 内置了一些常用的 Hooks，如 &lt;code&gt;useState&lt;/code&gt;、&lt;code&gt;useEffect&lt;/code&gt;、&lt;code&gt;useContext&lt;/code&gt; 等。&lt;/p&gt;
&lt;h2&gt;useState Hook&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;useState&lt;/code&gt; 是最常用的 Hook，用于在函数组件中添加 state。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import React, { useState } from &apos;react&apos;;

function Counter() {
  const [count, setCount] = useState(0);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;p&amp;gt;你点击了 {count} 次&amp;lt;/p&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setCount(count + 1)}&amp;gt;
        点击我
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;useState&lt;/code&gt; 返回一个数组，第一个元素是当前的 state 值，第二个元素是更新该 state 的函数。&lt;/p&gt;
&lt;h2&gt;useEffect Hook&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;useEffect&lt;/code&gt; 用于处理副作用操作，如数据获取、订阅、手动修改 DOM 等。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import React, { useState, useEffect } from &apos;react&apos;;

function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  useEffect(() =&amp;gt; {
    fetchUser(userId).then(data =&amp;gt; setUser(data));
  }, [userId]);

  if (!user) return &amp;lt;div&amp;gt;加载中...&amp;lt;/div&amp;gt;;

  return &amp;lt;div&amp;gt;欢迎, {user.name}!&amp;lt;/div&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;useEffect&lt;/code&gt; 接受两个参数：一个函数和一个依赖数组。当依赖数组中的值发生变化时，effect 会重新执行。&lt;/p&gt;
&lt;h2&gt;useContext Hook&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;useContext&lt;/code&gt; 让你可以在函数组件中读取 context 的值，而无需使用 Consumer 组件。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import React, { useContext } from &apos;react&apos;;

const ThemeContext = React.createContext(&apos;light&apos;);

function Button() {
  const theme = useContext(ThemeContext);
  return &amp;lt;button className={theme}&amp;gt;点击我&amp;lt;/button&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;自定义 Hooks&lt;/h2&gt;
&lt;p&gt;你可以创建自己的 Hooks 来复用状态逻辑。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function useWindowSize() {
  const [size, setSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight,
  });

  useEffect(() =&amp;gt; {
    const handleResize = () =&amp;gt; {
      setSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    };

    window.addEventListener(&apos;resize&apos;, handleResize);
    return () =&amp;gt; window.removeEventListener(&apos;resize&apos;, handleResize);
  }, []);

  return size;
}

function App() {
  const { width, height } = useWindowSize();
  return &amp;lt;div&amp;gt;窗口大小: {width} x {height}&amp;lt;/div&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Hooks 使用规则&lt;/h2&gt;
&lt;p&gt;使用 Hooks 时需要遵循以下规则：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;只在函数最外层调用 Hook&lt;/strong&gt;：不要在循环、条件判断或者子函数中调用&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;只在 React 函数中调用 Hook&lt;/strong&gt;：在 React 函数组件或自定义 Hook 中调用&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;// 错误示例
function BadExample() {
  if (condition) {
    const [count, setCount] = useState(0); // 不要在条件语句中使用
  }
}

// 正确示例
function GoodExample() {
  const [count, setCount] = useState(0);
  if (condition) {
    // 在这里使用 count
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;React Hooks 为函数组件带来了强大的能力，让我们能够更优雅地编写 React 组件。掌握常用的 Hooks 和自定义 Hooks 的编写，将大大提升你的 React 开发效率。&lt;/p&gt;
</content:encoded></item><item><title>React 组件性能优化技巧</title><link>https://www.asherxh.top/posts/react-performance-optimization/</link><guid isPermaLink="true">https://www.asherxh.top/posts/react-performance-optimization/</guid><pubDate>Mon, 23 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;React 组件性能优化技巧&lt;/h1&gt;
&lt;p&gt;在构建大型 React 应用时，性能优化是一个不可忽视的重要话题。本文将介绍几种常用的 React 组件性能优化技巧，帮助你构建更高效的应用。&lt;/p&gt;
&lt;h2&gt;使用 React.memo 避免不必要的渲染&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;React.memo&lt;/code&gt; 是一个高阶组件，它对函数组件进行记忆化处理。只有当 props 发生变化时，组件才会重新渲染。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const ExpensiveComponent = React.memo(function ExpensiveComponent({ data }) {
  console.log(&apos;渲染 ExpensiveComponent&apos;);
  return &amp;lt;div&amp;gt;{data.map(item =&amp;gt; &amp;lt;div key={item.id}&amp;gt;{item.name}&amp;lt;/div&amp;gt;)}&amp;lt;/div&amp;gt;;
});

function App() {
  const [count, setCount] = useState(0);
  const data = [{ id: 1, name: &apos;Item 1&apos; }];

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setCount(count + 1)}&amp;gt;点击: {count}&amp;lt;/button&amp;gt;
      &amp;lt;ExpensiveComponent data={data} /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;使用 useMemo 缓存计算结果&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;useMemo&lt;/code&gt; 可以缓存计算结果，避免在每次渲染时重复执行昂贵的计算。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function ExpensiveCalculation({ numbers }) {
  const sum = useMemo(() =&amp;gt; {
    console.log(&apos;执行复杂计算&apos;);
    return numbers.reduce((acc, num) =&amp;gt; acc + num, 0);
  }, [numbers]);

  return &amp;lt;div&amp;gt;总和: {sum}&amp;lt;/div&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;使用 useCallback 缓存函数&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;useCallback&lt;/code&gt; 可以缓存函数引用，避免在每次渲染时创建新的函数实例，这对于传递给子组件的回调函数特别有用。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function ParentComponent() {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() =&amp;gt; {
    console.log(&apos;按钮被点击&apos;);
  }, []);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;button onClick={() =&amp;gt; setCount(count + 1)}&amp;gt;计数: {count}&amp;lt;/button&amp;gt;
      &amp;lt;ChildComponent onClick={handleClick} /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}

const ChildComponent = React.memo(function ChildComponent({ onClick }) {
  console.log(&apos;渲染 ChildComponent&apos;);
  return &amp;lt;button onClick={onClick}&amp;gt;子组件按钮&amp;lt;/button&amp;gt;;
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;使用列表渲染时的 key 优化&lt;/h2&gt;
&lt;p&gt;在渲染列表时，为每个元素提供稳定的 &lt;code&gt;key&lt;/code&gt; 属性，帮助 React 识别哪些元素发生了变化。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;function TodoList({ todos }) {
  return (
    &amp;lt;ul&amp;gt;
      {todos.map(todo =&amp;gt; (
        &amp;lt;li key={todo.id}&amp;gt;
          {todo.text}
        &amp;lt;/li&amp;gt;
      ))}
    &amp;lt;/ul&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：不要使用数组索引作为 key，特别是在列表可能会重新排序的情况下。&lt;/p&gt;
&lt;h2&gt;代码分割和懒加载&lt;/h2&gt;
&lt;p&gt;使用 &lt;code&gt;React.lazy&lt;/code&gt; 和 &lt;code&gt;Suspense&lt;/code&gt; 实现组件的懒加载，减少初始加载体积。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import React, { lazy, Suspense } from &apos;react&apos;;

const HeavyComponent = lazy(() =&amp;gt; import(&apos;./HeavyComponent&apos;));

function App() {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;Suspense fallback={&amp;lt;div&amp;gt;加载中...&amp;lt;/div&amp;gt;}&amp;gt;
        &amp;lt;HeavyComponent /&amp;gt;
      &amp;lt;/Suspense&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;虚拟化长列表&lt;/h2&gt;
&lt;p&gt;对于包含大量数据的列表，使用虚拟滚动技术只渲染可见区域的元素。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { FixedSizeList as List } from &apos;react-window&apos;;

function Row({ index, style }) {
  return (
    &amp;lt;div style={style}&amp;gt;
      行 {index}
    &amp;lt;/div&amp;gt;
  );
}

function VirtualList({ items }) {
  return (
    &amp;lt;List
      height={400}
      itemCount={items.length}
      itemSize={35}
      width={300}
    &amp;gt;
      {Row}
    &amp;lt;/List&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;避免内联对象和数组&lt;/h2&gt;
&lt;p&gt;避免在 JSX 中直接创建对象和数组，这会导致每次渲染都创建新的引用。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 不好的做法
function BadComponent() {
  return &amp;lt;ChildComponent style={{ color: &apos;red&apos; }} /&amp;gt;;
}

// 好的做法
function GoodComponent() {
  const style = useMemo(() =&amp;gt; ({ color: &apos;red&apos; }), []);
  return &amp;lt;ChildComponent style={style} /&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;使用生产版本构建&lt;/h2&gt;
&lt;p&gt;确保在生产环境中使用 React 的生产版本，它会移除开发时的警告和检查，性能更好。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 构建生产版本
npm run build
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;性能优化是一个持续的过程，需要根据实际场景选择合适的优化策略。记住一个重要原则：&lt;strong&gt;过早优化是万恶之源&lt;/strong&gt;。先确保代码正确，再通过性能分析工具找出真正的瓶颈，然后针对性地进行优化。&lt;/p&gt;
</content:encoded></item><item><title>React 18 新特性详解</title><link>https://www.asherxh.top/posts/react-18-features/</link><guid isPermaLink="true">https://www.asherxh.top/posts/react-18-features/</guid><pubDate>Mon, 23 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;React 18 新特性详解&lt;/h1&gt;
&lt;p&gt;React 18 是 React 的一个重要版本更新，带来了许多令人兴奋的新特性和改进。本文将详细介绍 React 18 的主要新特性，帮助你更好地理解和使用这些功能。&lt;/p&gt;
&lt;h2&gt;并发渲染（Concurrent Rendering）&lt;/h2&gt;
&lt;p&gt;并发渲染是 React 18 的核心特性，它允许 React 准备多个版本的 UI 同时进行。这意味着 React 可以中断渲染过程，优先处理更重要的更新，然后再恢复被中断的渲染。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 启用并发模式
import { createRoot } from &apos;react-dom/client&apos;;

const container = document.getElementById(&apos;root&apos;);
const root = createRoot(container);
root.render(&amp;lt;App /&amp;gt;);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;自动批处理（Automatic Batching）&lt;/h2&gt;
&lt;p&gt;React 18 改进了批处理机制，现在可以在更多场景下自动批处理状态更新，减少不必要的重新渲染。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// React 17: 会导致两次渲染
function handleClick() {
  setCount(c =&amp;gt; c + 1);
  setFlag(f =&amp;gt; !f);
}

// React 18: 自动批处理，只渲染一次
function handleClick() {
  setCount(c =&amp;gt; c + 1);
  setFlag(f =&amp;gt; !f);
}

// 即使在异步操作中也能自动批处理
function handleClick() {
  fetchSomething().then(() =&amp;gt; {
    setCount(c =&amp;gt; c + 1);
    setFlag(f =&amp;gt; !f);
  });
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;新的 Hooks&lt;/h2&gt;
&lt;h3&gt;useTransition&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;useTransition&lt;/code&gt; 用于标记非紧急的状态更新，让 React 优先处理更重要的更新。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { useTransition } from &apos;react&apos;;

function SearchComponent() {
  const [isPending, startTransition] = useTransition();
  const [input, setInput] = useState(&apos;&apos;);
  const [list, setList] = useState([]);

  const handleChange = (e) =&amp;gt; {
    const value = e.target.value;
    setInput(value);

    startTransition(() =&amp;gt; {
      const filtered = largeList.filter(item =&amp;gt; item.includes(value));
      setList(filtered);
    });
  };

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;input value={input} onChange={handleChange} /&amp;gt;
      {isPending &amp;amp;&amp;amp; &amp;lt;div&amp;gt;加载中...&amp;lt;/div&amp;gt;}
      &amp;lt;ul&amp;gt;{list.map(item =&amp;gt; &amp;lt;li key={item}&amp;gt;{item}&amp;lt;/li&amp;gt;)}&amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;useDeferredValue&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;useDeferredValue&lt;/code&gt; 用于延迟更新某个值，类似于防抖，但由 React 内部优化。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { useDeferredValue } from &apos;react&apos;;

function SearchResults({ query }) {
  const deferredQuery = useDeferredValue(query);

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;Results query={deferredQuery} /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;useId&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;useId&lt;/code&gt; 用于生成唯一的 ID，特别适用于可访问性属性。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { useId } from &apos;react&apos;;

function Form() {
  const id = useId();

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;label htmlFor={id}&amp;gt;邮箱&amp;lt;/label&amp;gt;
      &amp;lt;input id={id} type=&quot;email&quot; /&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Suspense 改进&lt;/h2&gt;
&lt;p&gt;React 18 对 Suspense 进行了重要改进，现在支持服务端渲染。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { Suspense } from &apos;react&apos;;

function App() {
  return (
    &amp;lt;Suspense fallback={&amp;lt;Loading /&amp;gt;}&amp;gt;
      &amp;lt;DataComponent /&amp;gt;
    &amp;lt;/Suspense&amp;gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;严格模式变化&lt;/h2&gt;
&lt;p&gt;React 18 的严格模式会双重调用组件的 effects，帮助开发者发现副作用问题。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 开发模式下，effect 会被调用两次
useEffect(() =&amp;gt; {
  console.log(&apos;Effect 被调用&apos;);
  return () =&amp;gt; {
    console.log(&apos;Cleanup 被调用&apos;);
  };
}, []);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;新的客户端和服务器 API&lt;/h2&gt;
&lt;h3&gt;createRoot&lt;/h3&gt;
&lt;p&gt;新的 &lt;code&gt;createRoot&lt;/code&gt; API 替代了旧的 &lt;code&gt;render&lt;/code&gt; 方法。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { createRoot } from &apos;react-dom/client&apos;;

const root = createRoot(document.getElementById(&apos;root&apos;));
root.render(&amp;lt;App /&amp;gt;);
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;hydrateRoot&lt;/h3&gt;
&lt;p&gt;用于服务端渲染的 hydration。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { hydrateRoot } from &apos;react-dom/client&apos;;

hydrateRoot(document.getElementById(&apos;root&apos;), &amp;lt;App /&amp;gt;);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;移除的 API&lt;/h2&gt;
&lt;p&gt;React 18 移除了一些过时的 API：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ReactDOM.render&lt;/code&gt; → 使用 &lt;code&gt;createRoot&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ReactDOM.hydrate&lt;/code&gt; → 使用 &lt;code&gt;hydrateRoot&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;unmountComponentAtNode&lt;/code&gt; → 使用 &lt;code&gt;root.unmount()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;render&lt;/code&gt; 的回调参数&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;流式服务端渲染（Streaming SSR）&lt;/h2&gt;
&lt;p&gt;React 18 支持流式服务端渲染，允许服务器逐步发送 HTML 片段。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { renderToPipeableStream } from &apos;react-dom/server&apos;;

app.get(&apos;/&apos;, (req, res) =&amp;gt; {
  const stream = renderToPipeableStream(&amp;lt;App /&amp;gt;, {
    onShellReady() {
      res.statusCode = 200;
      res.setHeader(&apos;Content-type&apos;, &apos;text/html&apos;);
      stream.pipe(res);
    },
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;React 18 带来了许多重要的改进和新特性，特别是并发渲染和自动批处理，这些都将显著提升 React 应用的性能和用户体验。升级到 React 18 后，你可以逐步采用这些新特性，让应用更加高效和流畅。&lt;/p&gt;
&lt;p&gt;注意：React 18 是向后兼容的，你可以逐步迁移，不必一次性更新所有代码。&lt;/p&gt;
</content:encoded></item></channel></rss>