本项目需求功能Vue shop 相同,后端 API 也是一样的,使用的是 React 三件套:React、React Router 和 Redux。先对比一下最终效果吧,b本文主要就这两个项目说一说 React 与 Vue 的区别。
一、渲染不同
React 推荐通过 JSX 渲染模板。而 Vue 是更多时候和对 HTML 模板进行渲染。本质上,React 是在组件 JavaScript 代码中,通过原生 JavaScript 语法比如插值、条件,循环等、来实现模板,更加纯粹。React 通过 JavaScript 来操作一切:通过 JavaScript 来生成 html,所以设计了 JSX,甚至使用 JavaScript 来操作 CSS。它自身的 API 很小,得自己实现,幸好 React 的社区很活跃,不用什么都造轮子。所以说,React 的半门槛更高,更适合 JavaScript 基础更好的开发工程师。
看下面 CartControl 组件中 JSX 模板代码:
render() {
return (
<div className="cart-control">
<div className="cart-decrease" title="减"
onClick={this.decrement}>
<span className="iconfont icon-remove-circle"></span>
</div>
<input className="cart-count" value={this.state.count}
onChange={this.handleChange} />
<div className="cart-add" title="加" onClick={this.increment}>
<span className="iconfont icon-add-circle"></span>
</div>
</div>
)
}
}
可以看到 JSX 模板其实就是 ReactNode
,作为 render
方法的返回值使用的。状态及方法更接近原生 JavaScript 写法,绑定它们时仍然用到 this。因为 JSX 的本质是 JavaScript,此处的上下文就是组件本身。重要的事再强调一下, JSX 的本质是 JavaScript,得按 JavaScript 的方式来处理。
需要注意的是:
react 元素的事件处理和 DOM 元素的很相似,但是有一点语法上的不同:
- React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
- 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。
Vue 的单文件组件 JavaScript 代码和 HTML、CSS 样式都是分离的,对模板的操作通过指令来实现的,比如条件语句就需要 v-if 来实现对这一点,Vue 借鉴了 Angular 的做法,因此更适合有设计基础的开发工程师。Vue 自身的 API 很多,更像是一个是 MVVM 框架,有后端开发经验的同学理解起来也很容易。换名话说,Vue 的学习曲线要平滑得多。
如 CartControl 组件中 HTML 模板代码:
<div class="cart-control">
<div class="cart-decrease" title="减"
@click.stop.prevent="decrement(product)">
<span class="iconfont icon-remove-circle"></span>
</div>
<input class="cart-count" :value="count"
@input="inputHandler"></input>
<div class="cart-add" title="加" @click.stop.prevent="increment(product)">
<span class="iconfont icon-add-circle"></span>
</div>
</div>
注意到没有,这个模板用到了 v-bind
和 v-on
指令,使用的是简写方式,这些指令甚至有自己的修饰符。绑定状态及方法时不用上下 this
,在 Vue 的 mount
生命周期中,template 会被编译成 AST 语法树。感兴趣的可以深入去了解一下。另外,借助 transform-vue- JSX
插件,Vue 项目是也可以使用 JSX。
二、组件写法不同
React 是类组件写法,也可以使用函数组件。如下面的代码:
class CartControl extends Component {
constructor(props) {
super(props);
this.state = {
count: props.product.quantity || 1
}
this.handleChange = this.handleChange.bind(this)
this.increment = this.increment.bind(this)
this.decrement = this.decrement.bind(this)
}
static propTypes = {
product: PropTypes.object.isRequired,
added: PropTypes.number.isRequired,
needConfirmed: PropTypes.bool
}
increment(e) {
e.preventDefault()
const { product, needConfirmed, added } = this.props
let count = this.state.count;
let max = count
if (needConfirmed) {
max = this.state.count + added;
}
if (max < product.inventory) {
this.setState({ count: ++count });
this.watchCount(count)
}
}
...
render() {
return (
<div className="cart-control">
<div className="cart-decrease" title="减"
onClick={this.decrement}>
<span className="iconfont icon-remove-circle"></span>
</div>
<input className="cart-count" value={this.state.count}
onChange={this.handleChange} />
<div className="cart-add" title="加" onClick={this.increment}>
<span className="iconfont icon-add-circle"></span>
</div>
</div>
)
}
}
export default connect(state => state.cart, { willUpdateItem, updateCartItem })(CartControl)
React 就是 ES6 的写法:类、方法、属性,很纯粹。
注意:事件方法一般要在类组件的构造函数中绑定,否则访问不到 this。
而 vue 是声明式的写法,通过在字变量对象对象中设置 mixins
、directive
s、props
、data
、computed
、生命周期方法、watch
和 methods
自定义方法来定义组件。
export default {
name: 'CartControl',
props: {
product: {
type: Object,
default: function(){}
}
...
},
data() {
return {
count: this.product.quantity || 1
}
},
watch: {
count: function(count) {
if (this.needConfirmed) {
this.$store.commit('willUpdateCartItem', count)
} else {
this.$store.commit('updateCartItem', {
id: this.product._id,
count: count
}
)
}
}
},
methods: {
increment() {
let max = this.count
if (this.needConfirmed) {
max = this.count + this.added;
}
if (max < this.product.inventory) {
this.count++
}
}
...
}
</script>
所以 react 组件很纯粹,和 Typescript 整合更容易,vue 整合起来稍微复杂。
三、数据流的不同
React 一直不支持双向绑定,提倡的是单向数据流,称之为 onChange/setState
模式。不能对修改 props,如图所示:
Vue 也提倡单向数据流,但通过向父组件 emit
一个事件,或者借助 v-model
实现父子组件双向绑定了,这对于一些特殊场景,比如处理表表单也是很有用的。
注意:新版的 Vue 也不鼓励组件对自己的 props 进行任何修改。
四、监听数据变化的实现不同
Vue 将遍历此 data
对象所有的 property,并使用 Object.defineProperty
通过 getter/setter
以及一些函数的劫持追踪依赖。详见深入响应式原理。正是因为 Vue 会跟踪每一个组件的依赖关系,不需要重新渲染整个组件树,因此可以更快地计算出 VDOM 差异。
React 默认是通过比较引用的方式(diff
)进行的,在应用的状态被改变时,全部子组件都会重新渲染。它是为大项目而生的,如果不优化可能导致大量不必要的 VDOM 的重新渲染,甚至还没有直接操作 DOM 来得快。
Vue 的实现简单很多,Vue 使用的是可变数据,可以对 data
对象随意修改。而 React 更强调数据的不可变,对状态的修改必须要用 setState
方法。
React 是这样修改的:
handleChange(e) {
let val = e.target.value
// Should be a positive integer
if (/^[1-9]\d*$/.test(val) && val <= this.props.product.inventory) {
this.setState({ count: parseInt(val) })
this.watchCount(val)
} else {
e.target.value = this.state.count
}
}
vue 是这样实现的,
inputHandler(e) {
let val = e.target.value
// Should be a positive integer
if (/^[1-9]\d*$/.test(val) && val < this.product.inventory) {
this.count = parseInt(val)
} else {
e.target.value = this.count
}
}
五、Redux 和 Vuex 的联系区别
本质上,Redux 和 Vuex 都是对 MVVM 思想的服务,将数据从视图中抽离的一种方案。它们都使用单一的数据源,用了设计模式中的观察者模式或者说发布/订阅模式。在 React 中,initState
相当于 event
对象,dispatch
相当于 trigger
方法, dispatch
函数则相当于订阅的事件。在 Vuex 中,$store
相当于 event
对象,store.commit
相当于 trigger
方法, mutation
中的函数名则相当于订阅的事件。Vuex 借鉴了 Redux,将 store 作为全局的数据中心进行数据管理。
Redux 数据流向:View –> Actions –> Reducer –> State 变化 –> View
变化(同步异步一样)
Vuex 的数据流向:
View –> Commit –> Mutations –> State 变化 –> View 变化(同步操作)
View –> Dispatch –> Actions –> Mutations –> State 变化 –> View
变化(异步操作)
- 在 Redux 中,我们每一个组件都需要显示的用
connect
把需要的 props 和dispatch
连接起来。在 Vuex 中,$store
被直接注入到了组件实例中,因此可以比较灵活的使用; - Vuex 改进了 Redux 中的 Action 和 Reducer 函数,以 Mutations 变化函数取代 Reducer,无需 switch,只需在对应的 Mutation 函数里改变
state
值就可以; - Vuex 只能配合 Vue 使用,Redux 可以整合到任何框架中;
- 而 Redux 中没有异步操作的 API,得借助
redux-thunk
来实现,Vuex 中可以直接使用 Action 进行异步操作; - 而 Redux 是没有 module 化功能,Vuex 自带就有。
- React 和 Vue 中的路由基本上是一样,Vue Router 借鉴了 React Router,核心组件、配置和 API 都差不多。
React 和 Vue 的设计思想是不一样的,前者是映射思维,后者是模板思维。在映射思维的世界观里, JavaScript 数据是唯一的实质。在模板思维看来,html 模板和 JavaScript 数据都是实质,二者是并列的关系;
评论 (0)