Skip to Content
🚀 欢迎来到前端学习指南!这是一份从零基础到专家的完整学习路径
⚛️ 第二部分:框架篇07. React核心原理和生态

07. React核心原理和生态

📋 目录

React架构深度解析

React的核心思想是将UI视为函数的纯粹输出,通过声明式编程和组件化思想构建用户界面。

React核心概念

React设计理念

概念说明特点优势
UI = f(state)UI是状态的纯函数声明式编程可预测、易调试
组件化将UI拆分为独立组件可复用、可组合提高开发效率
Virtual DOM虚拟DOM抽象层内存中的JS对象性能优化、跨平台
单向数据流数据从上到下流动数据流清晰易于理解和维护

核心概念示例

// 1. 函数式组件的本质 function MyComponent(props) { // 这就是一个纯函数:相同输入 -> 相同输出 return <div>{props.children}</div>; } // 2. JSX编译过程 // JSX语法糖 const element = <h1 className="greeting">Hello, world!</h1>; // 编译后的真实代码 const element = React.createElement( 'h1', { className: 'greeting' }, 'Hello, world!' ); // 3. Virtual DOM结构 const virtualDOM = { type: 'h1', props: { className: 'greeting', children: 'Hello, world!' }, key: null, ref: null };

React核心特性

  • 声明式:描述UI应该是什么样子,而不是如何操作DOM
  • 组件化:将复杂UI拆分为简单、可复用的组件
  • 一次学习,随处编写:React Native、React Server Components等
  • 虚拟DOM:提供性能优化和跨平台能力

React渲染流程

⚠️

理解React的渲染流程对于编写高性能的React应用至关重要。React的渲染过程分为三个主要阶段。

React渲染三阶段

阶段特性主要工作可中断性
Render Phase纯函数,无副作用构建Fiber树、执行组件函数、Diffing✅ 可中断
Commit Phase操作DOMDOM更新、生命周期、useLayoutEffect❌ 不可中断
Passive Effects异步执行useEffect回调✅ 可延迟

更新触发方式

触发方式说明示例
首次渲染组件首次挂载ReactDOM.render()
状态更新setState/useStatesetCount(count + 1)
强制更新跳过shouldComponentUpdateforceUpdate()
父组件更新父组件重新渲染props变化

渲染流程示例

// 渲染流程示例 function Counter() { console.log("1. 组件函数执行"); // Render阶段 const [count, setCount] = useState(0); useLayoutEffect(() => { console.log("3. useLayoutEffect执行"); // Commit阶段 }); useEffect(() => { console.log("4. useEffect执行"); // Passive Effects阶段 }); return ( <div> <p>{count}</p> <button onClick={() => setCount(count + 1)}> 增加 </button> </div> ); } // 执行顺序: // 1. 组件函数执行 (Render) // 2. DOM更新 (Commit) // 3. useLayoutEffect执行 (Commit) // 4. useEffect执行 (Passive Effects)

Fiber架构和调度机制

Fiber架构是React 16引入的重大架构升级,它使React能够实现可中断的渲染和优先级调度。

Fiber架构优势

特性React 15 (Stack)React 16+ (Fiber)优势
渲染方式同步递归可中断渲染避免长时间阻塞
优先级调度支持优先级重要更新优先处理
错误边界有限支持完整支持更好的错误处理
并发特性不支持支持Suspense、并发渲染

Fiber节点结构

// Fiber节点的核心结构 const FiberNode = { // 节点信息 type: null, // 组件类型 key: null, // React key stateNode: null, // DOM节点或组件实例 // 树结构 return: null, // 父节点 child: null, // 第一个子节点 sibling: null, // 兄弟节点 // 状态管理 pendingProps: null, // 新props memoizedProps: null, // 旧props memoizedState: null, // 旧state updateQueue: null, // 更新队列 // 调度相关 lanes: NoLanes, // 优先级 flags: NoFlags, // 副作用标记 alternate: null // 双缓存指针 };

时间切片机制

