Vue2,Vue3,React的对比
1.网页依赖
Vue2:
Vue3:
React:
2.安装和脚手架
添加镜像和cnpm
npm config set registry https://registry.npm.taobao.org
npm install -g cnpm --registry=https://registry.npm.taobao.org
Vue2:
$ cnpm install vue
# 全局安装 vue-cli
$ cnpm install --global vue-cli
# 创建一个基于 webpack 模板的新项目
$ vue init webpack my-project
# 这里需要进行一些配置,默认回车即可
$ cd my-project
$ cnpm install
$ cnpm run dev
#打包
$ cnpm run build
Vue3:
$ cnpm install vue@next
# 全局安装 vue-cli
$ cnpm install -g @vue/cli
$ cnpm install -g @vue/cli-init
$ vue init webpack hello-vue3
# 这里需要进行一些配置,默认回车即可
#或者使用 vue create hello-vue3
# select vue 3 preset
$ cd hello-vue3
$ cnpm install
$ cnpm run dev
#打包
$ cnpm run build
React:
$ cnpm install -g create-react-app
$ create-react-app my-app
$ cd my-app/
安装依赖:cnpm install
启动项目:cnpm start
编译:cnpm run build
3.生命周期
Vue2:
beforeCreate :数据还没有挂载呢,只是一个空壳
created:这个时候已经可以使用到数据,也可以更改数据,在这里更改数据不会触发updated函数
beforeMount:虚拟dom已经创建完成,马上就要渲染,在这里也可以更改数据,不会触发updated
mounted:此时,组件已经出现在页面中,数据、真实dom都已经处理好了,事件都已经挂载好了
beforeUpdate:重新渲染之前触发,然后vue的虚拟dom机制会重新构建虚拟dom与上一次的虚拟dom树利用diff算法进行对比之后重新渲染
updated:数据已经更改完成,dom也重新render完成
beforeDestory:销毁前执行($destroy方法被调用的时候就会执行),一般在这里善后:清除计时器、清除非指令绑定的事件等等...
destroyed:组件的数据绑定、监听...都去掉了,只剩下dom空壳,这里也可以善后
常用的生命周期:created,mounted,beforeDestory
Vue3:

