以下是基于你提供的文档内容进行的详细梳理与补充,完成为一篇结构清晰、内容详实的博客文章。


🌙 React 知识扫盲

React 是一个用于构建用户界面的 JavaScript 库,其核心理念是组件化、声明式编程与高效的更新机制。本文将系统梳理 React 开发中常见但又容易被忽视的知识点,帮助你构建完整的 React 知识体系。


🌙 一、ref:访问 DOM 与持久化数据

🌙 1. 为什么需要 ref

ref 提供了一种访问 DOM 元素或 React 组件实例的方式,适用于以下场景:

  • 操作 DOM(如聚焦输入框、滚动条控制)
  • 存储不引起视图更新的数据(如计时器 ID、外部状态)
  • 与第三方库(如 D3、地图组件)交互

🌙 2. useRef 的使用方式与原理

const inputRef = useRef<HTMLInputElement>(null);

useEffect(() => {
  inputRef.current?.focus();
}, []);
1
2
3
4
5
  • useRef 返回一个可变对象,其 .current 属性可以存储任意值
  • useRef 的值更新不会触发组件重新渲染(与 useState 不同)
  • 原理:本质上是一个对象 { current: initialValue },React 内部保持其引用不变

🌙 3. refstate 的区别

特性 ref state
更新是否触发 re-render
适合存储的数据类型 DOM、外部状态、不可变数据 UI 状态
可变性 可变 不可变

🌙 二、forwardRef:转发 ref 到子组件

🌙 1. 为什么不能直接通过 props 传递 ref

ref 是 React 的特殊属性,不能通过 props 直接传递。React 为了确保 ref 行为一致,提供了 forwardRef API。

🌙 2. 如何使用 forwardRef

const Child = forwardRef((props, ref) => {
  const inputRef = useRef<HTMLInputElement>(null);

  useImperativeHandle(ref, () => ({
    focus: () => inputRef.current?.focus(),
  }));

  return <input ref={inputRef} />;
});
1
2
3
4
5
6
7
8
9
  • forwardRef 接收一个函数组件,并将 ref 作为第二个参数传入
  • useImperativeHandle 用于自定义暴露给父组件的方法

🌙 3. 实际应用场景

  • 表单组件(如封装的 Input 组件,需要支持 focus() 方法)
  • 动画控制(如 Canvas 组件暴露 start() 方法)
  • 第三方组件库(如 Ant Design、Material UI)

🌙 三、Suspense:优雅处理异步操作

🌙 1. Suspense + lazy:组件懒加载

const LazyComponent = lazy(() => import('./LazyComponent'));

function App() {
  return (
    <Suspense fallback="Loading...">
      <LazyComponent />
    </Suspense>
  );
}
1
2
3
4
5
6
7
8
9
  • lazy 动态导入组件,实现按需加载
  • Webpack 会自动拆分代码,减少初始加载体积
  • 配合 Suspense 提供加载状态 UI

🌙 2. Suspense + async:处理异步请求(React 18)

React 18 引入了 use 函数(实验性),允许在组件中直接使用 Promise

function useData(fetcher) {
  const result = use(fetcher());
  return result;
}

function MyComponent() {
  const data = useData(fetchData);
  return <div>{data}</div>;
}
1
2
3
4
5
6
7
8
9
  • use 可以在组件中捕获 Promise
  • Suspense 可以包裹组件,显示加载状态或错误边界

🌙 3. Suspense 捕获 Promise

当组件中使用了 uselazy,React 会自动捕获 Promise 并交由 Suspense 处理。


🌙 四、lazy:按需加载组件

🌙 1. 异步加载组件

const LazyComponent = lazy(() => import('./LazyComponent'));
1
  • lazy 接收一个返回 Promise 的函数
  • import() 是动态导入语法,Webpack 会自动分包

🌙 2. 与 Suspense 配合使用

<Suspense fallback={<Loading />}>
  <LazyComponent />