// 时间切片示例 function workLoopConcurrent() { // 在有剩余时间时继续工作 while (workInProgress !== null && !shouldYield()) { performUnitOfWork(workInProgress); } } function shouldYield() { // 检查是否应该让出控制权 return getCurrentTime() >= deadline; }
#### 优先级调度 | 优先级 | 值 | 使用场景 | 示例 | |--------|----|---------|----- | | **Immediate** | 1 | 立即执行 | 用户输入、focus事件 | | **UserBlocking** | 2 | 用户阻塞 | 点击、滚动、拖拽 | | **Normal** | 3 | 正常优先级 | 网络请求、数据更新 | | **Low** | 4 | 低优先级 | 分析统计、日志 | | **Idle** | 5 | 空闲时执行 | 预加载、缓存清理 | ## Hooks原理和最佳实践 ### Hooks实现原理 <Callout type="warning"> Hooks的实现基于链表结构,这就是为什么Hooks必须在组件顶层调用,不能在条件语句中使用。 </Callout> #### Hooks规则 | 规则 | 说明 | 原因 | 正确示例 | |------|------|------|----------| | **顶层调用** | 只在函数顶层调用Hooks | 保证调用顺序一致 | `const [state, setState] = useState()` | | **React函数中调用** | 只在React函数组件或自定义Hook中调用 | 确保在React上下文中 | 函数组件、自定义Hook | | **不在循环/条件中** | 不在循环、条件或嵌套函数中调用 | 保证每次渲染调用顺序相同 | 避免`if (condition) useState()` | #### Hooks实现原理 ```javascript // useState简化实现 let hookIndex = 0; let hooks = []; function useState(initialValue) { const currentIndex = hookIndex; // 初始化hook if (hooks[currentIndex] === undefined) { hooks[currentIndex] = { state: initialValue, queue: [] }; } const hook = hooks[currentIndex]; // 处理更新队列 hook.queue.forEach(action => { hook.state = typeof action === 'function' ? action(hook.state) : action; }); hook.queue = []; const setState = (action) => { hook.queue.push(action); rerender(); // 触发重新渲染 }; hookIndex++; return [hook.state, setState]; } // useEffect简化实现 function useEffect(callback, deps) { const currentIndex = hookIndex; if (hooks[currentIndex] === undefined) { hooks[currentIndex] = { callback, deps, cleanup: null }; hooks[currentIndex].cleanup = callback(); // 首次执行 } else { const hook = hooks[currentIndex]; // 检查依赖变化 const depsChanged = deps ? !deps.every((dep, i) => dep === hook.deps[i]) : true; if (depsChanged) { if (hook.cleanup) hook.cleanup(); // 清理 hook.cleanup = callback(); // 执行新副作用 hook.deps = deps; } } hookIndex++; }

常用Hooks对比

Hook用途返回值使用场景
useState状态管理[state, setState]组件内部状态
useEffect副作用处理undefined数据获取、订阅、DOM操作
useContext上下文消费contextValue跨组件数据传递
useReducer复杂状态管理[state, dispatch]复杂状态逻辑
useMemo值缓存memoizedValue昂贵计算优化
useCallback函数缓存memoizedCallback函数引用优化

自定义Hooks最佳实践

常用自定义Hooks

Hook名称功能返回值使用场景
useLocalStorage本地存储同步[value, setValue]用户偏好设置
useDebounce防抖处理debouncedValue搜索输入
useAsync异步状态管理{data, loading, error}API调用
useToggle布尔值切换[value, toggle]开关状态

自定义Hooks示例

// 1. useLocalStorage - 本地存储Hook function useLocalStorage(key, initialValue) { const [storedValue, setStoredValue] = useState(() => { try { const item = window.localStorage.getItem(key); return item ? JSON.parse(item) : initialValue; } catch (error) { return initialValue; } }); const setValue = useCallback((value) => { try { const valueToStore = value instanceof Function ? value(storedValue) : value; setStoredValue(valueToStore); window.localStorage.setItem(key, JSON.stringify(valueToStore)); } catch (error) { console.error(`Error setting localStorage:`, error); } }, [key, storedValue]); return [storedValue, setValue]; } // 2. useDebounce - 防抖Hook function useDebounce(value, delay) { const [debouncedValue, setDebouncedValue] = useState(value); useEffect(() => { const handler = setTimeout(() => setDebouncedValue(value), delay); return () => clearTimeout(handler); }, [value, delay]); return debouncedValue; } // 3. useAsync - 异步状态管理Hook function useAsync(asyncFunction, dependencies = []) { const [state, setState] = useState({ data: null, loading: false, error: null }); useEffect(() => { let cancelled = false; setState({ data: null, loading: true, error: null }); asyncFunction() .then(data => !cancelled && setState({ data, loading: false, error: null })) .catch(error => !cancelled && setState({ data: null, loading: false, error })); return () => { cancelled = true; }; }, dependencies); return state; }

