1. JSX/TSX 的本质解析
前端开发者第一次接触 JSX 时,往往会发出灵魂拷问:"这到底是 JavaScript 还是 HTML?" 实际上,JSX 是 JavaScript 的语法扩展(extension),它允许我们在 JavaScript 代码中直接编写类似 HTML 的标记结构。这种设计哲学源于一个核心理念:UI 应该与逻辑紧密结合。
Babel 或 TypeScript 编译器会将 JSX 语法转换为标准的 JavaScript 函数调用。例如下面这段 JSX:
jsx复制const element = <h1 className="title">Hello World</h1>;
会被编译为:
javascript复制const element = React.createElement(
'h1',
{ className: 'title' },
'Hello World'
);
这种转换揭示了 JSX 的三个核心特性:
- 标签名(如 h1)成为 createElement 的第一个参数
- 属性(如 className)被收集到第二个参数对象中
- 子元素作为后续参数传递
关键提示:JSX 不是模板引擎,它最终会被编译为普通的 JavaScript 函数调用,这也是为什么我们能在 JSX 中直接嵌入 JavaScript 表达式。
2. TSX 的类型增强机制
当 JSX 遇上 TypeScript,就诞生了 TSX。TSX 在保留 JSX 所有功能的基础上,通过类型系统为组件开发提供了强大的安全保障。以下是 TSX 的核心类型特性:
2.1 组件 Props 类型检查
通过接口定义组件属性类型:
tsx复制interface ButtonProps {
primary?: boolean;
size?: 'small' | 'medium' | 'large';
onClick?: () => void;
}
const Button: React.FC<ButtonProps> = ({ primary, size, onClick, children }) => {
// 实现...
};
此时如果错误传递属性:
tsx复制<Button priority={true} /> // 错误!应该是 primary 而非 priority
TypeScript 编译器会立即报错,这种即时反馈能防止大量运行时错误。
2.2 子元素类型约束
通过 React.ReactNode 类型可以精确控制子元素:
tsx复制interface CardProps {
title: string;
children: React.ReactNode; // 可以是字符串、JSX、数组等
}
2.3 事件处理类型安全
原生 DOM 事件也能获得完整类型提示:
tsx复制const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
console.log(e.target.value); // 正确推断出 value 属性
};
3. 高级模式与性能优化
3.1 条件渲染模式对比
常见的条件渲染方式及其适用场景:
| 模式 | 示例 | 适用场景 | 注意事项 |
|---|---|---|---|
| 逻辑与 | {isShow && <Modal/>} |
简单条件 | 注意 falsy 值导致的意外渲染 |
| 三元运算 | {isAdmin ? <AdminPanel/> : <UserPanel/>} |
二选一场景 | 嵌套会降低可读性 |
| 立即执行函数 | {(() => { /* 复杂逻辑 */ })()} |
复杂条件 | 影响可读性,慎用 |
| 组件封装 | <ConditionalRender when={cond} then={<A/>} else={<B/>}/> |
多处复用 | 增加组件层级 |
3.2 循环渲染性能关键点
使用 map 进行列表渲染时需要注意:
tsx复制{
items.map(item => (
<ListItem
key={item.id} // 必须提供稳定唯一 key
item={item}
// 避免在渲染函数中绑定事件
onClick={() => handleClick(item.id)} // ❌ 每次渲染都创建新函数
/>
))
}
优化方案:
tsx复制// 事件处理提前定义
const handleItemClick = useCallback((id) => {
/* 处理逻辑 */
}, []);
{
items.map(item => (
<ListItem
key={item.id}
item={item}
onClick={handleItemClick} // ✅ 保持引用稳定
/>
))
}
3.3 样式方案对比
现代 React 项目中常见的样式方案:
-
CSS Modules:
tsx复制import styles from './Button.module.css'; <button className={styles.primary} />- 优点:真正的局部作用域
- 缺点:动态样式处理较麻烦
-
CSS-in-JS (如 styled-components):
tsx复制const StyledButton = styled.button` background: ${props => props.primary ? 'blue' : 'gray'}; `;- 优点:极致灵活
- 缺点:运行时开销
-
Utility-First CSS (如 Tailwind):
tsx复制<button className="px-4 py-2 text-white bg-blue-500 rounded" />- 优点:开发效率高
- 缺点:学习曲线较陡
4. 企业级实践与设计模式
4.1 组件设计原则
-
单一职责原则:每个组件只做一件事
- Bad:
<UserProfileWithActions /> - Good:
<UserProfile /> + <ProfileActions />
- Bad:
-
受控与非受控组件:
- 受控组件:表单数据由 React 状态管理
- 非受控组件:通过 ref 直接访问 DOM
-
复合组件模式:
tsx复制<Tabs> <Tabs.List> <Tabs.Tab>Tab 1</Tabs.Tab> </Tabs.List> <Tabs.Panels> <Tabs.Panel>Content 1</Tabs.Panel> </Tabs.Panels> </Tabs>通过 Context 共享状态,提升组件灵活性
4.2 类型高级技巧
-
泛型组件:
tsx复制interface ListProps<T> { items: T[]; renderItem: (item: T) => React.ReactNode; } function List<T>({ items, renderItem }: ListProps<T>) { return <div>{items.map(renderItem)}</div>; } -
类型工具复用:
tsx复制type OmitKeys<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>; type ButtonProps = OmitKeys<React.ComponentProps<'button'>, 'className'> & { variant?: 'primary' | 'secondary'; }; -
组件类型推导:
tsx复制const createComponent = <T extends {}>(Component: React.FC<T>) => { return Component; }; const MyComp = createComponent(({ name }: { name: string }) => { return <div>{name}</div>; }); // MyComp 自动获得正确的 props 类型
5. 调试与错误处理实战
5.1 常见 TSX 错误类型
-
类型不匹配错误:
tsx复制interface Props { count: number; } const Counter = ({ count }: Props) => { /*...*/ }; <Counter count="5" /> // Error: Type 'string' is not assignable to type 'number' -
必填属性缺失:
tsx复制<UserProfile /> // Error: Property 'userId' is missing -
事件处理错误:
tsx复制const handleClick = (id: number) => { /*...*/ }; <button onClick={handleClick} /> // Error: 参数不匹配
5.2 调试技巧
-
类型检查辅助:
tsx复制// 临时类型检查 const _checkProps: React.ComponentProps<typeof MyComponent> = { // 填入 props 测试类型 }; -
React DevTools 高级用法:
- 使用 "⚛️ Components" 面板检查组件 props
- 使用 "⚛️ Profiler" 分析渲染性能
-
错误边界处理:
tsx复制class ErrorBoundary extends React.Component { state = { hasError: false }; static getDerivedStateFromError() { return { hasError: true }; } render() { if (this.state.hasError) { return <FallbackUI />; } return this.props.children; } }
6. 现代工具链集成
6.1 构建配置要点
以 Vite + TSX 为例的关键配置:
javascript复制// vite.config.js
export default defineConfig({
plugins: [react()],
esbuild: {
jsxInject: `import React from 'react'`, // 自动注入 React
},
});
6.2 ESLint 规则配置
推荐的核心规则:
javascript复制module.exports = {
rules: {
'react/jsx-uses-react': 'error',
'react/jsx-uses-vars': 'error',
'react/jsx-curly-brace-presence': ['error', { props: 'never', children: 'never' }],
'react/jsx-boolean-value': ['error', 'never'],
},
};
6.3 测试策略
-
组件快照测试:
javascript复制test('Button renders correctly', () => { const { container } = render(<Button>Click</Button>); expect(container.firstChild).toMatchSnapshot(); }); -
交互测试:
javascript复制test('calls onClick when clicked', () => { const handleClick = jest.fn(); render(<Button onClick={handleClick} />); userEvent.click(screen.getByRole('button')); expect(handleClick).toHaveBeenCalled(); }); -
类型测试:
typescript复制// 验证类型错误 // @ts-expect-error <Button invalidProp="value" />;
7. 架构演进与最佳实践
7.1 项目结构组织
渐进式结构示例:
code复制/src
/components
/ui # 通用UI组件
/features # 业务功能组件
/hooks # 自定义hooks
/types # 全局类型定义
/utils # 工具函数
/pages # 页面级组件
7.2 状态管理集成
-
Context API 模式:
tsx复制const UserContext = React.createContext<User | null>(null); function useUser() { const user = useContext(UserContext); if (!user) throw new Error('Missing UserProvider'); return user; } -
状态库集成 (以 Zustand 为例):
tsx复制interface StoreState { count: number; increment: () => void; } const useStore = create<StoreState>(set => ({ count: 0, increment: () => set(state => ({ count: state.count + 1 })), })); function Counter() { const { count, increment } = useStore(); return <button onClick={increment}>{count}</button>; }
7.3 性能优化策略
-
代码分割:
tsx复制const HeavyComponent = React.lazy(() => import('./HeavyComponent')); function App() { return ( <Suspense fallback={<Loader />}> <HeavyComponent /> </Suspense> ); } -
虚拟列表优化:
tsx复制<FixedSizeList height={400} width={300} itemSize={50} itemCount={1000} > {({ index, style }) => ( <div style={style}>Item {index}</div> )} </FixedSizeList> -
useMemo 优化:
tsx复制const formattedData = useMemo(() => { return rawData.map(transformData); }, [rawData]);
8. 从 JSX 到 TSX 的迁移指南
8.1 渐进式迁移策略
-
文件重命名:
- 将
.jsx改为.tsx - 在 tsconfig.json 中设置
"allowJs": true
- 将
-
类型逐步增强:
- 第一阶段:添加基本 PropTypes 对应类型
- 第二阶段:增强事件处理类型
- 第三阶段:引入高级类型模式
-
类型检查严格度提升:
json复制{ "compilerOptions": { "strict": true, "noImplicitAny": false // 初始阶段设为 false } }
8.2 常见问题解决
-
第三方库无类型定义:
bash复制
npm install --save-dev @types/library-name或创建
src/types/library-name.d.ts:typescript复制declare module 'library-name'; -
动态属性处理:
tsx复制interface Props { [key: string]: unknown; // 允许任意额外属性 knownProp: string; } -
类组件类型注解:
tsx复制class MyComponent extends React.Component<Props, State> { // 明确指定 props 和 state 类型 }
9. 前沿生态与发展趋势
9.1 JSX 运行时演进
-
经典运行时 (React 16及之前):
- 需要显式导入 React
- 转换结果:
React.createElement()
-
自动运行时 (React 17+):
- 通过
jsx-runtime自动处理 - 转换结果:
_jsx()调用 - 配置方式:
json复制{ "compilerOptions": { "jsx": "react-jsx" } }
- 通过
9.2 服务端组件创新
React Server Components 带来的变化:
tsx复制// 服务端组件 (ServerComponent.tsx)
async function ServerComponent() {
const data = await fetchData(); // 直接在服务端获取数据
return <ClientComponent data={data} />;
}
// 客户端组件 (ClientComponent.tsx)
'use client';
function ClientComponent({ data }) {
const [state, setState] = useState();
// 可以使用状态和效果
return <div>{/* ... */}</div>;
}
9.3 编译时优化方向
-
AST 转换优化:
- 预编译 JSX 为优化后的 JavaScript
- 示例工具:Babel-plugin-transform-react-jsx
-
CSS 提取优化:
- 编译时提取静态 CSS
- 示例:Linaria、Compiled
-
代码生成策略:
- 根据目标环境生成不同代码
- 示例:Vite 的环境区分构建
10. 实战:构建类型安全的表单库
10.1 核心类型设计
typescript复制type FieldValue = string | number | boolean;
interface FormSchema {
[field: string]: {
type: 'text' | 'number' | 'checkbox';
defaultValue: FieldValue;
validator?: (value: FieldValue) => string | null;
};
}
type FormValues<T extends FormSchema> = {
[K in keyof T]: T[K]['defaultValue'];
};
interface FormProps<T extends FormSchema> {
schema: T;
onSubmit: (values: FormValues<T>) => void;
}
10.2 组件实现
tsx复制function Form<T extends FormSchema>({ schema, onSubmit }: FormProps<T>) {
const [values, setValues] = useState<FormValues<T>>(() => {
return Object.fromEntries(
Object.entries(schema).map(([key, config]) => [key, config.defaultValue])
) as FormValues<T>;
});
const handleChange = useCallback((name: keyof T, value: FieldValue) => {
setValues(prev => ({ ...prev, [name]: value }));
}, []);
return (
<form onSubmit={() => onSubmit(values)}>
{Object.entries(schema).map(([name, config]) => (
<Field
key={name}
name={name}
type={config.type}
value={values[name]}
onChange={handleChange}
/>
))}
</form>
);
}
10.3 类型安全验证
使用时获得完整的类型提示:
tsx复制const userFormSchema = {
username: {
type: 'text',
defaultValue: '',
validator: (val) => val.length >= 3 ? null : 'Too short'
},
age: {
type: 'number',
defaultValue: 18
}
} satisfies FormSchema;
<Form
schema={userFormSchema}
onSubmit={(values) => {
// values 自动推断为 { username: string; age: number }
console.log(values.age.toFixed(2)); // 完全类型安全
}}
/>
11. 设计系统集成实践
11.1 主题类型定义
typescript复制interface Theme {
colors: {
primary: string;
secondary: string;
error: string;
};
spacing: (factor: number) => string;
}
const defaultTheme: Theme = {
colors: { /*...*/ },
spacing: (factor) => `${4 * factor}px`
};
const ThemeContext = React.createContext<Theme>(defaultTheme);
11.2 样式组件增强
tsx复制interface StyledProps {
$variant?: 'primary' | 'secondary';
}
const StyledButton = styled.button<StyledProps>`
background: ${({ $variant, theme }) =>
$variant === 'primary'
? theme.colors.primary
: theme.colors.secondary
};
padding: ${({ theme }) => theme.spacing(2)};
`;
11.3 复合组件模式
tsx复制interface MenuProps {
children: React.ReactElement<MenuItemProps>[];
}
const Menu = ({ children }: MenuProps) => {
return <div className="menu">{children}</div>;
};
interface MenuItemProps {
icon?: React.ReactNode;
}
const MenuItem = ({ icon, children }: MenuItemProps) => {
return (
<div className="menu-item">
{icon && <span className="icon">{icon}</span>}
{children}
</div>
);
};
// 使用示例
<Menu>
<MenuItem icon={<HomeIcon />}>Home</MenuItem>
<MenuItem icon={<SettingsIcon />}>Settings</MenuItem>
</Menu>
12. 调试与错误边界进阶
12.1 错误边界增强
tsx复制interface ErrorBoundaryProps {
fallback: React.ReactNode | ((error: Error) => React.ReactNode);
}
interface ErrorBoundaryState {
hasError: boolean;
error?: Error;
}
class ErrorBoundary extends React.Component<
React.PropsWithChildren<ErrorBoundaryProps>,
ErrorBoundaryState
> {
state: ErrorBoundaryState = { hasError: false };
static getDerivedStateFromError(error: Error) {
return { hasError: true, error };
}
componentDidCatch(error: Error, info: React.ErrorInfo) {
logError(error, info.componentStack);
}
render() {
if (this.state.hasError) {
return typeof this.props.fallback === 'function'
? this.props.fallback(this.state.error!)
: this.props.fallback;
}
return this.props.children;
}
}
12.2 开发环境调试工具
-
React Strict Mode:
tsx复制<React.StrictMode> <App /> </React.StrictMode>- 检测不安全的生命周期
- 识别废弃的 API 使用
-
自定义 Hook 调试:
tsx复制function useDebugValue<T>(value: T, format?: (value: T) => any) { React.useDebugValue(value, format); return value; } function useUser() { const user = fetchUser(); return useDebugValue(user, u => u ? `User: ${u.name}` : 'No user'); } -
性能追踪:
tsx复制import { unstable_trace as trace } from 'scheduler/tracing'; function handleClick() { trace('Button click', performance.now(), () => { setState(/*...*/); }); }
13. 测试策略全解析
13.1 单元测试实践
typescript复制// Button.test.tsx
describe('Button', () => {
it('renders with correct text', () => {
render(<Button>Click me</Button>);
expect(screen.getByText('Click me')).toBeInTheDocument();
});
it('calls onClick when clicked', () => {
const handleClick = jest.fn();
render(<Button onClick={handleClick} />);
userEvent.click(screen.getByRole('button'));
expect(handleClick).toHaveBeenCalled();
});
it('has correct type signature', () => {
// 类型测试
const TestComponent = () => (
<>
{/* 正确使用 */}
<Button variant="primary" />
{/* 错误使用 */}
{/* @ts-expect-error */}
<Button variant="invalid" />
</>
);
});
});
13.2 快照测试策略
typescript复制it('renders correctly', () => {
const { asFragment } = render(
<ThemeProvider theme={lightTheme}>
<Button variant="primary">Submit</Button>
</ThemeProvider>
);
expect(asFragment()).toMatchSnapshot();
});
13.3 集成测试示例
typescript复制describe('LoginForm', () => {
it('submits form with valid data', async () => {
const handleSubmit = jest.fn();
render(<LoginForm onSubmit={handleSubmit} />);
await userEvent.type(screen.getByLabelText('Email'), 'test@example.com');
await userEvent.type(screen.getByLabelText('Password'), 'password123');
await userEvent.click(screen.getByRole('button', { name: 'Login' }));
await waitFor(() => {
expect(handleSubmit).toHaveBeenCalledWith({
email: 'test@example.com',
password: 'password123'
});
});
});
});
14. 性能优化深度实践
14.1 渲染性能分析
使用 React Profiler API:
tsx复制function onRenderCallback(
id: string,
phase: 'mount' | 'update',
actualDuration: number,
baseDuration: number,
startTime: number,
commitTime: number,
interactions: Set<Interaction>
) {
console.log(`Component ${id} took ${actualDuration}ms to render`);
}
<React.Profiler id="App" onRender={onRenderCallback}>
<App />
</React.Profiler>
14.2 记忆化优化策略
tsx复制const ExpensiveComponent = React.memo(
({ items, selectedId }: { items: Item[]; selectedId: string }) => {
const selectedItem = useMemo(
() => items.find(item => item.id === selectedId),
[items, selectedId]
);
return <div>{/* 渲染逻辑 */}</div>;
},
(prevProps, nextProps) => {
// 自定义比较函数
return (
prevProps.selectedId === nextProps.selectedId &&
prevProps.items.length === nextProps.items.length
);
}
);
14.3 虚拟化长列表
tsx复制import { FixedSizeList as List } from 'react-window';
const Row = ({ index, style }: { index: number; style: React.CSSProperties }) => (
<div style={style}>Row {index}</div>
);
const VirtualList = () => (
<List
height={500}
width={300}
itemSize={50}
itemCount={1000}
>
{Row}
</List>
);
15. 状态管理深度集成
15.1 Context 性能优化
tsx复制const UserContext = React.createContext<{
user: User;
update: (user: User) => void;
} | null>(null);
function UserProvider({ children }: { children: React.ReactNode }) {
const [user, setUser] = useState<User>(initialUser);
const contextValue = useMemo(() => ({
user,
update: setUser
}), [user]);
return (
<UserContext.Provider value={contextValue}>
{children}
</UserContext.Provider>
);
}
function useUser() {
const context = useContext(UserContext);
if (!context) throw new Error('Missing UserProvider');
return context;
}
15.2 Redux 类型安全
typescript复制// store.ts
interface RootState {
user: UserState;
posts: PostsState;
}
const store = configureStore({
reducer: {
user: userReducer,
posts: postsReducer
}
});
type AppDispatch = typeof store.dispatch;
// hooks.ts
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
// component.tsx
const user = useAppSelector(state => state.user);
const dispatch = useAppDispatch();
dispatch(updateUser({ name: 'New Name' }));
15.3 原子状态管理
使用 Jotai 示例:
tsx复制const countAtom = atom(0);
const doubledAtom = atom(get => get(countAtom) * 2);
function Counter() {
const [count, setCount] = useAtom(countAtom);
const [doubled] = useAtom(doubledAtom);
return (
<div>
<button onClick={() => setCount(c => c + 1)}>Increment</button>
<div>Count: {count}</div>
<div>Doubled: {doubled}</div>
</div>
);
}
16. 服务端渲染进阶
16.1 Next.js 类型增强
typescript复制// next-env.d.ts
/// <reference types="next" />
/// <reference types="next/types/global" />
// 扩展 Page 类型
declare module 'next' {
interface NextPageContext {
isServer?: boolean;
}
}
// pages/index.tsx
const HomePage: NextPage<{ data: ApiData }> = ({ data }) => {
return <div>{/* 使用 data */}</div>;
};
export const getServerSideProps: GetServerSideProps = async () => {
const data = await fetchData();
return { props: { data } };
};
16.2 数据获取策略
-
静态生成 (SSG):
typescript复制export const getStaticProps: GetStaticProps = async () => { const posts = await getPosts(); return { props: { posts } }; }; -
服务端渲染 (SSR):
typescript复制export const getServerSideProps: GetServerSideProps = async (ctx) => { const user = await getUser(ctx.req.cookies.token); return { props: { user } }; }; -
增量静态再生 (ISR):
typescript复制export const getStaticProps: GetStaticProps = async () => { const products = await getProducts(); return { props: { products }, revalidate: 60 // 每60秒重新生成 }; };
16.3 样式处理方案
-
CSS Modules:
tsx复制import styles from './Page.module.css'; function Page() { return <div className={styles.container} />; } -
Styled JSX:
tsx复制function Page() { return ( <div> <style jsx>{` .container { max-width: 1200px; } `}</style> </div> ); } -
全局样式:
tsx复制// pages/_app.tsx import '../styles/globals.css';
17. 微前端架构集成
17.1 模块联邦配置
typescript复制// webpack.config.js
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'app1',
filename: 'remoteEntry.js',
exposes: {
'./Button': './src/components/Button',
},
shared: {
react: { singleton: true },
'react-dom': { singleton: true },
},
}),
],
};
17.2 类型共享策略
-
发布类型包:
bash复制
// 在库项目中 tsc --declaration --emitDeclarationOnly -
类型映射:
json复制// tsconfig.json { "compilerOptions": { "paths": { "@shared/*": ["../shared/src/*"] } } } -
运行时类型验证:
typescript复制import { is } from 'typescript-is'; function consumeData(data: unknown) { if (is<ExpectedType>(data)) { // 安全使用 data } }
17.3 跨应用通信
typescript复制// 事件总线类型
interface EventMap {
'user-logged-in': { userId: string };
'cart-updated': { itemCount: number };
}
class EventBus {
private listeners = new Map<keyof EventMap, Set<Function>>();
on<T extends keyof EventMap>(
event: T,
callback: (payload: EventMap[T]) => void
) {
// 实现...
}
emit<T extends keyof EventMap>(event: T, payload: EventMap[T]) {
// 实现...
}
}
18. 移动端开发适配
18.1 React Native 类型共享
typescript复制// shared/types.ts
interface User {
id: string;
name: string;
}
// React Native 组件
const UserProfile: React.FC<{ user: User }> = ({ user }) => {
return <Text>{user.name}</Text>;
};
// Web 组件
const WebUserProfile: React.FC<{ user: User }> = ({ user }) => {
return <div>{user.name}</div>;
};
18.2 响应式设计模式
tsx复制const useBreakpoint = () => {
const [breakpoint, setBreakpoint] = useState<'mobile' | 'tablet' | 'desktop'>('desktop');
useEffect(() => {
const handleResize = () => {
const width = window.innerWidth;
if (width < 768) setBreakpoint('mobile');
else if (width < 1024) setBreakpoint('tablet');
else setBreakpoint('desktop');
};
handleResize();
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return breakpoint;
};
function ResponsiveComponent() {
const breakpoint = useBreakpoint();
return (
<div>
{breakpoint === 'mobile' && <MobileView />}
{breakpoint === 'tablet' && <TableView />}
{breakpoint === 'desktop' && <DesktopView />}
</div>
);
}
18.3 手势处理集成
tsx复制import { useGesture } from '@use-gesture/react';
function Draggable() {
const [position, setPosition] = useState({ x: 0, y: 0 });
const bind = useGesture({
onDrag: ({ offset: [x, y] }) => {
setPosition({ x, y });
}
});
return (
<div
{...bind()}
style={{
transform: `translate3d(${position.x}px, ${position.y}px, 0)`,
touchAction: 'none'
}}
/>
);
}
19. 可视化与动画实践
19.1 SVG 组件化
tsx复制interface IconProps extends React.SVGProps<SVGSVGElement> {
size?: number;
color?: string;
}
const CircleIcon: React.FC<IconProps> = ({
size = 24,
color = 'currentColor',
...props
}) => {
return (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
stroke={color}
{...props}
>
<circle cx="12" cy="12" r="10" />
</svg>
);
};
19.2 动画性能优化
tsx复制const AnimatedBox = () => {
const ref = useRef<HTMLDivElement>(null);
useLayoutEffect(() => {
const element = ref.current;
if (!element) return;
// 使用 FLIP 动画技术
const first = element.getBoundingClientRect();
// 触发布局变化
element.style.transform = 'translateX(100px)';
const last = element.getBoundingClientRect();
const invert = {
x: first.left - last.left,
y: first.top - last.top
};
const animation = element.animate(
[
{ transform: `translate(${invert.x}px, ${invert.y}px)` },
{ transform: 'translate(0, 0)' }
],
{ duration: 300, easing: 'cubic-bezier(0.25, 0.1, 0.25, 1)' }
);
return () => animation.cancel();
}, []);
return <div ref={ref} className="box" />;
};
19.3 Canvas 集成
tsx复制const Canvas = () => {
const ref = useRef<HTMLCanvasElement>(null);
useEffect(() => {
const canvas = ref.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');
if (!ctx) return;
// 绘制逻辑
ctx.fillStyle = 'red';
ctx.fillRect(10, 10, 50, 50);
// 响应式处理
const handleResize = () => {
canvas.width = canvas.clientWidth * devicePixelRatio;
canvas.height = canvas.clientHeight * devicePixelRatio;
ctx.scale(devicePixelRatio, devicePixelRatio);
};
handleResize();
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return <canvas ref={ref} style={{ width: '100%', height: '100%' }} />;
};
20. 未来趋势与总结思考
20.1 编译时优化方向
-
React Forget (记忆化编译器):
- 自动生成 useMemo/useCallback
- 减少手动优化工作量
-
React Server Components:
- 服务端组件零 bundle 大小
- 自动代码分割