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

例子:


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:

react 学习笔记(一):react项目创建及目录结构_第1张图片

主要看 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:


Vue3+ts:

比较齐全的 Vue3+ts

React:

// Class componentclass MyReactComponent extends React.Component {render() {return 

Hello world

;} }// Function componentfunction MyReactComponent() {return

Hello world

; }

7.Props

Vue2:



...

Vue3+ts:

setup有两个参数 props 和 context

  • props:接受父组件传的值
  • context:vue3.x里面没有this,提供了一个context上下文属性,你可以通过这个属性去获取进行 一些 vue2.x 用this实现的操作

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:


Vue3+ts:

ref 声明基础数据类型

创建一个响应式的基础类型,只能监听number、String、boolean等简单的类型,该属性一旦发生更改,都会被检测到。


import {ref} from "vue"setup(){const count =ref(0)count.value++    //必须要加.valuereturn{count        //一定要return 出去}
}

 reactive 声明响应式数据对象


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:



...

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:


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出现时为了解决什么问题):
正常情况下,hello world在组件标签Child中的span标签会被组件模板template内容替换掉,当想让组件标签Child中内容传递给组件时需要使用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


React:

function MyReactComponent() {const [isLoading, setLoading] = useState(true);return ({isLoading && Loading...}{isLoading ? is loading : is loaded});
}

17.列表渲染

Vue2,Vue3


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

//App.vue
//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;


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部