自定义Hooks设计原则

  • 单一职责:每个Hook只负责一个功能
  • 可复用性:设计通用的参数接口
  • 错误处理:提供完善的错误处理机制
  • 性能优化:使用useMemo和useCallback优化性能
  • 清理资源:在useEffect中正确清理副作用

状态管理方案对比

React内置状态管理

useState vs useReducer

特性useStateuseReducer适用场景
复杂度简单复杂useState适合简单状态,useReducer适合复杂状态逻辑
状态更新直接设置通过actionuseReducer更适合多种状态变更方式
可预测性一般useReducer的状态变更更可预测
调试简单容易追踪useReducer便于调试状态变更

Redux vs Zustand vs Jotai

// 1. Redux + Redux Toolkit import { createSlice, configureStore } from '@reduxjs/toolkit'; const counterSlice = createSlice({ name: 'counter', initialState: { value: 0 }, reducers: { increment: (state) => { state.value += 1; }, decrement: (state) => { state.value -= 1; }, incrementByAmount: (state, action) => { state.value += action.payload; } } }); const store = configureStore({ reducer: { counter: counterSlice.reducer } }); // 2. Zustand import { create } from 'zustand'; const useCounterStore = create((set) => ({ count: 0, increment: () => set((state) => ({ count: state.count + 1 })), decrement: () => set((state) => ({ count: state.count - 1 })), reset: () => set({ count: 0 }) })); // 3. Jotai import { atom, useAtom } from 'jotai'; const countAtom = atom(0); const doubleCountAtom = atom((get) => get(countAtom) * 2); function JotaiCounter() { const [count, setCount] = useAtom(countAtom); const [doubleCount] = useAtom(doubleCountAtom); return ( <div> <span>Count: {count}</span> <span>Double: {doubleCount}</span> <button onClick={() => setCount(c => c + 1)}>+</button> </div> ); }

状态管理方案选择指南

方案适用场景优点缺点
Redux大型复杂应用可预测、调试工具强大样板代码多、学习曲线陡
Zustand中小型应用轻量、API简单生态相对较小
Jotai需要细粒度控制原子化、避免不必要重渲染概念相对新颖
Context简单全局状态React内置、无需依赖性能问题、不适合频繁更新

React性能优化

组件优化技巧

// 1. React.memo - 组件记忆化 const ExpensiveComponent = React.memo(({ data, onUpdate }) => { console.log('ExpensiveComponent 重新渲染'); return ( <div> {data.map(item => ( <div key={item.id}>{item.name}</div> ))} </div> ); }, (prevProps, nextProps) => { // 自定义比较函数 return prevProps.data.length === nextProps.data.length && prevProps.onUpdate === nextProps.onUpdate; }); // 2. useMemo - 值记忆化 function DataProcessor({ items, filter }) { const expensiveValue = useMemo(() => { console.log('计算昂贵的值'); return items .filter(item => item.category === filter) .reduce((sum, item) => sum + item.value, 0); }, [items, filter]); return <div>总计: {expensiveValue}</div>; } // 3. useCallback - 函数记忆化 function ParentComponent() { const [count, setCount] = useState(0); const [name, setName] = useState(''); // 没有useCallback,每次渲染都会创建新函数 const handleClick = useCallback(() => { console.log('按钮被点击'); }, []); // 空依赖数组,函数永远不会改变 const handleNameChange = useCallback((newName) => { setName(newName); }, []); // 使用函数式更新,避免依赖name return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(c => c + 1)}>增加</button> <ExpensiveChild onClick={handleClick} onNameChange={handleNameChange} /> </div> ); } // 4. 代码分割和懒加载 const LazyComponent = React.lazy(() => import('./LazyComponent')); function App() { return ( <div> <Suspense fallback={<div>加载中...</div>}> <LazyComponent /> </Suspense> </div> ); } // 5. 虚拟滚动 function VirtualList({ items, itemHeight = 50 }) { const [scrollTop, setScrollTop] = useState(0); const containerHeight = 400; const visibleCount = Math.ceil(containerHeight / itemHeight); const startIndex = Math.floor(scrollTop / itemHeight); const endIndex = Math.min(startIndex + visibleCount, items.length); const visibleItems = items.slice(startIndex, endIndex); return ( <div style={{ height: containerHeight, overflow: 'auto' }} onScroll={(e) => setScrollTop(e.target.scrollTop)} > <div style={{ height: items.length * itemHeight, position: 'relative' }}> {visibleItems.map((item, index) => ( <div key={startIndex + index} style={{ position: 'absolute', top: (startIndex + index) * itemHeight, height: itemHeight, width: '100%' }} > {item.name} </div> ))} </div> </div> ); }

