React:a declarative, efficient, and flexible JavaScript library for building user interfaces.(用于构建用户界面的声明式、高效和灵活的 JavaScript 库。)
Vue:a progressive, incrementally-adoptable JavaScript framework for building UI on the web.(用于在 web 上构建 UI 的渐进式、可逐步采用的 JavaScript 框架。)
亮点
- 都采用类似的方法来实现相同的目标。例如:灵活、高效构建 web UI。
- React 以 javascript 为中心,而 Vue 使用混合的 HTML 模板/JS。
- React 使用一种主动修改状态更新(state)的模型,Vue 通过观察(observe)响应数据。
- Vue 有许多内置的功能,React 更为灵活且比较依赖其社区。
语言方式
众所周知,Vue3.0 已经发布,composition API似乎是 Vue 的发展方向。
Vue 和 React 之间有明显的相似之处:Vue 组件选项 API 类似于 React 的类组件;而 Vue 3 的composition API类似于 React hooks。
// UserProfile.vue
<div>
<div>{{ id }}</div>
<Avatar v-if="showAvatar" :id="id" />
<UserBody v-if="user" :user="user" />
<button @click="$emit('follow-click')">Follow</button>
</div>
defineComponent({
props: {
id: { type: String },
showAvatar: { type: Boolean },
},
setup(props) {
const {id} = toRefs(props);
const user = ref(undefined);
function updateUser() {
fetchUser(id.value).then(data => {
user.value = data;
});
}
onMounted(updateUser);
watch(id, updateUser);
return {user};
}
})
// React
function UserProfile({
id,
showAvatar,
onFollowClick,
}: {
id: string,
showAvatar: boolean,
onFollowClick: () => void,
}) {
const [user, setUser] = React.useState(undefined)
React.useEffect(() => {
fetchUser(id).then(setUser)
}, [id])
return (
<div>
<div>{id}</div>
{showAvatar ? <Avatar id={id} /> : null}
{user !== undefined ? <UserBody user={user} /> : null}
<button onClick={onFollowClick}>Follow</button>
</div>
)
}
// React
function UserProfile({
id,
showAvatar,
onFollowClick,
}: {
id: string,
showAvatar: boolean,
onFollowClick: () => void,
}) {
const [user, setUser] = React.useState(undefined)
React.useEffect(() => {
fetchUser(id).then(setUser)
}, [id])
return (
<div>
<div>{id}</div>
{showAvatar ? <Avatar id={id} /> : null}
{user !== undefined ? <UserBody user={user} /> : null}
<button onClick={onFollowClick}>Follow</button>
</div>
)
}
对于 Vue,HTML 模板是灵魂,模板在构建时被处理成 JavaScript。可以通过Vue Template Explorer(https://vue-next-template-explorer.netlify.app/)查看模板是如何编译成 JS 的。
<div>Hello World!</div>
// 编译后
import {
createVNode as _createVNode,
openBlock as _openBlock,
createBlock as _createBlock,
} from 'vue'
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return _openBlock(), _createBlock('div', null, 'Hello World!')
}
JSX 则是 React 的语法糖。不少初学者觉得JSX写起来不舒服,后来就真香了,因为真的很灵活丫
从正反两面来说
Vue 模板语法的一个优点是,由于它的限制性更强,编译器能够执行更多的优化,例如分离静态模板内容以避免重新渲染。
而 React 做类似的工作需要借助 Babel 插件完成。理论上,Vue 可以对模板语法进行更多的优化。
Vue 模板的一个缺点是,有时JavaScript 的表现力被严重忽略,甚至是必要的(对比使用 JSX 的感受来说)。在这种情况下,官方推荐使用render函数,也可以通过更详细的createElement或 JSX。
如果使用 React hooks,React 组件只是函数,所有的逻辑都存在在这个函数里面。Vue 将组件定义从模板(或渲染函数)分离,使用composition API,组件定义在一个setup函数里面。有一个很明显的区别:React 钩子在每个render函数上运行,但是 Vue的setup 只在初始化时运行一次
Vue 设置监听器(生命周期和响应值),而 React 指定每个render的效果。
事件处理
Vue 和 React 的事件处理是不同语言方式的另一个体现。React 没有特殊的语法;它只是 JavaScript 函数。Vue 提供了侦听和发出事件的语法。
// MyVueComponent
<button @click="$emit('increment')">Increment</button>
<MyVueComponent @increment="methodName" />
// MyReactComponent
<button onClick={props.onIncrement}>Increment</button>
<MyReactComponent onIncrement={jsFunction} />
这里看到不同的处理事件的方式。React 向组件传递一个 JavaScript 函数。Vue 组件发出事件,这些事件被标识为带有关联数据的字符串。
静态分析
在某些方面,React 更适合静态分析。例如 TypeScript,React 以 javascript 为中心的语言方式使它更接近 TypeScript 语言,所以大多数编辑器/工具都能较好的配合。
一些 Vue 特性,如命名插槽、事件和它们的 props(相当于 React 子元素),对于完整的静态分析来说太动态了。例如,组件可以发出自定义事件,但没有明显的方法写出这种合约。
Vue 提供了一个全局命名空间,但不总是推荐这样做。可以通过名称向全局命名空间注册组件。Vue 插件可以注入全局方法、属性和 mixins。全局名称空间有时很方便,但在使用工具和可伸缩代码库时效果不太好。
更新模型
Vue 和 React 在功能上最大的区别是它们如何处理数据的更新。Vue 使用 observable(通过 JavaScript 的proxies或者defineProperty)来完成数据的响应。简单来说,它修改数据以跟踪何时读取或写入属性。这允许细粒度的依赖跟踪;Vue 知道哪些属性已经被读取,因此只有当这些属性发生变化时,它才会重新呈现和更新视图。这比React.memo更明智一些。
相比较,React 使用一种主动更新的模式,渲染通常被函数调用(状态更新或 reducer 分配时)触发,当 React 组件更新时,它也会重新渲染其所有子代。
// MyVueComponent
<button @click="count += 1">{{ count }}</button>
Vue.extend({
data: {
count: 0
}
})
// React Component
function MyReactComponent() {
const [count, setCount] = React.useState(0);
return <button onClick={() => setCount(count => count + 1)}>{count}</button>;
}
Vue 的更新模型就好像所有组件都包装在React.memo中一样,相同的是其函数只动态的比较最后渲染时使用的 props/状态。
Vue 的更新模型有点像 mobx。Vue 的计算属性功能比较好,每当计算属性的数据发生更改时,Vue 都会重新渲染当前页面,即使计算属性本身未更改也会如此。在 React 中如果不创建包裹组件,就很难使用React.useMemo来这样表达。
开箱即用,Vue 执行更细粒度的更新,因此默认情况下,Vue 更新的性能更高。当然,React 拥有React.memo但是需要理解闭包以及什么时候使用React.useMemo和React.useCallback。但 Vue 并没有摆脱困境,通过 注入 observable 来驱动更新是有陷阱的。
API
React 的 API 更小,需要学习的特定于 React 的概念更少(忽略 concurrent 模式和时间切片)。
但在 Vue 中有更多方便之处:
v-model
v-model 支持数据双向绑定:
// MyVueComponent
;<div>
<input v-model='message' />
<p>{{ message }}</p>
</div>
Vue.extend({
data: {
message: '',
},
})
React 文档中表示:在 React 中,数据是单向流动的:从所有者到子节点。我们认为这使你的应用程序的代码更容易理解。您可以将其视为“单向数据绑定”。
function MyReactComponent() {
const [message, setMessage] = React.useState('');
return (
<div>
<input value={message} onChange={e => setMessage(e.target.value} />} />
<p>{message}</p>
</div>
);
}
类名绑定
Vue 具有特殊的类和样式处理。这些属性会被合并,还会处理成对象映射和数组。
// MyVueComponent
<div :class="my-class-name">Hello</div>
<MyVueComponent :class="{ active: isActive }" />
但在 React 中,类名绑定没有什么特别之处,许多人会引入第三方库来处理样式(比如 classnames、CSS in JS)
function MyReactComponent({ className }) {
return <div className={'my-class-name ' + className}>Hello</div>
}
;<MyReactComponent className={isActive ? 'active' : ''} />
Vue 作为一个框架
React 标榜自己是一个库(library),而 Vue 是一个框架(framework)。这个界线很模糊,但是 Vue 比 React 有更多的开箱即用(out-of-the-box)的功能:Vue 有内置的过渡和动画,拥有用于路由和状态管理(vuex)的库。
React 核心,只关注渲染层。其他部分由生态系统提供,且其生态系统非常活跃。
相同点
Vue 和 React 有诸多不同,但是也有一些相似点。它们都是用于构建 web UI 视图的库并且很多概念都能从一个映射到另一个。
- 两者都使用虚拟 DOM 并支持 JSX
- Vue 插槽和 React 子节点
- Vue 的 props/state 和 React 的 props/state
- Vue 的 teleport 和 React 的 portal
你应该使用哪个
首先,无论用哪个你都能获得成功和成效。(此外,据大佬反馈,Vue3.0 解决了 Vue 2.x 的很多痛点。)
如果你比较钟爱类型系统,那么更推荐使用 React,它与 TypeScript 一起工作得更好,并且拥有更纯粹的语言方法。
如果你喜欢从 HTML/静态内容开始,然后稍微使用一些 JavaScript,那么 Vue 的模板方法会比较合适。
对于不太熟悉 JavaScript 的开发人员来说,Vue 可能更容易上手(文档也很友好)。模板是直观的,可以逐步采用。不需要考虑重新呈现,数据绑定很容易理解。但这并不代表不能用 Vue 构建复杂的应用程序。如果你在 JavaScript 上花了很多时间,您可能会喜欢 React 更纯粹的语言方法。
最后,我们很难忽视 React 的大规模应用和庞大的生态系统。对公司来说,React 将是风险较小的选择。拥有 React 经验多于拥有 Vue 经验的工程师在招聘上可能会更容易。此外,还有更多可供选择的 React 渲染目标,比如 React Native,您可能会发现它们很有用。
你也可以使用这两个框架来提高效率。