说明:由于Vue2中的beforeCreate和created生命周期的执行几乎与VUE3中的setup在同一时间执行,所以在Vue2中写在created和beforeCreate中的代码可以直接写在setup()方法中
总之:
- beforeCreate()和created()构造函数都应该写在setup()函数中
- 修改了部分钩子函数的名称
-
BeforeDestroy变成了onBeforeUnmount,destroyed变成了onUnmounted
- 新增了两个调试用钩子函数
- onRenderTracked,onRenderTriggered
例子:
Hello World
React:
1) react初始化的顺序是,constructor然后是componentWillMount(相当于vue 的beforeMounted) 然后是 render渲染函数再然后是componentDidMount(相当于vue的mounted )
2) 更新的时候:componentWillUpdate、render、componentDidUpdate(跟vue一样 平时没在用到更新的钩子函数)
shouldComponentUpdate,其实在更新的时也会触发这个钩子函数,你不写默认就是true,数据改变会执行更新的钩子函数, 如果你要组织他更新的话就写这个钩子函数写成false,意思就是不让更新.
3) 销毁的时候: componentWillUnmount(vue的 话一般用beforeDestroy用来清除定时器等)
这里还有一个比较少用的钩子函数,
在父组件里面改变props传值的时候触发的:componentWillReceiveProps
例如,组件需要以props中的某个属性作为与服务器通信时的请 求参数,当这个属性值发生更新时,组件自然需要重新与服务器通信。 不难发现 componentWillReceiveProps非常适合做这个工作。
react16.4后使用了新的生命周期,使用getDerivedStateFromProps代替了旧的componentWillReceiveProps及componentWillMount。使用getSnapshotBeforeUpdate代替了旧的componentWillUpdate。
最常用的还是
componentDidMount(对vue2--mounted,vue3-onMounted).componentWillUnmount(对vue2--beforeDestroy,vue3-onBeforeUnMount)
例子:
function component
function MyReactComponent() {// componentDidMountuseEffect(() => {}, []);// componentDidUpdate + componentDidMountuseEffect(() => {});// componentWillUnmountuseEffect(() => {return () => {...}}, []);// 在渲染之后但在屏幕更新之前同步运行useLayoutEffect(() => {}, []);return Hello World;
}
//Class component
class MyReactComponent extends React.Component {static getDerivedStateFromProps(props, state) {}componentDidMount() {}shouldComponentUpdate(nextProps, nextState) {}getSnapshotBeforeUpdate(prevProps, prevState) {}componentDidUpdate(prevProps, prevState) {}componentWillUnmount() {}render() {return Hello World;}
}
4.基本目录
vue2:
├── build/ # Webpack 配置目录
├── dist/ # build 生成的生产环境下的项目
├── src/ # 源码目录(开发都在这里进行)
│ ├── assets/ # 放置需要经由 Webpack 处理的静态文件
│ ├── components/ # 组件
│ ├── filters/ # 过滤器
│ ├── store/ # 状态管理
│ ├── routes/ # 路由
│ ├── services/ # 服务(统一管理 XHR 请求)
│ ├── utils/ # 工具类
│ ├── views/ # 路由页面组件
│ ├── app.js # 启动文件
│ ├── index.html # 静态基页
├── static/ # 放置无需经由 Webpack 处理的静态文件
├── .babelrc # Babel 转码配置
├── .eslintignore # (配置)ESLint 检查中需忽略的文件(夹)
├── .eslintrc # ESLint 配置
├── .gitignore # (配置)需被 Git 忽略的文件(夹)
├── package.json # (这个就不用多解释了吧)
├── package-lock.json # (以记录当前状态下实际安装的各个npm package的具体来源和版本号)
Vue3:
|-node_modules -- 所有的项目依赖包都放在这个目录下
|-public -- 公共文件夹
---|favicon.ico -- 网站的显示图标
---|index.html -- 入口的html文件
|-src -- 源文件目录,编写的代码基本都在这个目录下
---|assets -- 放置静态文件的目录,比如logo.pn就放在这里
---|components -- Vue的组件文件,自定义的组件都会放到这
---|App.vue -- 根组件,这个在Vue2中也有
---|main.ts -- 入口文件,因为采用了TypeScript所以是ts结尾
---|shims-vue.d.ts -- 类文件(也叫定义文件),因为.vue结尾的文件在ts中不认可,所以要有定义文件
|-.browserslistrc -- 在不同前端工具之间公用目标浏览器和node版本的配置文件,作用是设置兼容性
|-.eslintrc.js -- Eslint的配置文件,不用作过多介绍
|-.gitignore -- 用来配置那些文件不归git管理
|-package.json -- 命令配置和包管理文件
|-README.md -- 项目的说明文件,使用markdown语法进行编写
|-tsconfig.json -- 关于TypoScript的配置文件
|-yarn.lock -- 使用yarn后自动生成的文件,由Yarn管理,安装yarn包时的重要信息存储到yarn.lock文件中
React:

主要看 public 和 src 文件夹中的文件:
public 文件夹是公共文件夹,与src最大的区别就是不会被webpack加工,用于存放一些静态文件。
- manifest.json ,扩展的配置文件
- robots.txt,爬虫爬取时应该遵守的规则
- index.html,整个项目的入口文件
- 其他文件都是图标
src 文件夹是项目存放源文件的文件夹,项目的主要内容都会存放在里面。
- App.js, 项目的主组件
- App.css,App组件的样式
- App.test.js,测试文件
- index.css,整个项目的全局样式
- index.js,JS的入口文件
- serviceWorker.js,用于使项目可以离线运行
5.入口App
Vue2:
main.js是我们的入口文件,主要作用是初始化vue实例并使用需要的插件。
import Vue from 'vue'
import App from './App'
import router from './router'Vue.config.productionTip = false/* eslint-disable no-new */
new Vue({el: '#app',router,components: { App },template: ' '
})
App.vue是我们的主组件,所有页面都是在App.vue下进行切换的。可以理解为所有的路由router也是App.vue的子组件