</Suspense>
1
2
3
  • fallback 属性定义加载时的 UI
  • 支持嵌套使用,实现更细粒度的加载控制

🌙 五、memo:优化子组件渲染

🌙 1. React.memo 是什么?

React.memo 是一个高阶组件(HOC),用于避免不必要的子组件渲染。

const MemoizedChild = memo(Child);
1
  • 默认进行 props 的浅比较
  • 若 props 未变化,则跳过 re-render

🌙 2. 实现原理

  • React.memo(Component, arePropsEqual?)
  • arePropsEqual 可自定义比较逻辑(默认 Object.is
  • 不推荐对所有组件使用 memo,避免过度优化

🌙 3. React DevTools 查看更新

在 React DevTools 中启用 Highlight Updates,可以直观看到组件的渲染行为。


🌙 六、Hooks:React 的函数式编程基石

🌙 1. useState 是 useReducer 的语法糖

const [count, setCount] = useState(0);
// 等价于
const [state, dispatch] = useReducer((state, action) => {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    default:
      return state;
  }
}, { count: 0 });
1
2
3
4
5
6
7
8
9
10

🌙 2. useEffect vs useLayoutEffect

特性 useEffect useLayoutEffect
执行时机 浏览器绘制后 浏览器绘制前
是否阻塞渲染
适用场景 数据获取、订阅、副作用 DOM 操作、布局计算

🌙 3. 自定义 Hook:useIsomorphicLayoutEffect

const useIsomorphicLayoutEffect =
  typeof window !== 'undefined' ? useLayoutEffect : useEffect;
1
2
  • 用于在 SSR 或 React Native 中避免使用 useLayoutEffect 导致的不一致
  • React Native 不支持 DOM,因此 useLayoutEffect 会抛出警告

🌙 4. 新增 Hooks

  • useId:生成唯一 ID,用于无障碍属性(如 aria-labelledby
  • useTransition:标记更新为“过渡”状态,延迟高优先级更新
  • useSyncExternalStore:订阅外部状态源(如 Redux、MobX)

🌙 七、样式方案:React 中的 CSS 实践

🌙 1. 内联样式

<div style={{ color: 'red', fontSize: '14px' }}>Hello</div>
1
  • 优点:组件作用域、类型安全(TS)
  • 缺点:难以复用、不支持伪类

🌙 2. CSS Modules

import styles from './Button.module.css';
<button className={styles.primary}>Submit</button>
1
2
  • 模块化 CSS,避免类名冲突
  • 支持 SSR

🌙 3. CSS-in-JS

  • styled-components / emotion
  • 支持动态样式、主题、伪类
  • 缺点:SSR 需额外处理样式注入

🌙 4. Tailwind CSS

  • 实用类优先的 CSS 框架
  • 快速构建响应式 UI
  • 支持 JIT 模式,减少冗余类
<button className="bg-blue-500 text-white px-4 py-2 rounded">Submit</button>
1

🌙 八、状态管理:React 内置与第三方方案

🌙 1. Context + useReducer

const [state, dispatch] = useReducer(reducer, initialState);
const store = useMemo(() => ({ state, dispatch }), [state]);
1
2
  • 适合中小型应用的状态共享
  • 避免过度使用,复杂场景建议使用第三方库

🌙 2. 第三方状态管理库

  • Redux:可预测的状态容器,适合大型应用
  • MobX:响应式状态管理,适合复杂交互
  • Zustand / Jotai / Recoil:轻量、易用,适合中型应用

🌙 九、TypeScript 配置:React + TS 最佳实践

🌙 1. tsconfig.json 推荐配置

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": ["src"]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

🌙 2. 类型定义最佳实践

  • 使用 React.FC 类型定义函数组件
  • 使用 React.RefObject 定义 ref 类型
  • 使用 React.MutableRefObject 定义可变 ref

🌙 十、生态工具推荐

🌙 1. 开源项目推荐

🌙 2. TypeScript 资源