以下是基于你提供的文档内容进行的详细梳理与补充,完成为一篇结构清晰、内容详实的博客文章。
🌙 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
2
3
4
5
useRef
返回一个可变对象,其.current
属性可以存储任意值useRef
的值更新不会触发组件重新渲染(与useState
不同)- 原理:本质上是一个对象
{ current: initialValue }
,React 内部保持其引用不变
🌙 3. ref
与 state
的区别
特性 | 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
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
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
2
3
4
5
6
7
8
9
use
可以在组件中捕获Promise
Suspense
可以包裹组件,显示加载状态或错误边界
🌙 3. Suspense 捕获 Promise
当组件中使用了 use
或 lazy
,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
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
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
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
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
- 适合中小型应用的状态共享
- 避免过度使用,复杂场景建议使用第三方库
🌙 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
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. 开源项目推荐
- awesome-react (opens new window):React 生态资源汇总
- react-use (opens new window):丰富的自定义 Hook
- react18-use (opens new window):React 18 新特性 Hook
- immer (opens new window):不可变更新库,简化
useReducer