当前位置: 首页 > news >正文

20. JSX 支持

20. JSX 支持1. 概述TypeScript 提供了对 JSX 语法的原生支持允许在 TypeScript 文件中编写 JSX/TSX 代码。JSX 是一种 JavaScript 的语法扩展主要用于 React 等框架中描述用户界面。┌─────────────────────────────────────────────────────────────┐ │ TypeScript JSX 系统 │ ├─────────────────────────────────────────────────────────────┤ │ │ │ 文件类型 │ │ ├── .tsx包含 JSX 的 TypeScript 文件 │ │ └── .ts不含 JSX 的 TypeScript 文件 │ │ │ │ 配置选项 │ │ ├── jsx控制 JSX 输出格式 │ │ ├── jsxFactory指定工厂函数 │ │ ├── jsxFragmentFactory指定片段工厂函数 │ │ └── jsxImportSource指定 JSX 导入源 │ │ │ │ JSX 模式 │ │ ├── preserve保留 JSX 原样 │ │ ├── react转换为 React.createElement │ │ ├── react-jsx使用 JSX 转换React 17 │ │ ├── react-jsxdev开发模式 JSX 转换 │ │ └── react-native保留 JSX用于 React Native │ │ │ └─────────────────────────────────────────────────────────────┘2. 启用 JSX2.1 文件扩展名.tsx用于包含 JSX 语法的 TypeScript 文件.ts不含 JSX 的普通 TypeScript 文件2.2 tsconfig.json 配置{compilerOptions:{jsx:react-jsx,jsxFactory:React.createElement,jsxFragmentFactory:React.Fragment,jsxImportSource:react}}3. JSX 模式详解3.1 preserve 模式保留 JSX 原样不进行转换。{compilerOptions:{jsx:preserve}}// 输入 const element divHello/div; // 输出保持不变 const element divHello/div;3.2 react 模式转换为React.createElement调用。{compilerOptions:{jsx:react}}// 输入 const element div classNamecontainerHello/div; // 输出 const element React.createElement(div, { className: container }, Hello);3.3 react-jsx 模式React 17使用新的 JSX 转换无需显式导入 React。{compilerOptions:{jsx:react-jsx}}// 输入 const element divHello/div; // 输出 import { jsx as _jsx } from react/jsx-runtime; const element _jsx(div, { children: Hello });3.4 react-native 模式保留 JSX 原样用于 React Native。{compilerOptions:{jsx:react-native}}4. JSX 类型定义4.1 基本类型// 组件 Props 类型定义 interface ButtonProps { children?: React.ReactNode; onClick?: () void; disabled?: boolean; variant?: primary | secondary | danger; } // 函数组件 const Button: React.FCButtonProps ({ children, onClick, disabled, variant primary }) { return ( button onClick{onClick} disabled{disabled} className{btn btn-${variant}} {children} /button ); }; // 使用 const App () ( div Button variantprimary onClick{() console.log(clicked)} Click Me /Button /div );4.2 事件类型import { ChangeEvent, MouseEvent, FormEvent } from react; interface FormProps { onSubmit: (data: FormData) void; } const FormComponent: React.FCFormProps ({ onSubmit }) { const handleSubmit (e: FormEventHTMLFormElement) { e.preventDefault(); const formData new FormData(e.currentTarget); onSubmit(formData); }; const handleChange (e: ChangeEventHTMLInputElement) { console.log(e.target.value); }; const handleClick (e: MouseEventHTMLButtonElement) { console.log(Clicked at (${e.clientX}, ${e.clientY})); }; return ( form onSubmit{handleSubmit} input typetext nameusername onChange{handleChange} / input typeemail nameemail onChange{handleChange} / button typesubmit onClick{handleClick} Submit /button /form ); };4.3 Ref 类型import { useRef, useEffect, RefObject } from react; interface InputProps { inputRef?: RefObjectHTMLInputElement; autoFocus?: boolean; } const InputComponent: React.FCInputProps ({ inputRef, autoFocus }) { const internalRef useRefHTMLInputElement(null); const ref inputRef || internalRef; useEffect(() { if (autoFocus ref.current) { ref.current.focus(); } }, [autoFocus, ref]); return input ref{ref} typetext /; }; // 使用 forwardRef const FancyInput React.forwardRefHTMLInputElement, InputProps((props, ref) ( input ref{ref} classNamefancy {...props} / ));5. 泛型组件// 泛型组件 interface ListPropsT { items: T[]; renderItem: (item: T, index: number) React.ReactNode; keyExtractor?: (item: T) string | number; } function ListT({ items, renderItem, keyExtractor }: ListPropsT) { return ( ul {items.map((item, index) ( li key{keyExtractor ? keyExtractor(item) : index} {renderItem(item, index)} /li ))} /ul ); } // 使用 interface User { id: number; name: string; } const users: User[] [ { id: 1, name: Alice }, { id: 2, name: Bob } ]; const UserList () ( ListUser items{users} keyExtractor{(user) user.id} renderItem{(user) span{user.name}/span} / );6. 高阶组件类型// HOC 类型定义 interface WithLoadingProps { isLoading: boolean; } function withLoadingP extends WithLoadingProps( WrappedComponent: React.ComponentTypeP ) { return function WithLoadingComponent( props: OmitP, keyof WithLoadingProps ) { const [isLoading, setIsLoading] useState(false); if (isLoading) { return divLoading.../div; } return WrappedComponent {...(props as P)} isLoading{isLoading} /; }; } interface DataComponentProps extends WithLoadingProps { data: string[]; } const DataComponent: React.FCDataComponentProps ({ data, isLoading }) ( div {isLoading ? Loading... : data.join(, )} /div ); const EnhancedComponent withLoading(DataComponent);7. 上下文类型import { createContext, useContext } from react; // 定义上下文类型 interface ThemeContextType { theme: light | dark; toggleTheme: () void; } const ThemeContext createContextThemeContextType | undefined(undefined); // Provider 组件 const ThemeProvider: React.FC{ children: React.ReactNode } ({ children }) { const [theme, setTheme] useStatelight | dark(light); const toggleTheme () { setTheme(prev prev light ? dark : light); }; return ( ThemeContext.Provider value{{ theme, toggleTheme }} {children} /ThemeContext.Provider ); }; // 自定义 Hook const useTheme () { const context useContext(ThemeContext); if (!context) { throw new Error(useTheme must be used within ThemeProvider); } return context; }; // 使用 const ThemedButton: React.FC () { const { theme, toggleTheme } useTheme(); return ( button onClick{toggleTheme} style{{ background: theme light ? #fff : #333, color: theme light ? #333 : #fff }} Current theme: {theme} /button ); };8. 完整示例Todo 应用import React, { useState, useRef, FormEvent, ChangeEvent } from react; // 类型定义 interface Todo { id: number; text: string; completed: boolean; createdAt: Date; } type FilterType all | active | completed; // 组件定义 const TodoInput: React.FC{ onAdd: (text: string) void } ({ onAdd }) { const [text, setText] useState(); const inputRef useRefHTMLInputElement(null); const handleSubmit (e: FormEvent) { e.preventDefault(); if (text.trim()) { onAdd(text.trim()); setText(); inputRef.current?.focus(); } }; const handleChange (e: ChangeEventHTMLInputElement) { setText(e.target.value); }; return ( form onSubmit{handleSubmit} classNametodo-form input ref{inputRef} typetext value{text} onChange{handleChange} placeholderAdd a new todo... classNametodo-input / button typesubmit classNametodo-add-btn Add /button /form ); }; const TodoItem: React.FC{ todo: Todo; onToggle: (id: number) void; onDelete: (id: number) void; } ({ todo, onToggle, onDelete }) { const [isEditing, setIsEditing] useState(false); const [editText, setEditText] useState(todo.text); const handleSave () { if (editText.trim()) { // 保存逻辑 } setIsEditing(false); }; if (isEditing) { return ( li classNametodo-item editing input typetext value{editText} onChange{(e) setEditText(e.target.value)} onBlur{handleSave} onKeyDown{(e) e.key Enter handleSave()} autoFocus / /li ); } return ( li className{todo-item ${todo.completed ? completed : }} input typecheckbox checked{todo.completed} onChange{() onToggle(todo.id)} / span onDoubleClick{() setIsEditing(true)} {todo.text} /span button onClick{() onDelete(todo.id)}Delete/button /li ); }; const TodoFilter: React.FC{ filter: FilterType; onFilterChange: (filter: FilterType) void; } ({ filter, onFilterChange }) { const filters: { value: FilterType; label: string }[] [ { value: all, label: All }, { value: active, label: Active }, { value: completed, label: Completed } ]; return ( div classNametodo-filter {filters.map(f ( button key{f.value} className{filter f.value ? active : } onClick{() onFilterChange(f.value)} {f.label} /button ))} /div ); }; // 主组件 const TodoApp: React.FC () { const [todos, setTodos] useStateTodo[]([ { id: 1, text: Learn TypeScript, completed: false, createdAt: new Date() }, { id: 2, text: Build a React app, completed: false, createdAt: new Date() } ]); const [filter, setFilter] useStateFilterType(all); const addTodo (text: string) { const newTodo: Todo { id: Date.now(), text, completed: false, createdAt: new Date() }; setTodos([...todos, newTodo]); }; const toggleTodo (id: number) { setTodos(todos.map(todo todo.id id ? { ...todo, completed: !todo.completed } : todo )); }; const deleteTodo (id: number) { setTodos(todos.filter(todo todo.id ! id)); }; const filteredTodos todos.filter(todo { if (filter active) return !todo.completed; if (filter completed) return todo.completed; return true; }); return ( div classNametodo-app h1Todo App/h1 TodoInput onAdd{addTodo} / TodoFilter filter{filter} onFilterChange{setFilter} / ul classNametodo-list {filteredTodos.map(todo ( TodoItem key{todo.id} todo{todo} onToggle{toggleTodo} onDelete{deleteTodo} / ))} /ul div classNametodo-stats {todos.filter(t !t.completed).length} items left /div /div ); }; export default TodoApp;9. 总结配置值说明jsxreactReact.createElementjsxreact-jsx新版 JSX 转换jsxpreserve保留 JSXjsxreact-native保留 JSXRNjsxFactory函数名自定义工厂函数jsxFragmentFactory函数名片段工厂函数jsxImportSource模块名JSX 导入源
http://www.zskr.cn/news/1360113.html