Vue3+ts:
main.ts
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'const app = createApp(App)app.use(router)app.mount('#app')
React:
// index.js
import React from 'react';
// ReactDom用于页面渲染
import ReactDOM from 'react-dom';
// index.css用于处理页面样式
import './index.css';
// App 是一个组件
import App from './App';
import * as serviceWorker from './serviceWorker';// 用ReactDOM.render来将元素渲染到页面中
ReactDOM.render( , document.getElementById('root'));// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
6.基本组件写法
Vue2:
Hello World
Vue3+ts:
vue3新语法
{{girl}}
比较齐全的 Vue3+ts

React:
// Class componentclass MyReactComponent extends React.Component {render() {return Hello world
;}
}// Function componentfunction MyReactComponent() {return Hello world
;
}
7.Props
Vue2:
Hello {{ name }}
...
Vue3+ts:
setup有两个参数 props 和 context
- props:接受父组件传的值
- context:vue3.x里面没有this,提供了一个context上下文属性,你可以通过这个属性去获取进行 一些 vue2.x 用this实现的操作
Hello {{ name }}
React:
function MyReactComponent(props) {const { name, mark } = props;return Hello {name}{mark}
;
}
MyReactComponent.propTypes = {name: PropTypes.string.isRequired,mark: PropTypes.string,
}
MyReactComponent.defaultProps = {mark: '!',
}
...
8.事件绑定
Vue2,Vue3:
React:
//Class component
class MyReactComponent extends React.Component {save = () => {console.log("save");};render() {return ;}
}//Function component
function MyReactComponent() {const save = () => {console.log("save");};return ;
}
9.自定义事件(子组件调用父组件函数,可以传参数)
Vue2,Vue3:
...
React:
function MyItem({ item, handleDelete }) {return ;/** 应用useCallback钩子来防止在每次渲染时生成新的函数。** const handleClick = useCallback(() => handleDelete(item), [item, handleDelete]);** return ;*/
}
...
function App() {const handleDelete = () => { ... }return
}
10.State(Data)和Change-State(Change Data)
Vue2:
{{count}}
Vue3+ts:
ref 声明基础数据类型
创建一个响应式的基础类型,只能监听number、String、boolean等简单的类型,该属性一旦发生更改,都会被检测到。
{{count}} // 1
import {ref} from "vue"setup(){const count =ref(0)count.value++ //必须要加.valuereturn{count //一定要return 出去}
}
reactive 声明响应式数据对象
{{count.name}} // 857
import {reactive} from "vue"setup(){const count =reactive({name:'369'})count.name='857'return{count }
}
React:
//Class component
class MyReactComponent extends React.Component {state = {count: 0,};increaseCount = () => {this.setState({ count: this.state.count + 1 });// 在更新之前获取当前状态,以确保我们没有使用陈旧的值// this.setState(currentState => ({ count: currentState.count + 1 }));};render() {return ({this.state.count});}
}//functiom component
function MyReactComponent() {const [count, setCount] = useState(0);const increaseCount = () => {setCount(count + 1);// setCount(currentCount => currentCount + 1);};return ({count});
}
11.双向绑定 (仅Vue.js,语法糖,加入界面数据->data的变化)
Vue2,Vue3
React:
function MyReactComponent() {const [content, setContent] = useState("");return ( setContent(e.target.value)}/>);
}
12.计算属性computed
watch和computed各自处理的数据关系场景不同
watch擅长处理的场景:一个数据影响多个数据
computed擅长处理的场景:一个数据受多个数据影响
Vue2:
{{displayName}}
...
Vue3+ts:
async setup() {const data = reactive({a: 10,b: 20,});let sum = computed(() => data.a + data.b);return { sum };},
React:使用useMemo
function DisplayName({ firstName, lastName }) {const displayName = useMemo(() => {return `${firstName} ${lastName}`;}, [firstName, lastName]);return {displayName};
}
...
13.watch
Vue2:
{{count}}
Vue3+ts:
const state = reactive({ count: 0 })
watch(() => state.count,(count, prevCount) => {//...}
)
React:使用useEffect
function MyReactComponent() {const [count, setCount] = useState(0);const increaseCount = () => {setCount((currentCount) => currentCount + 1);};useEffect(() => {localStorage.setItem("my_count", newCount);}, [count]);return ({count});
}
class Component 可以在下面两个函数设置,也可以借助第三方库
componentWillUpdate(object nextProps, object nextState)
componentDidUpdate(object prevProps, object prevState)
14.Children-and-Slot
Slot
是对组件的扩展,通过slot插槽向组件内部指定位置传递内容,通过slot可以父子传参;
开发背景(slot出现时为了解决什么问题):
正常情况下,
Vue2,Vue3
...
Hello World
React:
function MyReactComponent({ children }) {return {children};
}
...
Hello World
15.渲染HTML
Vue2,Vue3
React:
function MyReactComponent() {return { __html: "...
" }} />;
}
16.条件渲染
Vue2,Vue3
Loading...is loadingis loaded
React:
function MyReactComponent() {const [isLoading, setLoading] = useState(true);return ({isLoading && Loading...}{isLoading ? is loading : is loaded});
}
17.列表渲染
Vue2,Vue3
- {{item.name}}: {{item.desc}}
React:
function MyReactComponent({ items }) {return ({items.map((item) => (- {item.name}: {item.desc}
))}
);
}
18.Ref
Vue2,Vue3
React:
//Class component
class AutofocusInput extends React.Component {constructor(props) {super(props);this.ref = React.createRef();}state = {content: "",};componentDidMount() {this.ref.current.focus();}setContent = (e) => {this.setState({ content: e.target.value });};render() {return ( );}
}//Function component
function AutofocusInput() {const [content, setContent] = useState("");const ref = useRef(null);useEffect(() => {if (ref && ref.current) {ref.current.focus();}}, []);return ( setContent(e.target.value)}/>);
}
19.vuex,redux
为什么不用localstorage可以代替vuex?
1).区别:vuex存储在内存,localstorage(本地存储)则以文件的方式存储在本地,永久保存;sessionstorage( 会话存储 ) ,临时保存。localStorage和sessionStorage只能存储字符串类型,对于复杂的对象可以使用ECMAScript提供的JSON对象的stringify和parse来处理
2).应用场景:vuex用于组件之间的传值,localstorage,sessionstorage则主要用于不同页面之间的传值。
3).永久性:当刷新页面(这里的刷新页面指的是 --> F5刷新,属于清除内存了)时vuex存储的值会丢失,sessionstorage页面关闭后就清除掉了,localstorage不会。
注:很多同学觉得用localstorage可以代替vuex, 对于不变的数据确实可以,但是当两个组件共用一个数据源(对象或数组)时,如果其中一个组件改变了该数据源,希望另一个组件响应该变化时,localstorage,sessionstorage无法做到,原因就是区别1。

