前言
大家好,我是奈德丽。如果你跟我一样,一直以来在项目中只写过Vue,但又想快速上手React,也许这篇文章会帮到你,那么来看一眼我是如何学的吧
我是如何学React的
学习新语言对于很多同学来说有些头疼,但是掌握了方法,其实也不过只是依葫芦画瓢,手到擒来。下面将React与Vue做了一些简单的对比5。
1. 组件定义方式
React 组件定义
js
// 函数组件
export default function App() {
// 状态和逻辑
return (
// JSX 模板
);
}
Vue 组件定义
js
<template>
<!-- HTML 模板 -->
</template>
<script setup lang="ts">
// 组件逻辑
</script>
<style scoped>
/* 组件样式 */
</style>
2. 响应式数据详细对比
React 管理响应式数据
js
// 使用 useState 创建状态
const [list, setList] = useState(toDolist);
const [inputVal, setInputVal] = useState("");
// 更新状态
setList(newList);
setInputVal("");
特点:
- 状态更新是异步的
- 状态更新会触发组件重新渲染
- 每次渲染都会重新执行整个函数组件
- 状态是不可变的,需要创建新对象/数组来更新
Vue管理响应式数据
js
<script setup>
// 使用 ref 创建响应式状态
const list = ref(toDolist);
const inputVal = ref('');
// 更新状态
list.value = newList;
inputVal.value = '';
</script>
特点:
- 基于 Proxy 的响应式系统
- 只有依赖变化的部分会重新渲染
- 可以直接修改 .value 属性
- 支持深层响应式
3. 引用和持久化值
React 的 useRef
js
const curId = useRef(list.length + 1);
const inputRef = useRef(null);
// 访问和修改
curId.current++;
inputRef.current?.focus();
特点:
- 在组件重新渲染时保持值不变
- 修改 .current 不会触发重新渲染
- 可以引用 DOM 元素
js
<script setup>
const curId = ref(list.value.length + 1);
const inputRef = ref(null);
// 访问和修改
curId.value++;
inputRef.value?.focus();
</script>
特点:
- 在 Vue 中,ref 既可以用于响应式数据,也可以引用 DOM 元素
- 修改 .value 会触发依赖更新
- 通过 ref="inputRef" 绑定到模板元素
4. 模板语法对比
React JSX
js
return (
<>
<input
ref={inputRef}
value={inputVal}
onChange={(e) => setInputVal(e.target.value)}
/>
<button onClick={() => handleAdd([...])}>Add</button>
<ul>
{list.map((item) => (
<li key={item.id}>
{item.title}{" "}
<input
type={"checkbox"}
onChange={() => handleDelete(item.id)}
/>
</li>
))}
</ul>
</>
);
特点:
- 使用 JSX 语法,本质上是 JavaScript
- 使用大括号 {} 插入表达式
- 事件处理使用驼峰命名法 onClick
- 列表渲染使用 map() 方法
- 条件渲染使用 && 或三元运算符
- 需要显式指定 key 属性
Vue 模板
js
<template>
<div>
<input
ref="inputRef"
v-model="inputVal"
/>
<button @click="handleAdd">Add</button>
<ul>
<li v-for="item in list" :key="item.id">
{{ item.title }}
<input
type="checkbox"
@change="() => handleDelete(item.id)"
/>
</li>
</ul>
</div>
</template>
特点:
- 使用基于 HTML 的模板语法
- 使用双大括号 {{ }} 插值
- 使用指令如 v-model 、 v-for 、 v-if
- 事件处理使用 @ 前缀
- 属性绑定使用 : 前缀
- 支持双向绑定 v-model
5. 事件处理对比
React 事件处理
js
<input onChange={(e) => setInputVal(e.target.value)} />
<button onClick={() => handleAdd([...])}>Add</button>
特点:
- 使用驼峰命名法
- 传递函数引用
- 事件处理函数接收合成事件对象
- 需要手动处理表单值更新
Vue 事件处理
js
<input v-model="inputVal" />
<button @click="handleAdd">Add</button>
特点:
- 使用 @ 前缀( @click 是 v-on:click 的语法糖)
- 可以直接调用方法或内联表达式
- v-model 提供双向绑定,简化表单处理
6. 生命周期对比
React 生命周期(Hooks)
js
import { useEffect } from 'react';
// 组件挂载
useEffect(() => {
inputRef.current?.focus();
}, []);
// 监听特定值变化
useEffect(() => {
console.log('list changed:', list);
}, [list]);
// 组件卸载
useEffect(() => {
return () => {
console.log('component unmounted');
};
}, []);
Vue 生命周期(组合式 API)
js
<script setup>
import { onMounted, onUnmounted, watch } from 'vue';
// 组件挂载
onMounted(() => {
inputRef.value?.focus();
});
// 监听特定值变化
watch(list, (newList) => {
console.log('list changed:', newList);
});
// 组件卸载
onUnmounted(() => {
console.log('component unmounted');
});
</script>
7.性能优化对比
React 性能优化
js
import { memo, useCallback, useMemo } from 'react';
// 避免不必要的重新渲染
const MemoizedItem = memo(TodoItem);
// 缓存回调函数
const handleDelete = useCallback((id) => {
// ...
}, [list]);
// 缓存计算结果
const completedItems = useMemo(() => {
return list.filter(item => item.completed);
}, [list]);
8. 渲染机制对比
React 渲染机制
- 使用虚拟 DOM 进行差异比较
- 状态变化时,整个组件函数会重新执行
- 需要手动优化避免不必要的重新渲染(memo, useMemo, useCallback)
- 单向数据流
Vue 渲染机制
- 也使用虚拟 DOM,但结合了依赖追踪系统
- 精确追踪组件依赖,只更新需要更新的部分
- 自动优化渲染,开发者通常不需要手动优化
- 支持双向绑定
最后一步,写一个TodoList
对于Vue深度用户而言仅仅记住概念是不够的,我的建议就是直接上手敲代码,使用React做一个Todolist,通过实战,才能对React的理解更加深刻。
Vue3版本
演示链接:code.juejin.cn/pen/7493168...
js
<template>
<div>
<input
ref="inputRef"
v-model="inputVal"
/>
<button @click="handleAdd">
Add
</button>
<ul>
<li v-for="item in list" :key="item.id">
{{ item.title }}
<input
type="checkbox"
@change="() => handleDelete(item.id)"
/>
</li>
</ul>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
const toDolist = [
{
id: 1,
title: "吃饭",
},
{
id: 2,
title: "睡觉",
},
];
const list = ref(toDolist);
// 在Vue中,curId不会随着list的变化而重新计算
// 因为Vue使用的是基于代理(Proxy)的响应式系统,只有依赖于响应式数据的部分会更新
const curId = ref(list.value.length + 1);
const inputRef = ref(null);
const inputVal = ref('');
const handleDelete = (id: number) => {
const newList = list.value.filter((item) => item.id !== id);
setTimeout(() => {
list.value = newList;
}, 500);
};
const handleAdd = () => {
if (inputVal.value.trim()) {
list.value = [...list.value, { id: curId.value, title: inputVal.value }];
curId.value++;
inputVal.value = '';
}
};
onMounted(() => {
inputRef.value?.focus();
});
</script>
<style scoped>
li {
margin: 8px 0;
}
input[type="checkbox"] {
margin-left: 8px;
}
button {
margin-left: 8px;
}
</style>
React版本实现
现在,让我们看看如何用React实现相同的功能:
演示链接:code.juejin.cn/pen/7493168...
tsx
import { useState, useRef } from "react";
const toDolist = [
{
id: 1,
title: "吃饭",
},
{
id: 2,
title: "睡觉",
},
];
export default function App() {
const [list, setList] = useState(toDolist);
//为什么curId在list改变的时候,值会变?
// 当你调用 setList 更新状态时,React会重新执行整个Gallery函数组件,这意味着 let curId=list.length; 会被重新执行,curId会被重新赋值为当前list的长度。
// 而Vue使用的是基于代理(Proxy)的响应式系统,只有依赖于响应式数据的部分会更新,而不是重新执行整个组件函数。
// let curId=list.length;
const curId = useRef(list.length + 1);
const inputRef = useRef(null);
const handleDelete = (id) => {
const newList = list.filter((item) => item.id !== id);
setTimeout(() => {
setList(newList);
}, 500);
};
const handleAdd = (newList) => {
setInputVal("");
setList(newList);
curId.current++;
};
const [inputVal, setInputVal] = useState("");
return (
<>
<input
ref={inputRef}
value={inputVal}
onChange={(e) => setInputVal(e.target.value)}
></input>
<button
onClick={() =>
handleAdd([...list, { id: curId.current, title: inputVal }])
}
>
Add
</button>
<ul>
{
list.map((item) => {
return (
<li key={item.id}>
{item.title}{" "}
<input
type={"checkbox"}
onChange={() => handleDelete(item.id)}
></input>
</li>
);
})}
</ul>
</>
);
}
实现效果:

结语
以上从Vue开发一个Todolist会用到的基本知识,在React中寻找对应的实现方案的角度来入门React,读完你应该会用React开发一些简单的页面,之后我们会讲如何在React中像Vue Router一样管理url。
恩恩......懦夫的味道