相关文章:

  • 微电网协调控制柜 vs 传统配电柜:本质差异与代际跨越
  • 用 MapleSim 卷绕和卷材加工仿真库加速智能制造与电池产线优化
  • ngx_http_find_virtual_server
  • 清除缓存,释放C盘
  • Taotoken 的 API Key 权限管理与审计日志功能在安全开发中的价值
  • 游戏NPC不再脚本化!Unity+LangChain Agent实时剧情生成技术,上线72小时用户时长↑43%
  • 自定义中间件限流limit
  • 酒店客控系统十大品牌2026排行-技术路线与选型建议
  • 分享一个Python爬虫的小技巧
  • 面部美化 API 集成指南
  • 蒲公英R300重磅升级!串口数据采集与MQTT上云一步到位!
  • RadexMarkets瑞德克斯:到账时效与影响因素的客观说明
  • 接口性能优化实战:从 5 秒到 50ms,我做了这 6 件事
  • AI智能体应用工程师报名流程拆解:学习、考试、证书查询一次说清 - 精选教育培训热点
  • 终极游戏库管理器Playnite:一站式管理20+平台游戏的最佳解决方案
  • 当Windows 11变得臃肿时:如何用开源工具Win11Debloat重获系统控制权
  • 高效解决PostgreSQL镜像拉取难题:DaoCloud镜像同步实战深度解析
  • python智慧乡村治理平台系统
  • PlugOS: 重构移动安全——让安全系统与智能手机硬件解耦
  • 《男人来自火星,女人来自金星4:生活篇》第10-12章深度解读:性别化饮食、体型密码与自我治愈终极指南
  • P4777 【模板】扩展中国剩余定理(EXCRT)题解
  • 2026年5月诚信的阻燃电缆沟盖板厂家,免费样品测试助力客户精准选型适配项目 - 品牌鉴赏师
  • 淘宝闪购官宣招募服务商:5大模式开启餐饮数字化新红利
  • 【广东专升本】2026广东专升本真题PDF+备考资料汇总|政治英语+专业基础课+专业综合课+模拟卷
  • 内网离线部署RPA:打包EXE+本地激活+数据零上云方案
  • Codex CLI 接 Gemini 3.5 Flash 实测:代码生成、推理速度、价格三维度横评(2026)
  • 苗带识别导向的水田管理机直线辅助驾驶系统【附程序】
  • 解决连接蓝牙音箱默认音量100%的问题
  • 深夜办公不掉链:2026免费PDF转PPT工具Top榜 - 时讯资讯
  • 题解:luogu P8996([CEOI 2022] Abracadabra)