【react】TypeScript在react中的使用

目录

一、环境与项目配置

1. 创建 TypeScript React 项目

2. 关键tsconfig.json配置

3.安装核心类型包

二、组件类型定义

 1. 函数组件(React 18+)

2.类组件

三、Hooks 的深度类型集成

 1. useState

 2. useEffect

 3. useRef

4. 自定义 Hook

四、事件处理

1. 表单事件

2. 鼠标/键盘事件

五、状态管理(Redux Toolkit)

1.定义类型化的 Slice

2. 类型化的useSelector和useDispatch(组件中使用)

六、路由(React Router v6)

七、类型扩展与最佳实践

1. 扩展全局类型

2. 组件默认 Props

3. 泛型组件

4.高阶组件(HOC)类型

5.Context API类型安全

八、测试与调试

1. Jest + Testing Library

2.类型安全的Mock数据

九、常见问题

1. 如何处理第三方库类型?

2.处理动态导入(Lazy Loading )

3. 类型断言的使用

3. 处理可选 Props

4、性能优化

1.使用react.memo 优化渲染

2.类型化的useCallback和useMemo

十一、学习资源


一、环境与项目配置

1. 创建 TypeScript React 项目

# 使用 Create React App(推荐)

npx create-react-app my-app --template typescript

# 或使用 Vite(更轻量)

