React 核心技术深度笔记

React 核心技术深度笔记

一、非交互性更新的优先级

1.1 理解更新优先级

React 18 引入了优先级调度系统,不同类型的更新有不同的优先级:

优先级 类型 说明
Immediate 同步更新 需要立即执行,不能中断
UserBlocking 用户交互 点击、输入等,需要快速响应
Normal 普通更新 数据获取后的更新
Low 低优先级 非关键更新,如日志上报
Idle 空闲时执行 可延迟到浏览器空闲时

1.2 非交互性更新的处理

场景示例

jsx 复制代码
import { startTransition, useEffect } from 'react';

function SearchResults({ query }) {
  const [results, setResults] = useState([]);
  
  useEffect(() => {
    // 低优先级更新:不会阻塞用户交互
    startTransition(() => {
      fetchResults(query).then(data => {
        setResults(data);
      });
    });
  }, [query]);
  
  return <ResultsList items={results} />;
}

使用 useTransition 钩子

jsx 复制代码
import { useTransition } from 'react';

function App() {
  const [isPending, startTransition] = useTransition();
  
  const handleSearch = (query) => {
    // 标记为过渡更新
    startTransition(() => {
      setSearchQuery(query);
    });
  };
  
  return (
    <>
      <SearchInput onChange={handleSearch} />
      {isPending && <LoadingIndicator />}
      <Results query={searchQuery} />
    </>
  );
}

二、Server Components(RSC)深度解析

2.1 什么是 Server Components

定义:在服务端运行的 React 组件,无需发送到客户端

核心优势

  • 📦 减少 JS 体积:不包含在客户端 bundle 中
  • 🚀 数据获取更高效:直接在服务端访问数据库
  • 🎯 SEO 友好:服务端渲染完整 HTML

2.2 RSC vs SSR vs Client Components

特性 Server Components SSR Client Components
运行位置 服务端 服务端渲染,客户端交互 客户端
可访问 数据库、文件系统 仅通过 API 浏览器 API
JS 体积 0KB 需要 hydration 包含在 bundle
交互能力 需要 hydration 完全支持

2.3 RSC 实践

创建 Server Component

jsx 复制代码
// app/PostList.server.jsx
async function PostList() {
  // 直接在服务端获取数据
  const posts = await db.posts.findMany({ 
    orderBy: { createdAt: 'desc' },
    take: 10 
  });
  
  return (
    <ul>
      {posts.map(post => (
        <li key={post.id}>
          <h3>{post.title}</h3>
          <p>{post.excerpt}</p>
        </li>
      ))}
    </ul>
  );
}

混合使用 Server/Client Components

jsx 复制代码
// app/Blog.jsx
import PostList from './PostList.server';
import CommentSection from './CommentSection.client';

function Blog({ postId }) {
  return (
    <div>
      {/* Server Component:渲染内容 */}
      <PostList />
      
      {/* Client Component:处理交互 */}
      <CommentSection postId={postId} />
    </div>
  );
}

2.4 RSC 数据流模式

arduino 复制代码
┌─────────────────────────────────────────────────────────────┐
│                    Server Side                              │
├─────────────────────────────────────────────────────────────┤
│  Server Components                                          │
│  ├─ 获取数据(DB/API)                                      │
│  ├─ 渲染为特殊格式(React Server Component Payload)         │
│  └─ 发送到客户端                                             │
└─────────────────────────────────────────────────────────────┘
                            │
                            ▼
┌─────────────────────────────────────────────────────────────┐
│                    Client Side                              │
├─────────────────────────────────────────────────────────────┤
│  Client Components                                          │
│  ├─ 接收 Server Component 的渲染结果                        │
│  ├─ 进行 hydration(如果需要)                              │
│  └─ 处理用户交互                                            │
└─────────────────────────────────────────────────────────────┘

2.5 RSC 适用场景

内容展示组件 :博客文章、产品列表、静态页面

数据密集型组件 :仪表盘、报表

SEO 关键页面:首页、落地页

高交互组件 :表单、实时编辑器

需要浏览器 API:DOM 操作、事件监听


三、React.memo 完全指南

3.1 什么是 React.memo

定义:高阶组件(HOC),用于对组件输出进行浅比较,避免不必要的重渲染

工作原理

jsx 复制代码
// 伪代码展示 React.memo 的工作方式
function memo(Component) {
  return function MemoizedComponent(props) {
    // 比较前后 props
    if (propsChanged(prevProps, currentProps)) {
      return <Component {...props} />;
    }
    // 返回缓存的结果
    return cachedResult;
  };
}

3.2 使用场景

场景一:纯展示组件

jsx 复制代码
const UserCard = React.memo(function UserCard({ user }) {
  return (
    <div className="card">
      <img src={user.avatar} alt={user.name} />
      <h3>{user.name}</h3>
      <p>{user.bio}</p>
    </div>
  );
});

场景二:列表项组件

