前端技术栈全家桶:React+Vue+TypeScript开发实战指南
最近在多个项目中深入实践了React、Vue和TypeScript的协同用法,积累了不少值得分享的实战经验。很多前端开发者通过后台询问:这三大前端工具到底该如何搭配?TypeScript在实际项目中怎么落地?——本文就来系统性地拆解这些核心问题。
前端技术栈迭代速度确实很快,React 19刚刚发布、Vue 3.4也迎来更新、TypeScript 5.x又增加了新特性,但它们的底层逻辑已经趋于稳定。把核心原理掌握透彻了,学习任何新框架都会事半功倍。

一、为什么需要前端技术栈全家桶?
不少开发者可能会疑惑:学好一个框架不就够用了吗?为什么还要掌握React+Vue+TypeScript三件套?这里有几个现实场景会让答案变得清晰:
- 公司技术栈切换:今天公司用Vue,明天被收购后可能迁移到React,不会对应框架就会陷入被动。
- 开源项目贡献:GitHub上优质项目React和Vue各占半壁江山,只会一个就等于少了一半的参与机会。
- 技术选型能力:只有都深入了解过,才能在架构设计时做出最优的技术决策。
- TypeScript成为刚需:2024年的今天,不用TypeScript的前端项目确实越来越罕见。
掌握这三种技术的核心用法与最佳实践,已成为进阶前端工程师的必修课程。
二、TypeScript:前端开发的基石与保障
2.1 为什么TypeScript如此重要?
TypeScript不再是"可选的加分项",而是"必须掌握的核心基本功"。
// 没有TS的时候,这种bug可能要运行时才发现
function calculateTotal(price: number, quantity: number): number {
return price * quantity;
}
// 有了TS,类型错误在写代码的时候就能捕获
interface Product {
id: string;
name: string;
price: number;
stock: number;
tags?: string[]; // 可选属性
}
// 定义一个购物车项的类型
interface CartItem {
product: Product;
quantity: number;
discount?: number;
}
// 类型安全的购物车计算
class ShoppingCart {
private items: CartItem[] = [];
addItem(product: Product, quantity: number, discount?: number): void {
if (quantity <= 0) {
throw new Error("数量必须大于0");
}
if (product.stock < quantity) {
throw new Error(`库存不足!当前库存:${product.stock}`);
}
this.items.push({ product, quantity, discount });
}
getTotal(): number {
return this.items.reduce((total, item) => {
const itemTotal = item.product.price * item.quantity;
const discount = item.discount || 0;
return total + itemTotal * (1 - discount);
}, 0);
}
getSummary(): { totalItems: number; totalPrice: number } {
return {
totalItems: this.items.reduce((sum, item) => sum + item.quantity, 0),
totalPrice: this.getTotal(),
};
}
}
2.2 泛型实战:编写可复用的工具函数
泛型在前端项目中应用非常广泛,来看一个实际开发场景:
// 通用的API请求封装
interface ApiResponse {
code: number;
message: string;
data: T;
timestamp: number;
}
// 通用的分页数据结构
interface PaginatedData {
list: T[];
total: number;
page: number;
pageSize: number;
}
// 泛型请求函数
async function fetchApi(url: string, options?: RequestInit): Promise> {
const response = await fetch(url, {
headers: {
'Content-Type': 'application/json',
...options?.headers,
},
...options,
});
if (!response.ok) {
throw new Error(`请求失败: ${response.status}`);
}
return response.json();
}
// 使用示例
interface User {
id: string;
name: string;
email: string;
a vatar: string;
}
// 类型安全的数据获取
const userData = await fetchApi('/api/users');
const paginatedUsers = await fetchApi>('/api/users?page=1');
有了泛型,API请求的类型安全就有了坚实保障,再也不用 any 到处飞了。
三、React实战:组件化开发的艺术
3.1 React 19 + TypeScript 项目搭建
先用Vite快速搭建一个现代化的React项目。
# 使用Vite创建React+TS项目
npm create vite@latest my-react-app -- --template react-ts
cd my-react-app
npm install
npm run dev
3.2 自定义Hook:封装业务逻辑
React最强大的特性之一就是自定义Hook,可以把复杂逻辑优雅地抽离出来。
// useFetch.ts - 通用数据请求Hook
import { useState, useEffect, useCallback } from 'react';
interface UseFetchState {
data: T | null;
loading: boolean;
error: string | null;
}
interface UseFetchReturn extends UseFetchState {
refetch: () => void;
}
function useFetch(url: string): UseFetchReturn {
const [state, setState] = useState>({
data: null,
loading: true,
error: null,
});
const fetchData = useCallback(async () => {
setState(prev => ({ ...prev, loading: true, error: null }));
try {
const response = await fetch(url);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data: T = await response.json();
setState({ data, loading: false, error: null });
} catch (err) {
setState({
data: null,
loading: false,
error: err instanceof Error ? err.message : '未知错误',
});
}
}, [url]);
useEffect(() => {
fetchData();
}, [fetchData]);
return { ...state, refetch: fetchData };
}
// 使用示例:用户列表组件
function UserList() {
const { data: users, loading, error, refetch } = useFetch('/api/users');
if (loading) return 加载中...
;
if (error) return 出错了: {error}
;
return (
用户列表
{users?.map(user => (
-
{user.name}
{user.email}
))}
);
}
3.3 组件设计模式:复合组件
接下来介绍一种高级但非常实用的模式——复合组件模式。
// Card复合组件
interface CardProps {
children: React.ReactNode;
className?: string;
}
function Card({ children, className = '' }: CardProps) {
return {children}
;
}
Card.Header = function Header({ children, title }: { children?: React.ReactNode; title: string }) {
return (
{title}
{children}
);
};
Card.Body = function Body({ children }: { children: React.ReactNode }) {
return {children}
;
};
Card.Footer = function Footer({ children }: { children: React.ReactNode }) {
return {children}
;
};
// 使用起来非常优雅
function UserProfile() {
return (
姓名:张三
职位:前端工程师
);
}
四、Vue 3实战:优雅的响应式编程
4.1 Vue 3 + TypeScript组合式API
再来看看Vue 3的写法。
# 使用Vite创建Vue3+TS项目
npm create vite@latest my-vue-app -- --template vue-ts
cd my-vue-app
npm install
npm run dev
4.2 组合式函数(Composables)
Vue 3的Composables和React的Custom Hooks有异曲同工之妙,但写法上更为优雅简洁。
// composables/useCounter.ts
import { ref, computed } from 'vue';
export function useCounter(initialValue: number = 0) {
const count = ref(initialValue);
const doubleCount = computed(() => count.value * 2);
const isEven = computed(() => count.value % 2 === 0);
function increment(): void {
count.value++;
}
function decrement(): void {
count.value--;
}
function reset(): void {
count.value = initialValue;
}
function incrementBy(amount: number): void {
count.value += amount;
}
return {
count,
doubleCount,
isEven,
increment,
decrement,
reset,
incrementBy,
};
}
计数器
{{ count }}
双倍值:{{ doubleCount }}
{{ isEven ? '偶数' : '奇数' }}
4.3 Pinia状态管理实战
Vue 3官方推荐的状态管理方案Pinia,用起来确实非常丝滑。
// stores/userStore.ts
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
interface User {
id: string;
name: string;
email: string;
role: 'admin' | 'user' | 'guest';
}
export const useUserStore = defineStore('user', () => {
const users = ref([]);
const currentUser = ref(null);
const loading = ref(false);
const adminUsers = computed(() =>
users.value.filter(user => user.role === 'admin')
);
const totalUsers = computed(() => users.value.length);
const isLoggedIn = computed(() => currentUser.value !== null);
async function fetchUsers(): Promise {
loading.value = true;
try {
const response = await fetch('/api/users');
users.value = await response.json();
} finally {
loading.value = false;
}
}
function login(user: User): void {
currentUser.value = user;
localStorage.setItem('currentUser', JSON.stringify(user));
}
function logout(): void {
currentUser.value = null;
localStorage.removeItem('currentUser');
}
return {
users, currentUser, loading,
adminUsers, totalUsers, isLoggedIn,
fetchUsers, login, logout,
};
});
五、React vs Vue:如何选择?
很多开发者最纠结的问题:到底选React还是Vue?这里直接给出详细的对比分析。
| 对比维度 | React | Vue |
|---|---|---|
| 学习曲线 | 中等偏上 | 较低,上手快 |
| 生态规模 | 超大,社区活跃 | 大,中文生态好 |
| TypeScript支持 | 原生支持,体验好 | Vue 3支持优秀 |
| 状态管理 | Redux/Zustand/Jotai | Pinia(官方推荐) |
| 适用场景 | 大型复杂应用 | 中小型到大型均可 |
| 就业市场 | 需求量大 | 国内需求旺盛 |
几个核心选择建议:新手入门推荐先学Vue,上手快、成就感强;如果想进大厂,React是必备技能;想技术全面的话建议两个都学,先学一个,再学第二个会非常快。
六、实战案例:打造一个Todo App
用React和TypeScript实现一个完整的Todo App来串联所有知识点。
// React + TypeScript 版本的Todo App
import { useState, useCallback, useMemo } from 'react';
interface Todo {
id: string;
text: string;
completed: boolean;
priority: 'low' | 'medium' | 'high';
createdAt: number;
}
type FilterType = 'all' | 'active' | 'completed';
function TodoApp() {
const [todos, setTodos] = useState([]);
const [inputText, setInputText] = useState('');
const [filter, setFilter] = useState('all');
const addTodo = useCallback(() => {
if (!inputText.trim()) return;
const newTodo: Todo = {
id: crypto.randomUUID(),
text: inputText.trim(),
completed: false,
priority: 'medium',
createdAt: Date.now(),
};
setTodos(prev => [newTodo, ...prev]);
setInputText('');
}, [inputText]);
const toggleTodo = useCallback((id: string) => {
setTodos(prev =>
prev.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
)
);
}, []);
const deleteTodo = useCallback((id: string) => {
setTodos(prev => prev.filter(todo => todo.id !== id));
}, []);
const filteredTodos = useMemo(() => {
switch (filter) {
case 'active': return todos.filter(t => !t.completed);
case 'completed': return todos.filter(t => t.completed);
default: return todos;
}
}, [todos, filter]);
const stats = useMemo(() => ({
total: todos.length,
completed: todos.filter(t => t.completed).length,
active: todos.filter(t => !t.completed).length,
}), [todos]);
return (
Todo App
setInputText(e.target.value)}
onKeyDown={e => e.key === 'Enter' && addTodo()}
placeholder="添加新任务..."
/>
{(['all', 'active', 'completed'] as FilterType[]).map(f => (
))}
总计: {stats.total}
已完成: {stats.completed}
进行中: {stats.active}
{filteredTodos.map(todo => (
-
toggleTodo(todo.id)}
/>
{todo.text}
))}
);
}
七、总结与展望
回顾一下几个核心要点:
- TypeScript是前端开发的基石,类型安全能帮助你避免大量潜在bug。
- React的Hooks和组件模式让逻辑复用变得优雅高效。
- Vue 3的组合式API和Pinia提供了简洁流畅的开发体验。
- 两个框架各有优势,两个都学总不会错。
接下来可以尝试的进阶方向:用React+TS重构一个现有项目;用Vue 3写一个完整的CRUD应用;对比两个框架在同一个项目中的不同实现。