vue2:
const store = new Vuex.Store({state:{loading: false,todoList : [{id:1,name:'11'},{id:2,name:'22'},{id:3,name:'33'},],num: 0,},mutations:{setNumIs5(state){state.num = 5},setNumIsWhat(state,payload){state.num = payload.num}},actions:{ <----- 增加actions属性setNum(content){ <----- 增加setNum方法,默认第一个参数是content,其值是复制的一份storereturn new Promise((resolve)=>{ <----- 返回一个promise,我们模拟一个异步操作,1秒后修改num为5setTimeout(()=>{content.commit('setNumIs5')resolve()},1000)})}}
})async mounted() {console.log('旧值---'+this.$store.state.num);await this.$store.dispatch('setNum') <----- actions使用dispatch进行触发,就像mutation使用commit触发一样console.log('新值---'+this.$store.state.num);},
Vue3与Vue2不同之处:
//创建实例的方式改变,Vue2.x为new Store , Vue3.x为createStore
//Vue2.x 中创建 store 实例
export default new Vuex.Store({// ...
})//Vue3.x
import Vuex from 'vuex'export default Vuex.createStore({state: {count: 0},mutations: {ADD (state) {state.count++}},actions: {add ({ commit }) {commit('ADD')}},modules: {}
})
React:
//index.js
import React from 'react';
import ReactDOM from 'react-dom';
import TodoList from './TodoList';//第一步
import {Provider} from 'react-redux';//引入react-redux
import store from './store/index';//作用:把store提供给 所有的组件实现store共享
const App=( {/*这里面的组件都有能力获取store里的数据*/}{/**/}{/**/}
);
//
// ReactDOM.render( , document.getElementById('root'));
ReactDOM.render(App, document.getElementById('root'));//TodoList
import React,{Component} from 'react';
//第二步
import {connect} from 'react-redux';class TodoList extends Component{render(){return({this.props.list.map((item,index)=>{return - this.props.deleteItem(index)}>{item}
})}
)}}
//规定映射条件 store里的state映射到组件的props里const mapStateToProps=(state)=>{return {inputValue:state.inputValue,//inputValue是指组件this.props.inputValue,state.inputValue是指store里的inputValuelist:state.list,}
};//把store.dispatch映射到组件的props上
const mapDispatchToProps=(dispatch)=>{return {//把这个函数映射到组件的props上changeInputValue(e){const action={//1:创建action消息type:'change_input_value',value:e.target.value,//把输入框里的值传给store};dispatch(action);//2:把这个消息传给store处理},addItem(){const action={type:'add_item',};dispatch(action);},deleteItem(index){const action={type:'delete_item',index:index,};dispatch(action);}}
};//目的:使TodoList和store做链接
export default connect(mapStateToProps,mapDispatchToProps)(TodoList);//store/index.js
import {createStore} from 'redux';
import reducer from './reducer';
const store=createStore(reducer);export default store;//store/reducer.js
const defaultState={//创建一个默认stateinputValue:'',list:[],
};export default (state=defaultState,action)=>{//3:处理store自动传过来的action消息if(action.type==='change_input_value'){const newState=JSON.parse(JSON.stringify(state));//对原有数据进行深拷贝、newState.inputValue=action.value;return newState;//4:reducer把newState传给store,store进行更新处理}if (action.type==='add_item'){const newState=JSON.parse(JSON.stringify(state));//对原有数据进行深拷贝、newState.list.push(newState.inputValue);newState.inputValue='';return newState;}if (action.type==='delete_item'){const newState=JSON.parse(JSON.stringify(state));//对原有数据进行深拷贝、newState.list.splice(action.index,1);//删除从索引开始的1个return newState;}return state;
}
用户发出 Action,Reducer 函数算出新的 State,View 重新渲染。但是,一个关键问题没有解决:异步操作怎么办?Action 发出以后,Reducer 立即算出 State,这叫做同步;Action 发出以后,过一段时间再执行 Reducer,这就是异步。
怎么才能 Reducer 在异步操作结束后自动执行呢?这就要用到新的工具:中间件. redux-thunk。
20.route
Vue2:
//home.vue
home
{{msg}}
//App.vue

Home
//index.js
import Vue from "vue";
import VueRouter from "vue-router";// 引入组件
import home from "./home.vue";
import about from "./about.vue";// 要告诉 vue 使用 vueRouter
Vue.use(VueRouter);const routes = [{path:"/home",component: home}
]var router = new VueRouter({routes
})
export default router;//main.js
import Vue from 'vue'
import App from './App.vue'// 引入路由
import router from "./router.js" // import router 的router 一定要小写, 不要写成Router, 否则报 can't match的报错
new Vue({el: '#app',router, // 注入到根实例中render: h => h(App)
})//router.js
const routes = [{path:"/home",component: home},{path: "/about",component: about},// 重定向{path: '/', redirect: '/home' }
]
Vue3与Vue2不同点:
//Vue2.x//通过this获取router实例
export default{mounted() {this.getRouter();},methods: {getRouter() {console.log(this.$route);console.log(this.$router);},},
}//Vue3.x//第一种 通过使用 getCurrentInstance 方法获取当前组件实例import { getCurrentInstance } from "vue";
export default {setup(props, context) {const { ctx } = getCurrentInstance();console.log(ctx.$router.currentRoute.value);},
};//第二种通过userRoute和userRouter
import { useRoute, useRouter } from "vue-router";
export default {setup(props, context) {const currRoute = useRoute();const currRouter = useRouter();console.log(currRoute);console.log(currRouter);},
};
React 和Vue差不多:
//Test.js
import React, { Component } from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import Index from '../pages/Index'
import List from './List'
class Test extends Component {constructor(props) {super(props);this.state = {};}render() {return (- 首页
);}
}export default Test;//index.js
import React, { Component } from 'react';
class Index extends Component {constructor(props) {super(props);this.state = { }}render() { return ( index);}
}export default Index;
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