jsx 复制代码
const TodoItem = React.memo(function TodoItem({ todo, onToggle }) {
  return (
    <div onClick={() => onToggle(todo.id)}>
      <input 
        type="checkbox" 
        checked={todo.completed} 
        readOnly 
      />
      <span className={todo.completed ? 'completed' : ''}>
        {todo.text}
      </span>
    </div>
  );
});

3.3 自定义比较函数

深度比较场景

jsx 复制代码
const DeepMemoComponent = React.memo(
  MyComponent,
  (prevProps, nextProps) => {
    // 自定义比较逻辑
    return (
      prevProps.id === nextProps.id &&
      prevProps.data.value === nextProps.data.value
    );
  }
);

3.4 React.memo 的性能考量

什么时候使用

  • 组件渲染成本高(复杂计算、大量子组件)
  • 组件频繁接收相同 props
  • 在大型列表中使用

什么时候不使用

  • 简单组件(比较成本 > 渲染成本)
  • props 频繁变化
  • 组件内部有 useState/useContext

3.5 React.memo vs useMemo

特性 React.memo useMemo
作用范围 组件级 值/计算结果
比较方式 浅比较 props 比较依赖数组
返回值 新组件 缓存的值
使用方式 包装组件 包装计算表达式
jsx 复制代码
// React.memo - 缓存组件渲染
const MemoizedList = React.memo(List);

// useMemo - 缓存计算结果
const expensiveValue = useMemo(() => {
  return computeExpensiveData(data);
}, [data]);

四、组件设计原则

4.1 单一职责原则

定义:一个组件应该只负责一件事情

反例

jsx 复制代码
// ❌ 违反单一职责:同时处理数据获取和UI渲染
function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  
  useEffect(() => {
    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(data => setUser(data));
  }, [userId]);
  
  if (!user) return <Loading />;
  
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
      {/* ... 更多UI */}
    </div>
  );
}

正例

jsx 复制代码
// ✅ 数据获取逻辑
function useUser(userId) {
  const [user, setUser] = useState(null);
  
  useEffect(() => {
    fetch(`/api/users/${userId}`)
      .then(res => res.json())
      .then(data => setUser(data));
  }, [userId]);
  
  return user;
}

// ✅ 纯UI组件
function UserProfile({ user }) {
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}

// ✅ 使用
function ProfilePage({ userId }) {
  const user = useUser(userId);
  if (!user) return <Loading />;
  return <UserProfile user={user} />;
}

4.2 可复用性原则

设计通用、可配置的组件

示例:通用 Button 组件

jsx 复制代码
const Button = ({ 
  children, 
  variant = 'primary', 
  size = 'md',
  disabled = false,
  onClick,
  className = '',
  ...props 
}) => {
  const baseStyles = 'px-4 py-2 rounded font-medium transition-all';
  
  const variants = {
    primary: 'bg-blue-500 text-white hover:bg-blue-600',
    secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
    danger: 'bg-red-500 text-white hover:bg-red-600',
  };
  
  const sizes = {
    sm: 'text-sm px-3 py-1',
    md: 'text-base',
    lg: 'text-lg px-6 py-3',
  };
  
  return (
    <button
      disabled={disabled}
      onClick={onClick}
      className={`${baseStyles} ${variants[variant]} ${sizes[size]} ${className}`}
      {...props}
    >
      {children}
    </button>
  );
};

// 使用
<Button>默认按钮</Button>
<Button variant="secondary" size="sm">次要按钮</Button>
<Button variant="danger" disabled>危险按钮</Button>

4.3 纯组件原则

定义:相同输入产生相同输出,无副作用

纯组件特征

  • 不修改传入的 props
  • 不依赖外部状态
  • 不产生副作用(如 API 调用、DOM 操作)
  • 相同输入始终返回相同输出

示例

jsx 复制代码
// ✅ 纯组件
function Greeting({ name }) {
  return <h1>Hello, {name}!</h1>;
}

// ❌ 不纯组件
function BadGreeting({ name }) {
  // 副作用:直接修改 props
  name = name.toUpperCase();
  return <h1>Hello, {name}!</h1>;
}

五、React.lazy() 与代码分割

5.1 什么是代码分割

定义:将应用代码分割成多个小块,按需加载

核心价值

  • 📦 减少初始加载体积
  • ⚡ 提升首屏加载速度
  • 🚀 优化用户体验

5.2 React.lazy() 基础用法

jsx 复制代码
import { lazy, Suspense } from 'react';

// 动态导入组件
const HeavyChart = lazy(() => import('./HeavyChart'));
const DataTable = lazy(() => import('./DataTable'));

function Dashboard() {
  return (
    <div>
      <h1>Dashboard</h1>
      <Suspense fallback={<Loading />}>
        <HeavyChart />
        <DataTable />
      </Suspense>
    </div>
  );
}

5.3 路由级代码分割

jsx 复制代码
import { lazy, Suspense } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';

const Home = lazy(() => import('./Home'));
const About = lazy(() => import('./About'));
const Dashboard = lazy(() => import('./Dashboard'));

