跟着双越老师的划水AI项目学习记录,从Vue转向React+Next.js的踩坑经验分享。
核心工具快速了解
UI相关库
- lucide-react:1000+矢量图标,即取即用
- shadcn/ui:零依赖组件库,代码复制到项目完全可控
- @radix-ui:shadcn/ui底层依赖,提供无障碍基础组件
样式工具
- class-variance-authority (CVA):管理组件变体样式
- tailwind-merge:智能合并Tailwind类名,解决冲突
- clsx:条件性组合类名的微型工具
tsx
复制代码
import { twMerge } from 'tailwind-merge';
import clsx from 'clsx';
// 结合使用,处理复杂样式场景
function Button({ variant, size, className, children, ...props }) {
return (
<button
className={twMerge(
clsx(
'inline-flex items-center justify-center rounded-md font-medium',
{
'bg-blue-600 text-white': variant === 'primary',
'bg-gray-200 text-gray-800': variant === 'secondary',
'h-9 px-3 text-sm': size === 'sm',
'h-10 px-4 text-base': size === 'md',
},
className // 外部传入的样式会正确覆盖默认样式
)
)}
{...props}
>
{children}
</button>
);
}
功能库
- Next.js:全栈React框架,文件系统路由
- next-themes:主题切换(暗色/亮色模式)
- react-resizable-panels:可拖拽调整的面板布局
- react-hook-form:高性能表单处理和验证
- ...
Vue vs React 核心差异
1. 快速适应技巧
- 从"指令"到"表达式" :
v-if
→ {condition && <div/>}
- 从"双向绑定"到"单向数据流":手动控制状态更新
- 从"选项式"到"函数式":一切都是函数和Hook
2. 常用Hook对照
Vue Composition API |
React Hook |
ref() |
useState() |
computed() |
useMemo() |
watch() |
useEffect() |
onMounted() |
useEffect([], []) |
3. Next.js特色功能
- 服务器组件:默认在服务器渲染,性能更好
- 客户端组件 :添加
'use client'
才能使用浏览器API
- 文件路由 :
app/work/[id]/page.tsx
= /work/123
4.具体代码对比
1. 组件结构
vue
复制代码
<!-- Vue:三段式分离 -->
<template>
<div>{{ title }}</div>
</template>
<script>
const title = ref('标题')
</script>
<style scoped>
.title { color: red; }
</style>
tsx
复制代码
// React:JSX一体化
export default function Component() {
const [title, setTitle] = useState('标题');
return <div className="text-red-500">{title}</div>;
}
2. 数据绑定
Vue |
React |
{{ message }} |
{message} |
v-model="input" |
value={input} onChange={setInput} |
@click="handle" |
onClick={handle} |
v-if="show" |
{show && <div/>} |
v-for="item in list" |
{list.map(item => <div/>)} |
3. 状态管理
vue
复制代码
<!-- Vue -->
<script setup>
const count = ref(0);
const user = reactive({ name: '张三' });
</script>
tsx
复制代码
// React
const [count, setCount] = useState(0);
const [user, setUser] = useState({ name: '张三' });
// 更新对象需要展开
setUser(prev => ({ ...prev, age: 20 }));
4. 路由参数获取
js
复制代码
// Vue Router
const id = this.$route.params.id;
tsx
复制代码
// Next.js 15 - 服务器组件
export default async function Page({ params }) {
const { id } = await params;
return <div>项目 {id}</div>;
}
// Next.js 15 - 客户端组件
'use client';
import { useParams } from 'next/navigation';
const params = useParams();
5. 条件样式处理
vue
复制代码
<!-- Vue -->
<div :class="{ active: isActive, error: hasError }">内容</div>
tsx
复制代码
// React - 使用 clsx
import clsx from 'clsx';
<div className={clsx('base-style', {
'active': isActive,
'error': hasError
})}>内容</div>
// React - 使用 CVA(组件变体)
import { cva } from 'class-variance-authority';
const cardVariants = cva('p-4 rounded', {
variants: {
variant: {
default: 'bg-white',
primary: 'bg-blue-500 text-white'
}
}
});
<div className={cardVariants({ variant: 'primary' })}>卡片</div>
6. 生命周期
js
复制代码
// Vue
onMounted(() => {})
onUpdated(() => {})
onUnmounted(() => {})
tsx
复制代码
// React
useEffect(() => {
// 挂载后执行
return () => {
// 卸载时清理
};
}, []); // 空数组表示只执行一次
7. 表单处理
vue
复制代码
<!-- Vue -->
<input v-model="email" />
<input v-model="password" type="password" />
tsx
复制代码
// React - 原生方式
const [email, setEmail] = useState('');
<input value={email} onChange={(e) => setEmail(e.target.value)} />
// React - 使用 react-hook-form(推荐)
import { useForm } from 'react-hook-form';
const { register, handleSubmit } = useForm();
<input {...register('email', { required: '邮箱必填' })} />