npm create vite@latest my-react-app -- --template react-ts
2. 关键tsconfig.json配置
{"compilerOptions": {"target": "ESNext","lib": ["DOM", "DOM.Iterable", "ESNext"], // 浏览器环境支持"jsx": "react-jsx",                      // React 17+ 的 JSX 转换"strict": true,                          // 启用所有严格类型检查"esModuleInterop": true,                  // 兼容 CommonJS/ES6 模块"skipLibCheck": true,                     // 跳过第三方库类型检查(提升速度)"forceConsistentCasingInFileNames": true, // 强制文件名大小写一致"baseUrl": "./src",                       // 路径别名基础目录"paths": {"@components/*": ["components/*"]       // 路径别名配置}},"include": ["src/**/*"]
}
3.安装核心类型包
npm install @types/react @types/react-dom @types/node --save-dev

二、组件类型定义

 1. 函数组件(React 18+)
// Button.tsx
import React from 'react';// 定义 Props 类型
interface ButtonProps {children: React.ReactNode;onClick: () => void;variant?: 'primary' | 'secondary';//可选属性disabled?: boolean;//可选回调函数
}//使用React.FC 泛型定义组件( React 18 后 FC 不再隐式包含 children)
const Button: React.FC<ButtonProps> = ({ children, onClick, variant = 'primary', //默认值disabled = false 
}) => {return (<button className={`btn-${variant}`}onClick={onClick}disabled={disabled}>{children}</button>);
};export default Button;
2.类组件
// Counter.tsx
import React from 'react';//State和Props类型定义
interface CounterProps {initialCount?: number;
}interface CounterState {count: number;
}class Counter extends React.Component<CounterProps, CounterState> {// 默认 Propsstatic defaultProps: Partial<CounterProps> = {initialCount: 0};// 初始化 State(需明确类型)state: CounterState = {count: this.props.initialCount!};// 箭头函数绑定 this(避免手动 bind)increment = () => {this.setState((prev) => ({ count: prev.count + 1 }));};render() {return (<div><p>Count: {this.state.count}</p><button onClick={this.increment}>Increment</button></div>);}
}

三、Hooks 的深度类型集成

 1. useState
//react
//const [count, setCount] = React.useState<number>(0); // 显式指定类型
//const [user, setUser] = React.useState<User | null>(null); // 联合类型// 基础类型推断
const [count, setCount] = useState<number>(0);// 复杂对象类型(明确初始值)
interface User {id: string;name: string;email?: string;
}const [user, setUser] = useState<User>({id: '1',name: 'Alice'
});
 2. useEffect
// 异步请求的类型安全处理
useEffect(() => {let isMounted = true; // 防止组件卸载后更新状态const fetchData = async () => {try {const response = await fetch('/api/users');const data: User[] = await response.json();if (isMounted) setUsers(data);} catch (error) {console.error('Fetch error:', error);}};fetchData();return () => {isMounted = false;};
}, []);
 3. useRef
// DOM 引用
const inputRef = useRef<HTMLInputElement>(null);
// 可变值(非 DOM)
// 引用 DOM 元素
const inputRef = useRef<HTMLInputElement>(null);// 存储可变值(非 DOM)
interface Timer {id: number;start: () => void;
}const timerRef = useRef<Timer | null>(null);
4. 自定义 Hook
// useLocalStorage.ts
import { useState, useEffect } from 'react';function useLocalStorage<T>(key: string,initialValue: T
): [T, (value: T) => void] {const [storedValue, setStoredValue] = useState<T>(() => {try {const item = window.localStorage.getItem(key);return item ? JSON.parse(item) : initialValue;} catch (error) {return initialValue;}});const setValue = (value: T) => {try {setStoredValue(value);window.localStorage.setItem(key, JSON.stringify(value));} catch (error) {console.error('LocalStorage set error:', error);}};useEffect(() => {const handleStorageChange = (e: StorageEvent) => {if (e.key === key) {setStoredValue(JSON.parse(e.newValue!));}};window.addEventListener('storage', handleStorageChange);return () => window.removeEventListener('storage', handleStorageChange);}, [key]);return [storedValue, setValue];
}// 使用
const [theme, setTheme] = useLocalStorage<'light' | 'dark'>('theme', 'light');

四、事件处理

1. 表单事件
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {e.preventDefault();// 访问表单元素const input = e.currentTarget.elements.namedItem('username') as HTMLInputElement;console.log(input.value);
};
2. 鼠标/键盘事件
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {console.log(e.clientX, e.clientY);
};
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {if (e.key === 'Enter') {// 处理回车}
};

五、状态管理(Redux Toolkit)

1.定义类型化的 Slice
// features/counter/counterSlice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';interface Todo {id:string;text: string ;value: number;
}
interface TodosState {list: Todo[];status: 'idle' | 'loading' | 'succeeded' | 'failef';const initialState: TodosState = {list: [];status: 'idle'
};const counterSlice = createSlice({name: 'tods',initialState,reducers: {addTodo: (state, action: PayloadAction<{ text: string }>) => {const newTodo: Todo = {id: Date.now().toString(),text: action.payload.text,completed: false};state.list.push(newTodo);},toggleTodo: (state, action: PayloadAction<string>) => {const todo = state.list.find(t => t.id === action.payload);if (todo) todo.completed = !todo.completed;}},extraReducers: (builder) => {// 异步处理示例builder.addCase(fetchTodos.pending, (state) => {state.status = 'loading';}).addCase(fetchTodos.fulfilled, (state, action: PayloadAction<Todo[]>) => {state.status = 'succeeded';state.list = action.payload;});}
});export const {addTodo, toggleTodo} = counterSlice.actions;
export default todoSlice.reducer;
2. 类型化的useSelector和useDispatch(组件中使用)
// Counter.tsx
import { useDispatch, useSelector } from 'react-redux';
import type { RootState } from '@/app/store';
import { increment } from '@/features/counter/counterSlice';const Counter = () => {const count = useSelector((state: RootState) => state.counter.value);const dispatch = useDispatch();return (<div><span>{count}</span><button onClick={() => dispatch(increment())}>+1</button></div>);
};

六、路由(React Router v6)

// App.tsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';interface RouteConfig {path: string;element: React.ReactNode;
}const routes: RouteConfig[] = [{ path: '/', element: <HomePage /> },{ path: '/about', element: <AboutPage /> }
];const App = () => (<BrowserRouter><Routes>{routes.map((route) => (<Route key={route.path} {...route} />))}</Routes></BrowserRouter>
);

七、类型扩展与最佳实践

1. 扩展全局类型
// react-app-env.d.ts
declare namespace React {interface HTMLAttributes<T> extends AriaAttributes, DOMAttributes<T> {// 扩展自定义属性customAttr?: string;}
}
2. 组件默认 Props
interface Props {size?: 'small' | 'medium' | 'large';
}const MyComponent = ({ size = 'medium' }: Props) => {// ...
};
3. 泛型组件
interface ListProps<T> {items: T[];renderItem: (item: T) => React.ReactNode;
}
function List<T>({ items, renderItem }: ListProps<T>) {return (<div>{items.map((item, index) => (<div key={index}>{renderItem(item)}</div>))}</div>);
}// 使用
<List<{ id: string; name: string }> items={users}renderItem={(user) => <span>{user.name}</span>}
/>
4.高阶组件(HOC)类型
type WithLoadingProps = {isLoading: boolean;
};// 高阶组件:为组件添加 loading 状态
function withLoading<T extends object>(WrappedComponent: React.ComponentType<T>
) {return (props: T & WithLoadingProps) => {if (props.isLoading) return <div>Loading...</div>;return <WrappedComponent {...props} />;};
}// 使用
const UserListWithLoading = withLoading(UserList);
<UserListWithLoading isLoading={true} users={[]} />;
5.Context API类型安全
// ThemeContext.tsx
import React, { createContext, useContext } from 'react';type Theme = 'light' | 'dark';
type ThemeContextType = {theme: Theme;toggleTheme: () => void;
};const ThemeContext = createContext<ThemeContextType | undefined>(undefined);export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {const [theme, setTheme] = useState<Theme>('light');const toggleTheme = () => {setTheme((prev) => (prev === 'light' ? 'dark' : 'light'));};return (<ThemeContext.Provider value={{ theme, toggleTheme }}>{children}</ThemeContext.Provider>);
};// 自定义 Hook 确保 Context 存在
export const useTheme = () => {const context = useContext(ThemeContext);if (!context) throw new Error('useTheme must be used within ThemeProvider');return context;
};

八、测试与调试

1. Jest + Testing Library
// Button.test.tsx
import { render, screen, fireEvent } from '@testing-library/react';
import Button from './Button';test('handles click event', () => {const handleClick = jest.fn();render(<Button onClick={handleClick}>Click Me</Button>);fireEvent.click(screen.getByText(/click me/i));expect(handleClick).toHaveBeenCalledTimes(1);
});// 测试异步操作
test('loads user data', async () => {render(<UserProfile userId="1" />);await waitFor(() => {expect(screen.getByText('Alice')).toBeInTheDocument();});
});
2.类型安全的Mock数据
// mocks/user.ts
import { User } from '../types';export const mockUser: User = {id: '1',name: 'Alice',email: 'alice@example.com'
};// 测试中使用
jest.mock('../api', () => ({fetchUser: jest.fn().mockResolvedValue(mockUser)
}));

九、常见问题

1. 如何处理第三方库类型?
npm install @types/react-router-dom @types/lodash # 安装类型声明# 安装社区维护的类型包
npm install @types/lodash @types/react-select --save-dev# 临时忽略类型检查(不推荐)
// @ts-ignore
import untypedLib from 'untyped-lib';
2.处理动态导入(Lazy Loading )
// 明确组件类型
const LazyComponent = React.lazy(() => import('./LazyComponent'));// 使用 Suspense
<Suspense fallback={<div>Loading...</div>}><LazyComponent />
</Suspense>
3. 类型断言的使用
//例a
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {const value = e.target.value as string; // 明确类型//例b 
const element = document.getElementById('root') as HTMLElement; // 安全断言
const data = response as ApiResponse; // 明确知道类型时
3. 处理可选 Props
interface AvatarProps {src: string;alt?: string; // 可选属性size?: number;
}const Avatar = ({ src, alt = '', size = 40 }: AvatarProps) => (<img src={src} alt={alt} width={size} />
);
4、性能优化
1.使用react.memo 优化渲染
interface MemoizedComponentProps {data: string[];
}const MemoizedComponent = React.memo<MemoizedComponentProps>(({ data }) => {// 复杂计算return <div>{data.join(', ')}</div>;
});
2.类型化的useCallback和useMemo
const memoizedCallback = useCallback((id: string) => {console.log('Callback called with:', id);},[] // 依赖项数组
);const memoizedValue = useMemo(() => {return computeExpensiveValue(a, b);
}, [a, b]); // 依赖项变化时重新计算

十一、学习资源

  1. React TypeScript Cheatsheet

  2. DefinitelyTyped(第三方库类型)

  3. TypeScript 官方文档

码字不易,各位大佬点点赞呗

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/24834.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL注入练习

目录 一、如何绕过 information schema 字段过滤注入 二、如何绕过 order by 语句过滤注入 三、seacmsv9 实现报错注入数据 一、如何绕过 information schema 字段过滤注入 1、使用其他系统表&#xff0c;不同数据库有各自的系统表&#xff0c;可替代information_schema。 …

手机放兜里,支付宝“碰一下”被盗刷?

大家好&#xff0c;我是小悟。 近期&#xff0c;网络上关于“支付宝‘碰一下’支付易被盗刷”的传言甚嚣尘上&#xff0c;不少用户对此心生疑虑。 首先&#xff0c;要明确一点&#xff1a;“碰一下”支付并不会像某些传言中所描述的那样容易被隔空盗刷。这一观点已经得到了支付…

MySQL MHA 部署全攻略:从零搭建高可用数据库架构

文章目录 1.MHA介绍2.MHA组件介绍3.集群规划4.服务器初始化5.MySQL集群部署5.1 安装MySQL集群5.2 配置一主两从5.3 测试MySQL主从5.4 赋予MHA用户连接权限 6.安装MHA环境6.1 安装MHA Node6.2 安装MHA Manager 7.配置MHA环境8.MySQL MHA高可用集群测试8.1 通过VIP连接MySQL8.2模…

国标28181协议在智联视频超融合平台中的接入方法

一. 国标28181介绍 国标 28181 协议全称是《安全防范视频监控联网系统信息传输、交换、控制技术要求》&#xff0c;是国内视频行业最重要的国家标准&#xff0c;目前有三个版本&#xff1a; 2011 年&#xff1a;推出 GB/T 28181-2011 版本&#xff0c;为安防行业的前端设备、平…

ThinkPHP:配置Redis并使用

文章目录 一、环境说明二、php.ini中配置Redis扩展1、下载php_redis.dll文件2、安装Redis扩展3、修改php.ini4、重启wamp服务 三、thinkphp6项目中修改配置及使用 一、环境说明 我的是64位Windows10环境&#xff0c;安装了wamp环境集成工具&#xff0c;方便学习使用。 php版本…

[ComfyUI]官方已支持Skyreels混元图生视频,速度更快,效果更好(附工作流)

一、介绍 昨天有提到官方已经支持了Skyreels&#xff0c;皆大欢喜&#xff0c;效果更好一些&#xff0c;还有GGUF量化版本&#xff0c;进一步降低了大家的显存消耗。 今天就来分享一下官方流怎么搭建&#xff0c;我体验下来感觉更稳了一些&#xff0c;生成速度也更快&#xf…

ui设计公司兰亭妙微分享:科研单位UI界面设计

科研单位的UI界面设计是一项至关重要的任务&#xff0c;它不仅关乎科研工作的效率&#xff0c;还直接影响到科研人员的用户体验。以下是对科研单位UI界面设计的详细分析&#xff1a; 一、设计目标 科研单位的UI界面设计旨在提升科研工作的效率与便捷性&#xff0c;同时确保科…

纷析云:赋能企业财务数字化转型的开源解决方案

在企业数字化转型的浪潮中&#xff0c;财务管理的高效与安全成为关键。纷析云凭借其开源、安全、灵活的财务软件解决方案&#xff0c;为企业提供了一条理想的转型路径。 一、开源的力量&#xff1a;自主、安全、高效 纷析云的核心优势在于其100%开源的财务软件源码。这意味着…

Win11安装dpanel实现docker可视化面板,并解决端口冲突的问题

目标是给Win11的docker安装dpanel可视化面板&#xff0c;可以更直观的看到docker中的数据。 执行镜像&#xff08;没有则自动拉取&#xff09; 首先配置好docker加速环境&#xff08;阿里云的docker加速等&#xff09;&#xff0c;然后访问GitHub - donknap/dpanel: 轻量化 do…

Jmeter聚合报告导出log文档,Jmeter聚合报告导出到CSV

Jmeter聚合报告导出log文档 在Filename中输入 EKS_perf_log\\${type}_log\\${__P(UNIQUEID,${__time(YMDHMS)})}\all-graph-results-log.csv 可以得到执行的log&#xff0c;文件夹包含时间戳 Jmeter聚合报告导出到CSV 点击Save Table Data&#xff0c;保存到CSV文件中

OpenAPI Generator:API开发的瑞士军刀

一、工具介绍 OpenAPI Generator是基于OpenAPI规范(Swagger)的代码生成工具&#xff0c;支持50种编程语言的客户端/服务端代码生成。其核心价值在于&#xff1a; 自动化生成⇒减少重复劳动规范API开发流程 核心能力矩阵&#xff1a; 功能支持示例客户端SDK生成Java/Python/T…

【Linux探索学习】第二十七弹——信号(上):Linux 信号基础详解

Linux学习笔记&#xff1a; https://blog.csdn.net/2301_80220607/category_12805278.html?spm1001.2014.3001.5482 前言&#xff1a; 前面我们已经将进程通信部分讲完了&#xff0c;现在我们来讲一个进程部分也非常重要的知识点——信号&#xff0c;信号也是进程间通信的一…

DeepSeek行业应用实践报告-智灵动力【112页PPT全】

DeepSeek&#xff08;深度搜索&#xff09;近期引发广泛关注并成为众多企业/开发者争相接入的现象&#xff0c;主要源于其在技术突破、市场需求适配性及生态建设等方面的综合优势。以下是关键原因分析&#xff1a; 一、技术核心优势 开源与低成本 DeepSeek基于开源架构&#xf…

探索AI新前沿,CoT推理赋能文生图!港中文首次提出文生图的o1推理和inference scaling新范式

OpenAI的o1模型凭借思维链&#xff08;Chain-of-Thought, CoT&#xff09;技术&#xff0c;在推理能力上实现了质的飞跃&#xff0c;引领了大模型理解领域的新风尚。然而&#xff0c;这一创新的火花能否照亮图像生成领域&#xff1f;近日&#xff0c;来自香港中文大学、北京大学…

C# | GDI+图像测距辅助线的实现思路

C# | GDI图像测距辅助线的实现思路 文章目录 C# | GDI图像测距辅助线的实现思路一、辅助线需求概述二、坐标系与角度计算2.1 笛卡尔坐标系2.2 线长和角度计算方法2.3 文本角度矫正计算方法2.4 坐标变换实现步骤 三、与if判断方式对比四、总结 一、辅助线需求概述 在图像测量工…

SQL Server2019下载及安装教程

一、软件下载 SQLServer2019及SSMS管理工具下载链接&#xff1a; 百度网盘 请输入提取码 二、SQLServer2019安装 选中要安装的iso映像文件&#xff0c;右键点击装载&#xff08;有些系统可以直接双击打开&#xff0c;有些需要安装Daemon Tools软件去打开&#xff09; 找到s…

嵌入式开发--STM32的USB不识别和需要重新拔插的解决

STM32在通过USB口设备连接电脑时&#xff0c;一般是将其模拟为虚拟串口&#xff08;VCP&#xff09;。如果在调试中按了复位键&#xff0c;就不能连接电脑了。此时一般需要拔插一下USB口&#xff0c;但这样会给用户带来许多麻烦。 USB接口电路 电路接口中&#xff0c;USB-P线会…

深度剖析数据中台架构图,铸造数字文明的基石

🔥🔥 AllData大数据产品是可定义数据中台,以数据平台为底座,以数据中台为桥梁,以机器学习平台为中层框架,以大模型应用为上游产品,提供全链路数字化解决方案。 ✨奥零数据科技官网:http://www.aolingdata.com ✨AllData开源项目:https://github.com/alldatacenter/a…

MySQL练习

将安装包下载并上传 方法一 步骤 创建组与用户 [rootlocalhost ~]# groupadd mysql [rootlocalhost ~]# useradd -r -g mysql -s /bin/false mysql 解压安装包 [rootlocalhost ~]# tar xf mysql-8.0.36-linux-glibc2.28-x86_64.tar.xz -C /usr/local/软连接 [rootlocalh…

jdk21下载、安装(Windows、Linux、macOS)

Windows 系统 1. 下载安装 访问 Oracle 官方 JDK 下载页面 或 OpenJDK 下载页面&#xff0c;根据自己的系统选择合适的 Windows 版本进行下载&#xff08;通常选择 .msi 安装包&#xff09;。 2. 配置环境变量 右键点击 “此电脑”&#xff0c;选择 “属性”。 在左侧导航栏…