React生态工具链

React拥有丰富的生态系统,包括开发工具、状态管理、路由、测试等各个方面的解决方案。

开发工具

# Create React App - 官方脚手架 npx create-react-app my-app cd my-app npm start # Vite + React - 现代构建工具 npm create vite@latest my-react-app -- --template react cd my-react-app npm install npm run dev # Next.js - 全栈React框架 npx create-next-app@latest my-next-app cd my-next-app npm run dev

状态管理工具

// Redux Toolkit - 现代Redux import { createSlice, configureStore } from '@reduxjs/toolkit'; const counterSlice = createSlice({ name: 'counter', initialState: { value: 0 }, reducers: { increment: (state) => { state.value += 1; }, decrement: (state) => { state.value -= 1; } } }); export const { increment, decrement } = counterSlice.actions; export const store = configureStore({ reducer: { counter: counterSlice.reducer } }); // Zustand - 轻量级状态管理 import { create } from 'zustand'; const useStore = create((set) => ({ count: 0, increment: () => set((state) => ({ count: state.count + 1 })), decrement: () => set((state) => ({ count: state.count - 1 })) }));

路由管理

// React Router v6 import { BrowserRouter, Routes, Route, Link } from 'react-router-dom'; function App() { return ( <BrowserRouter> <nav> <Link to="/">Home</Link> <Link to="/about">About</Link> <Link to="/contact">Contact</Link> </nav> <Routes> <Route path="/" element={<Home />} /> <Route path="/about" element={<About />} /> <Route path="/contact" element={<Contact />} /> <Route path="/users/:id" element={<UserProfile />} /> </Routes> </BrowserRouter> ); }

UI组件库

// Ant Design import { Button, Table, Form, Input } from 'antd'; function MyComponent() { return ( <Form> <Form.Item label="用户名" name="username"> <Input /> </Form.Item> <Button type="primary" htmlType="submit"> 提交 </Button> </Form> ); } // Material-UI (MUI) import { Button, TextField, Box } from '@mui/material'; function MyComponent() { return ( <Box component="form"> <TextField label="用户名" variant="outlined" /> <Button variant="contained" color="primary"> 提交 </Button> </Box> ); }

测试工具

// Jest + React Testing Library import { render, screen, fireEvent } from '@testing-library/react'; import '@testing-library/jest-dom'; import Counter from './Counter'; test('renders counter and increments', () => { render(<Counter />); const counter = screen.getByText(/count: 0/i); expect(counter).toBeInTheDocument(); const button = screen.getByRole('button', { name: /increment/i }); fireEvent.click(button); expect(screen.getByText(/count: 1/i)).toBeInTheDocument(); }); // Cypress E2E测试 describe('Counter App', () => { it('should increment counter', () => { cy.visit('/'); cy.contains('Count: 0'); cy.get('[data-testid="increment-button"]').click(); cy.contains('Count: 1'); }); });

理解React的核心原理和Fiber架构是成为React高级开发者的关键。这些知识将帮助你编写更高效、更可维护的React应用。


📚 参考学习资料

📖 官方文档

🎓 优质教程

🛠️ 实践项目

🔧 开发工具

📝 深入阅读

💡 学习建议:建议从官方文档开始,通过Create React App创建项目实践,然后深入学习Hooks和性能优化,最后了解Fiber架构原理。

Last updated on