finyx_data_frontend/docs/代码转换快速参考.md

565 lines
8.2 KiB
Markdown

# React 到 Vue 代码转换快速参考
## 🔄 常用转换模式
### 1. 组件定义
#### React
```typescript
import React from 'react';
interface Props {
title: string;
count: number;
}
export const Component: React.FC<Props> = ({ title, count }) => {
return <div>{title}: {count}</div>;
};
```
#### Vue 3
```vue
<template>
<div>{{ title }}: {{ count }}</div>
</template>
<script setup lang="ts">
interface Props {
title: string;
count: number;
}
defineProps<Props>();
</script>
```
---
### 2. 状态管理
#### React useState
```typescript
const [count, setCount] = useState(0);
const [user, setUser] = useState({ name: '', age: 0 });
setCount(5);
setUser({ ...user, name: 'John' });
```
#### Vue ref
```typescript
const count = ref(0);
const user = ref({ name: '', age: 0 });
count.value = 5;
user.value.name = 'John';
```
#### Vue reactive (对象)
```typescript
const user = reactive({ name: '', age: 0 });
user.name = 'John'; // 不需要 .value
```
---
### 3. 副作用处理
#### React useEffect
```typescript
useEffect(() => {
// 副作用逻辑
return () => {
// 清理逻辑
};
}, [dependency]);
```
#### Vue watchEffect
```typescript
watchEffect(() => {
// 副作用逻辑
return () => {
// 清理逻辑
};
});
```
#### Vue watch
```typescript
watch(() => dependency, (newVal, oldVal) => {
// 副作用逻辑
}, { immediate: true });
```
---
### 4. 计算属性
#### React useMemo
```typescript
const doubled = useMemo(() => {
return count * 2;
}, [count]);
```
#### Vue computed
```typescript
const doubled = computed(() => {
return count.value * 2;
});
```
---
### 5. 条件渲染
#### React
```tsx
{isVisible && <Component />}
{condition ? <A /> : <B />}
{items.length > 0 && items.map(item => <Item key={item.id} />)}
```
#### Vue
```vue
<Component v-if="isVisible" />
<A v-if="condition" />
<B v-else />
<Item v-for="item in items" :key="item.id" v-if="items.length > 0" />
```
---
### 6. 事件处理
#### React
```tsx
<button onClick={handleClick}>Click</button>
<input onChange={(e) => setValue(e.target.value)} />
<form onSubmit={handleSubmit}>
```
#### Vue
```vue
<button @click="handleClick">Click</button>
<input @change="handleChange" v-model="value" />
<form @submit.prevent="handleSubmit">
```
---
### 7. 双向绑定
#### React
```tsx
<input
value={value}
onChange={(e) => setValue(e.target.value)}
/>
```
#### Vue
```vue
<input v-model="value" />
```
---
### 8. 样式绑定
#### React
```tsx
<div className={`base ${isActive ? 'active' : ''}`}>
<div className={cn('base', { active: isActive })}>
<div style={{ width: `${percent}%` }}>
```
#### Vue
```vue
<div :class="['base', { active: isActive }]">
<div :class="{ base: true, active: isActive }">
<div :style="{ width: `${percent}%` }">
```
---
### 9. 列表渲染
#### React
```tsx
{items.map(item => (
<Item key={item.id} data={item} />
))}
```
#### Vue
```vue
<Item
v-for="item in items"
:key="item.id"
:data="item"
/>
```
---
### 10. 组件通信
#### React Props
```tsx
<ChildComponent
prop1={value1}
prop2={value2}
onClick={handleClick}
/>
```
#### Vue Props & Emits
```vue
<ChildComponent
:prop1="value1"
:prop2="value2"
@click="handleClick"
/>
```
---
### 11. Context API
#### React Context
```typescript
const Context = createContext();
const value = useContext(Context);
```
#### Vue provide/inject
```typescript
// 提供
provide(key, value);
// 注入
const value = inject(key);
```
#### Pinia Store (推荐)
```typescript
// store
export const useStore = defineStore('store', () => {
const state = ref(0);
return { state };
});
// 使用
const store = useStore();
store.state;
```
---
### 12. 生命周期
#### React
```typescript
useEffect(() => {
// componentDidMount
return () => {
// componentWillUnmount
};
}, []);
useEffect(() => {
// componentDidUpdate
}, [dependency]);
```
#### Vue
```typescript
onMounted(() => {
// 组件挂载后
});
onUnmounted(() => {
// 组件卸载前
});
onUpdated(() => {
// 组件更新后
});
```
---
### 13. 表单处理
#### React
```tsx
const [form, setForm] = useState({ name: '', email: '' });
<input
value={form.name}
onChange={(e) => setForm({ ...form, name: e.target.value })}
/>
```
#### Vue
```vue
<script setup>
const form = reactive({ name: '', email: '' });
</script>
<template>
<input v-model="form.name" />
</template>
```
---
### 14. 条件类名
#### React
```tsx
<div className={cn(
'base-class',
{ 'active': isActive, 'disabled': isDisabled }
)}>
```
#### Vue
```vue
<div :class="[
'base-class',
{ active: isActive, disabled: isDisabled }
]">
```
---
### 15. 动态属性
#### React
```tsx
<div {...props}>
<img src={imageSrc} alt={altText} />
```
#### Vue
```vue
<div v-bind="props">
<img :src="imageSrc" :alt="altText" />
```
---
### 16. 插槽 (Slots)
#### React
```tsx
function Layout({ children }) {
return <div>{children}</div>;
}
```
#### Vue
```vue
<template>
<div>
<slot />
</div>
</template>
```
#### 具名插槽
```vue
<!-- 父组件 -->
<Layout>
<template #header>Header</template>
<template #default>Content</template>
<template #footer>Footer</template>
</Layout>
<!-- 子组件 -->
<template>
<div>
<slot name="header" />
<slot />
<slot name="footer" />
</div>
</template>
```
---
### 17. 图标使用
#### React (lucide-react)
```tsx
import { FileJson, Terminal } from 'lucide-react';
<FileJson size={20} />
<Terminal size={20} className="text-blue-500" />
```
#### Vue (lucide-vue-next)
```vue
<script setup>
import { FileJson, Terminal } from 'lucide-vue-next';
</script>
<template>
<FileJson :size="20" />
<Terminal :size="20" class="text-blue-500" />
</template>
```
---
### 18. 异步数据获取
#### React
```typescript
const [data, setData] = useState(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
setLoading(true);
fetchData().then(result => {
setData(result);
setLoading(false);
});
}, []);
```
#### Vue
```typescript
const data = ref(null);
const loading = ref(false);
onMounted(async () => {
loading.value = true;
data.value = await fetchData();
loading.value = false;
});
```
---
### 19. 防抖/节流
#### React
```typescript
const debouncedSearch = useMemo(
() => debounce((value) => {
// 搜索逻辑
}, 300),
[]
);
```
#### Vue (使用 @vueuse/core)
```typescript
import { useDebounceFn } from '@vueuse/core';
const debouncedSearch = useDebounceFn((value) => {
// 搜索逻辑
}, 300);
```
---
### 20. 组件引用
#### React useRef
```tsx
const inputRef = useRef<HTMLInputElement>(null);
<input ref={inputRef} />
inputRef.current?.focus();
```
#### Vue ref
```vue
<template>
<input ref="inputRef" />
</template>
<script setup>
const inputRef = ref<HTMLInputElement | null>(null);
onMounted(() => {
inputRef.value?.focus();
});
</script>
```
---
## 📝 常见陷阱
### 1. ref 值访问
```typescript
// ❌ 错误
const count = ref(0);
console.log(count); // RefImpl 对象
// ✅ 正确
const count = ref(0);
console.log(count.value); // 0
```
### 2. 响应式对象
```typescript
// ❌ 错误 - 解构会失去响应性
const { name } = user;
// ✅ 正确 - 使用 toRefs
const { name } = toRefs(user);
```
### 3. 数组更新
```typescript
// React
setItems([...items, newItem]);
// Vue
items.value.push(newItem);
// 或
items.value = [...items.value, newItem];
```
### 4. 对象更新
```typescript
// React
setUser({ ...user, name: 'John' });
// Vue (ref)
user.value = { ...user.value, name: 'John' };
// Vue (reactive)
user.name = 'John'; // 直接修改
```
---
## 🎯 最佳实践
1. **优先使用 `ref` 处理基本类型,`reactive` 处理对象**
2. **使用 `computed` 而不是 `watch` 处理派生状态**
3. **使用 `watchEffect` 处理副作用,`watch` 处理特定依赖**
4. **使用 Pinia 管理全局状态,而不是 provide/inject**
5. **使用 `<script setup>` 语法,更简洁**
6. **合理使用 `v-model` 处理表单双向绑定**
7. **使用 `defineProps` 和 `defineEmits` 定义组件接口**
---
## 📚 参考资源
- [Vue 3 官方文档](https://vuejs.org/)
- [Vue 3 Composition API](https://vuejs.org/guide/extras/composition-api-faq.html)
- [Pinia 文档](https://pinia.vuejs.org/)
- [VueUse 工具库](https://vueuse.org/)