function App() {
  return (
    <BrowserRouter>
      <Suspense fallback={<LoadingScreen />}>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/about" element={<About />} />
          <Route path="/dashboard" element={<Dashboard />} />
        </Routes>
      </Suspense>
    </BrowserRouter>
  );
}

5.4 高级用法:命名导出

jsx 复制代码
// 导出多个组件
export const Chart = () => <div>Chart</div>;
export const Table = () => <div>Table</div>;

// 导入指定组件
const { Chart } = await import('./components');
jsx 复制代码
// 使用命名导出的 lazy 加载
const Chart = lazy(() => 
  import('./components').then(module => ({ default: module.Chart }))
);

5.5 React.lazy vs loadable-components

特性 React.lazy loadable-components
SSR 支持
加载状态 需要 Suspense 内置 loading 状态
错误处理 需要 Error Boundary 内置 error 状态
预加载

六、学习阶段指南

6.1 进阶阶段:核心技能

Hooks 精通

  • useState/useEffect/useContext/useReducer
  • useCallback/useMemo/useRef
  • 自定义 Hooks 设计模式

状态管理

  • Context API 深度应用
  • Redux Toolkit 或 Zustand
  • 状态规范化与选择器

路由

  • React Router 6.x 完整掌握
  • 嵌套路由、路由守卫
  • 动态路由与参数处理

项目结构

bash 复制代码
src/
├── components/          # 通用组件
│   ├── layout/          # 布局组件
│   └── ui/              # UI 原子组件
├── features/            # 功能模块
│   └── auth/            # 认证模块
│       ├── hooks/       # 自定义 hooks
│       ├── components/  # 模块组件
│       └── index.js     # 模块入口
├── hooks/               # 全局 hooks
├── utils/               # 工具函数
└── App.js

6.2 高级阶段:性能优化

渲染优化

  • React.memo、useMemo、useCallback
  • 虚拟列表(react-window/react-virtualized)
  • 状态提升与拆分

资源优化

  • 图片优化(WebP/AVIF)
  • 代码分割与懒加载
  • 资源预加载(preload/prefetch)

服务端渲染

  • Next.js App Router
  • Server Components
  • 数据获取策略(getServerSideProps、fetch)

性能监控

  • Web Vitals
  • React DevTools Profiler
  • 自定义性能指标

6.3 工程化阶段:企业级实践

TypeScript

  • 类型安全、泛型、类型体操
  • 类型定义文件(.d.ts)
  • ESLint + TypeScript 集成

测试体系

  • 单元测试(Jest + RTL)
  • 集成测试(Playwright)
  • 端到端测试

构建工具

  • Vite 配置与插件
  • Webpack 高级配置
  • 构建优化策略

CI/CD

  • GitHub Actions/GitLab CI
  • 自动化测试与部署
  • 环境配置与变量管理

七、最佳实践总结

7.1 性能优化优先级

  1. 架构层面:使用 Server Components 减少客户端 JS
  2. 组件层面:React.memo + useMemo/useCallback 优化渲染
  3. 打包层面:React.lazy + Suspense 实现按需加载
  4. 运行时层面:虚拟滚动、代码分割、资源优化

7.2 组件设计检查清单

  • 是否符合单一职责?
  • 是否可复用、可配置?
  • 是否为纯组件(无副作用)?
  • props 是否最小化、清晰?
  • 是否有合适的错误处理?

7.3 RSC 使用决策树

arduino 复制代码
需要渲染内容吗?
    │
    ├─ 是 → 需要交互吗?
    │       │
    │       ├─ 是 → Client Component
    │       └─ 否 → Server Component
    │
    └─ 否 → 考虑是否需要该组件

这些笔记涵盖了你提到的所有主题,从基础概念到高级实践都有详细说明。建议根据自己的学习阶段,从进阶阶段开始逐步深入,重点关注 Server Components 和性能优化,这是当前 React 生态的核心竞争力所在。

相关推荐
Pkmer1 小时前
古法编程: SPA的路由浅思考
前端
Cobyte1 小时前
9.响应式系统演进:effectScope 的作用与实现原理(Vue3.2)
前端·javascript·vue.js
heimeiyingwang1 小时前
【架构实战】微前端架构设计与落地
前端·架构
techdashen2 小时前
Cloudflare HTML 解析器的十年演化史(二)
前端·html
ZC跨境爬虫2 小时前
Apple官网复刻第二阶段day_1:(导航栏模块化重构+工业化可复用UI落地)
前端·javascript·css·ui·重构
天外飞雨道沧桑2 小时前
Node.js在前端开发中扮演的角色
前端·node.js
梅梅绵绵冰2 小时前
若依框架-智慧社区项目
前端·javascript·vue.js
IT_陈寒2 小时前
Vite开发爽是爽,但这个动态导入坑差点让我崩溃
前端·人工智能·后端
Mr_pyx2 小时前
CompletableFuture 使用全攻略:从异步编程到异常处理
linux·前端·python