理解 React 的核心概念,将帮助开发者更好地使用 React 构建高效的用户界面。
基础概念
组件(Components)
就像乐高积木,每个组件都是独立的功能模块:
function Button() {
return <button>点击我</button>;
}
虚拟DOM(VDOM)
React 的”建筑图纸系统”,开发者的修改都会先在图纸上标记(生成新VDOM),施工队(协调机制)拿着新旧图纸对比后,只修改实际变化的部分:
// 设计草稿(旧VDOM)
const oldBlueprint = {
type: 'div',
props: { children: 'Hello' }
};
// 修订方案(新VDOM)
const newBlueprint = {
type: 'div',
props: {
children: [
'Hello',
{ type: 'span', props: { children: ' World' } }
]
}
};
// 施工流程(Diffing算法)
1. 比对图纸类型变化(div → 保持)
2. 检查属性变化(无新增/删除)
3. 发现子节点变化:
- 文本节点 'Hello' 保留
- 新增 <span> 节点
🏗️
React 的协调机制就像施工队长:
- 发现图纸变化后,标记需要修改的区域
- 重用可复用的建筑部件(DOM节点复用)
- 按最小修改量施工(DOM操作优化)
可视化比对流程:
JSX
让 HTML 住在 JavaScript 里的魔法语法:
const element = <h1 className="title">你好 React</h1>;
组件渲染
列表渲染与 Keys
给列表元素配”身份证号码”,避免更新混乱:
function TodoList({ todos }) {
return (
<ul>
{todos.map((todo) => (
<li key={todo.id}> {/* 唯一标识符 */}
{todo.text}
<button onClick={() => handleDelete(todo.id)}>删除</button>
</li>
))}
</ul>
);
}
// 错误示例:使用数组索引作为 key
{todos.map((todo, index) => (
<li key={index}>...</li> {/* 可能导致渲染问题 */}
))}
💡
Key 应该来自数据的唯一标识,推荐使用 ID 而非索引
协调机制 (Reconciliation)
React 的”版本对比系统”,像快递分拣员比较新旧包裹:
// 旧包裹
<ul>
<li>苹果</li>
<li>香蕉</li>
</ul>
// 新包裹
<ul>
<li>橙子</li>
<li>苹果</li>
<li>香蕉</li>
</ul>
// React 会智能地只插入橙子
组件交互
Refs
组件的”遥控器”,直接操控 DOM 元素:
// 函数组件用法
function TextInput() {
const inputRef = useRef(null);
const focusInput = () => inputRef.current?.focus();
return (
<>
<input ref={inputRef} />
<button onClick={focusInput}>聚焦输入框</button>
</>
);
}
// 类组件用法
class AutoFocusInput extends React.Component {
constructor(props) {
super(props);
this.inputRef = React.createRef();
}
componentDidMount() {
this.inputRef.current.focus();
}
render() {
return <input ref={this.inputRef} />;
}
}
⚠️
Ref 应作为 DOM 操作的逃生舱,优先使用声明式数据流
Props
组件之间的传纸条:
function Welcome(props) {
return <h1>你好, {props.name}</h1>;
}
State
组件的便签纸(记忆功能):
function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(count+1)}>点击 {count}</button>;
}
高级特性
错误边界 (Error Boundary)
组件的”安全气囊”,防止局部错误导致整个应用崩溃:
class ErrorBoundary extends React.Component {
state = { hasError: false }
static getDerivedStateFromError(error) {
return { hasError: true }
}
render() {
return this.state.hasError
? <h1>零件故障,正在检修</h1>
: this.props.children
}
}
// 使用方式
<ErrorBoundary>
<BuggyComponent />
</ErrorBoundary>
自定义 Hooks
打造专属的”多功能工具包”:
function useWindowSize() {
const [size, setSize] = useState({
width: window.innerWidth,
height: window.innerHeight
})
useEffect(() => {
const handleResize = () => setSize({
width: window.innerWidth,
height: window.innerHeight
})
window.addEventListener('resize', handleResize)
return () => window.removeEventListener('resize', handleResize)
}, [])
return size
}
// 在组件中使用
const { width } = useWindowSize()
Suspense
组件的”加载中提示牌”,优雅处理异步操作:
const LazyComponent = React.lazy(() => import('./HeavyComponent'));
function App() {
return (
<React.Suspense fallback={<div>正在加载...</div>}>
<LazyComponent />
</React.Suspense>
);
}
// 配合错误边界使用
<ErrorBoundary>
<Suspense fallback={<Loading />}>
<AsyncContent />
</Suspense>
</ErrorBoundary>
React 18 新特性
并发模式 (Concurrent Mode)
组件的”交通信号灯系统”,优先处理紧急更新:
// 使用并发渲染
const root = createRoot(document.getElementById('root'))
root.render(
<ConcurrentMode>
<App />
</ConcurrentMode>
)
自动批处理
状态更新的”快递合并发货”:
function handleClick() {
setName('李雷') // 不会立即渲染
setAge(18) // 不会立即渲染
// 所有更新会批量处理
}
Hooks
组件的瑞士军刀:
useEffect(() => {
document.title = `点击了 ${count} 次`;
}, [count]);
Context
组件树的广播系统:
const ThemeContext = createContext('light');
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
⚠️
实际开发中建议搭配 TypeScript 使用以获得更好的类型提示
🚀
React 18 的并发特性需要配合 createRoot 使用,可显著提升复杂应用的交互流畅度
Last updated on