写在前面的话
有人说前端技术更新日新月异,框架版本更新快,前面你刚配置好环境,一不留神,不知道什么时候作者悄悄更新了插件,API,你的项目就跑不动了,留下你一脸茫然找bug......
但对于前端框架,其实不管是vue从1.0到2.0,再到翻天覆地的3.0版本;或是Angular半年更新一个版本,亦或者React从2013年的v0.3.0到今天的v17.0.2,前端又是一直未变的,依旧还是html+css+js的三剑客组合。前端一直关注和完善的都是这三块的内容。
对于一个用过一年Angular,后来又用了两年Vue,现在又重新开始学React的前端开发来说,开发似乎变得陌生又熟悉,写着写着又觉得还是熟悉的配方,不一样的味道,渐渐得还有点酣畅淋漓的快感,获得了解除束缚后的自由✌️。
对于前端本身来说,不管是版本的更新迭代,还是框架的变化,都是换汤不换药的三剑客,因此从入职至今我也一直都是在类比Vue来学习React。
从Vue到React
先来看下他们的官方定义吧
这两张图高效准确的说明了两者的特点:一个是渐进式javaScript框架,恰好符合vue的易用,灵活,而React相较于Vue,最大的特点就是声明式和组件化,让创建交互式 UI 变得轻而易举。
React 和 Vue 有许多相似之处,官方列出的三点是
我在具体使用中发现的具体的点是
在vue中用的是单文件组件,页面是后缀名为.vue的文件,直接可以把html、css、js写到一个文件中,html提供了模板引擎来处理。而react用的是jsx的语法糖,通过 js 完整控制组件的能力,可以通过js生成html,css.比如说对于vue中的一些v-if指令,可以直接用短路&& 逻辑或者 js 三目运算符就可以了。react中render函数是支持闭包特性的,所以我们import的组件在render中可以直接调用。但是在Vue中,由于模板中使用的数据都必须挂在 this 上进行一次中转,所以我们import 一个组件完了之后,还需要在 components 中再声明下,这样显然是很奇怪但又不得不这样的做法。
在React中,对于类组件,它和Vue一样都是有自己的生命周期和数据,不同的是在Vue组件中我们定一个data数据,直接可以通过this.data就可以去更新它,但在React中,我们需要用setState才能更新组件 state的值,当然这只是一种方法的区别,React和Vue在数据层还是相似的,毕竟都是单向数据流,支持双向数据绑定,也都是通过虚拟dom构建页面。
Vue组合不同功能的方式是通过mixin来分发 Vue 组件中的可复用功能,但mixin本身是混合的意思,这也恰恰说明了它的缺点,同名混合时会丢失合并一些组件,同时它的可重用性也是有限的:我们不能向 mixin 传递任何参数来改变它的逻辑,这也降低了它们在抽象逻辑方面的灵活性。
const myMixin = {
created() {
console.log('mixin 对象的钩子被调用');
},
data() {
return {
message: 'hello',
foo: 'abc',
};
},
};
const app = Vue.createApp({
mixins: [myMixin],
data() {
return {
message: 'goodbye',
bar: 'def',
};
},
created() {
console.log('组件钩子被调用');
console.log(this.$data);
},
});
// => "mixin 对象的钩子被调用"
// => "组件钩子被调用"
// => { message: "goodbye", foo: "abc", bar: "def" }
React组合不同功能的方式是通过HOC(高阶组件),官方文档中具体说法就是;高阶组件是参数为组件,返回值为新组件的函数。。
const EnhancedComponent = higherOrderComponent(WrappedComponent);
在Vue中经常会用到一个计算属性computed,支持缓存,只有依赖数据发生改变,才会重新进行计算,一般是多对一的关系;在React中useMemo完全可以很完美得支持这一点,比如下面会在某个依赖项改变时才重新计算 memoized 值。
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
说到Vue中的computed就不得不提到watch,它们就像是一对异卵同生的龙凤胎似的,总是会被拿在一起做比较,一般对于监听数据变化,我们说computed是多对一,就会说watch是一对多,watch一般是用在侦听某一个属性有变化时,需要执行对应的多项操作。那么对应的useEffect也有类似的API可以完成这样的行为,它甚至在此基础上做了优化,在effect 返回一个函数,会在组件卸载的时候执行清除操作。
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
// Specify how to clean up after this effect:
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
}, [props.friend.id]); // 仅在 props.friend.id 发生变化时,重新订阅
上面说了那几点都是些非常基础的,属于react新手入门必备的一些api中的区别,对于前端来说,不过是换了个写法而已,但对于vuex和redux虽然都是状态管理器,这可以说是完全一次全新的升级打怪的体验,不一样的feeling.
Vuex中state是驱动应用的数据源,view是以声明方式将state映射到视图,actions响应view上的用户输入导致的状态变化,形成了下图的“单向数据流”
Vuex的状态自管理应用具体包括:State、getters、mutations、commit、actions、dispatch。
他们之间的关系如下图
Redux作为状态管理遵循了三大原则:单一数据源,state只读,reducer纯函数.主要包括
Action 把数据从应用传到 store 的有效载荷。它是 store 数据的唯一来源。
Reducers 指定了应用状态的变化如何响应actions并发送到 store 的。
Store 就是把action和reducer它们联系到一起的对象
具体的应用实例在Redux网站有Todo List
参考地址:https://www.redux.org.cn/docs/basics/ExampleTodoList.html
Redux和Vuex虽然在应用上有很大差异,但都是通过store来作为全局状态存储对象,只是在vuex中的是使用mutation方法,在redux中的使用的是reducer方法。
以上只是自己在刚接触React实践中的部分简单类比,在React实战经验中的挑战那才是层出不穷,比如类组件和函数组件,还有状态管理在这两个组件中的具体运用,到后来的typeScript,不断面临新的挑战,不断学习,不断进步与成长。哪怕是每天进步一点点,也会觉得自己愈发充实。
另附
本文参考了Vue,React,Vuex,Redux官网。