SoFunction
Updated on 2025-04-04

Detailed explanation of project preparations for transferring from react to vue development

Preface

First of all, why do I need to prepare for this project? Because I have been accustomed to React development for many years, I have taken over a Vue project recently, and I have basically never practiced Vue before. This abruptly made me, who is still addicted to React development, and I was not used to it. Naturally, I need to find a way to make Vue development similar to React as much as possible, so that I may be more handy in the development process.

Component development

Feature comparison

As we all know, Vue and React have a feature, that is, we can carry out component development, so that the code can be better reused and decoupled. In architectural positioning, this should be called vertical hierarchy. However, the writing of the two framework development components is different (this difference is based on my development habits). Let’s take a look at the different parts first.

First of all, React, I am used to writing es6 (I have never used the writing of createClass in es5):

import React, { Component } from 'react';
import propTypes from 'prop-types';

export default class Demo extends Component {

 state = {
  text: 'hello world'
 };

 static propTypes = {
  title: 
 }

 static defaultProps = {
  title: 'React Demo'
 }

 setText = e => {
  ({
   text: 'Clicked the button'
  })
 }

 componentWillReveiveProps(nextProps) {
  (`Title from ${} Turned into ${}`)
 }

 render() {
  const { title } = ;
  const { text } = ;
  return <div>
   <h1>{title}</h1>
   <span>{text}<span>
   <button onClick={}>Button<button>
  </div>
 }
}

Here are the common ways to write vue:

<template>
 <div>
  <h1>{{title}}</h1>
  <span>{{text}}<span>
  <button @click="setText">Button</button>
 </div>
</template>

<script>
export default {
 props: {
  title: {
   type: String,
   default: 'Vue Demo'
  }
 },
 watch: {
  title(newTitle, oldTitle) {
   (`Title from ${oldTile} Turned into ${newTitle}`)
  }
 },
 data() {
  return {
   text: 'hello world'
  }
 },
 methods: {
  setText(e) {
    = 'Clicked the button';
  }
 }
}
</script>

Let's ignore the rendering of the view here first, and the next section will be compared in detail.

Prop comparison:

  • Vue's prop must be declared in the props field. React's prop does not force declaration, and can also use prop-types to declare constraints on it when declaring it.
  • Vue's prop declaration is hung under this component, and it is obtained in this when needed. React's prop is found in the component's props field, and it is directly retrieved in it when used.

Component status comparison, Vue is data, and React is state:

  • Vue's state data needs to be declared as a function in the data field of the component and returns an object. The state state of React can be directly mounted in the component's state field and initialized before use.
  • Vue's status data is declared and hung under this. What is needed is the time to get it in this. The state state of React is found in the component's state field and is directly retrieved when used.
  • Vue's status update can be directly assigned to it, and the views can be synchronized directly. React's status update must use setState, otherwise the view will not be updated.

Then there is the component method comparison:

  • Vue's method needs to be declared in the methods field. React methods can be declared under the component by method.
  • Vue and React are used in the same way, because they are both mounted in the component and can be retrieved directly in this.

Computed Computed Computed Computed:

  • Vue has computed properties declared in computed fields. There is no computing attribute feature in React, and other libraries such as mobx need to be assisted.
  • Vue's computed attributes are declared and mounted under this, and are obtained in this when needed.

Data comparison:

  • In Vue, you can compare prop, data, and computed in the watch field, and then do the corresponding operations. All changes in React need to be compared manually in the declaration cycle componentWillReveiveProps.

After comparing, I found that Vue actually gave me my personal feeling that I was writing configurations myself, but the configurations were written in the form of functions, and then Vue helped you mount these configured things under the components. Moreover, prop, data, computed, and methods are all mounted components. In fact, it is difficult to understand from the js syntax alone. For example, in computed, I want to obtain data text data, and I use it to obtain it. If I put aside vue and use js syntax alone, this is actually mostly pointing to computed objects, so I personally think that such syntax is reverse-oriented.

At this time, looking at React's class writing method, it is originally an object-oriented writing method. The state state belongs to the state, the attribute prop belongs to the attribute, the method belongs to the method, what content you want to obtain is directly obtained through this, which is closer to JavaScript programming, and is relatively easy to understand.

Component transformation

For Vue's reverse object-oriented, we can change its writing method and compile our own writing method into the writing method that Vue needs to use in the form of syntax sugar.

vue-class-component

vue-class-componentIt is a package recommended by Vue's official English website. You can write vue components in class mode, which brings a lot of convenience:

  • Methods, hooks can directly write class methods
  • Computed attribute can be obtained directly through get
  • Initialize the attribute that data can be declared as class
  • All the others can be placed in the Component decorator

vue-property-decorator

vue-property-decorator This package completely relies on vue-class-component, provides multiple decorators to assist in the declaration of prop, watch, model and other attributes.

Compilation preparation

Since we are using decorator syntax sugar, we need to support alignment in our webpack's babel compiler.

First of all, class syntax support is supported. For babel6 and lower versions, you need to configure the class syntax support plugin to the babel plugin.babel-plugin-transform-class-properties, for babel7, you need to use plug-ins@babel/plugin-proposal-class-propertiesPerform syntax conversion to class.

Then there is the decorator syntax support. For babel6 and lower versions, you need to configure the decorator syntax support plugin to configure the babel plugin.babel-plugin-transform-decorators-legacy, for babel7, you need to use plug-ins@babel/plugin-proposal-decoratorsSyntax conversion of the decorator.

For baable6, configure .babelrc as follows

{
  "presets": ["env", "stage-1"],
  "plugins": [
   "transform-runtime",
   "syntax-dynamic-import",
   "transform-class-properties", // Added class syntax support   "transform-decorators-legacy" // Added decorator syntax support  ]
}

For Bable7, the official recommendation is to use it directly@vue/apppreset, this preset contains@babel/plugin-proposal-class-propertiesand@babel/plugin-proposal-decoratorsTwo plug-ins, and also include dynamic split loading chunks support@babel/plugin-syntax-dynamic-import, and also includes@babel/envpreset.babelrc configuration is as follows:

{
 "presets": [
   ["@vue/app", {
     "loose": true,
     "decoratorsLegacy": true
   }]
 ]
}

Rewrite components

After the compilation plugin is ready, we rewrite the above Vue component, the code is as follows

<template>
 <div>
  <h1>{{title}}</h1>
  <span>{{text}}<span>
  <button @click="setText">Button</button>
 </div>
</template>

<script>
import { Vue, Component, Watch, Prop } from 'vue-property-decorator';

@Component
export default class Demo extends Vue {

 text = 'hello world';

 @Prop({type: String, default: 'Vue Demo'}) title;

 @Watch('title')
 titleChange(newTitle, oldTitle) {
  (`Title from ${oldTile} Turned into ${newTitle}`)
 }

 setText(e) {
   = 'Clicked the button';
 }
}
</script>

So far, our components have been rewrited, and it seems relatively easier to understand compared to the previous "write configuration" writing method.

Note: The methods written in Vue's class are still not possible to use arrow functions. The detailed reason is not expanded here, probably because of the way Vue mounts functions internally.

View Development

Feature comparison

For the development of views, Vue advocates the writing of separation of html, js, and css, while React advocates all-in-js, all written in js.

Of course, each has its own advantages. For example, Vue separates it and has good code readability, but it cannot perfectly demonstrate JavaScript's programming ability in html. For React's jsx writing method, it allows us to complete view development more flexibly because of JavaScript's programming syntax support.

For this kind of inflexible situation, Vue also supports jsx, and only needs to add plugins in babelbabel-plugin-transform-vue-jsxbabel-plugin-syntax-jsxbabel-helper-vue-jsx-merge-props(babel6, for babel7, the official recommendation@vue/appThe preset already contains the jsx conversion plugin, and we can declare the render function in the component like React, and return the jsx object. As follows, we transform the components in the previous section:

Component transformation

<script>
import { Vue, Component, Watch, Prop } from 'vue-property-decorator';

@Component
export default class Demo extends Vue {

 title = 'hello world';

 @Prop({type: String, default: 'Vue Demo'}) title;

 @Watch('title')
 titleChange(newTitle, oldTitle) {
  (`Title from ${oldTile} Turned into ${newTitle}`)
 }

 setText(e) {
   = 'Clicked the button';
 }

 render() {
  const { title, text } = this;
  return <div>
   <h1>{title}</h1>
   <span>{text}<span>
   <button onClick={}>Button<button>
  </div>
 }
}
</script>

Notes on using jsx in Vue

Having written this, I basically found that its writing style is similar to React's class style. So what is the difference between Vue's jsx and React's jsx?

React's jsx syntax requires React support, that is, in modules that you use jsx, React must be introduced.

Vue's jsx syntax requires Vue's createElement support, that is, in the scope of your jsx syntax, the variable h must exist, and the variable h iscreateElementThe alias of this is a common convention in the Vue ecosystem. In render, the h variable is automatically injected into the scope by the compiler. For details of automatic injection, seeplugin-transform-vue-jsx, If there is no variable h, it needs to be retrieved and declared from the component, the code is as follows:

const h = this.$createElement;

Here, with the help of an official example, it basically contains all the commonly used syntax of Vue's jsx, as follows:

// ...
render (h) {
 return (
  <div
   // normal attributes or component props.
   
   // DOM properties are prefixed with `domProps`
   domPropsInnerHTML="bar"
   // event listeners are prefixed with `on` or `nativeOn`
   onClick={}
   nativeOnClick={}
   // other special top-level properties
   class={{ foo: true, bar: false }}
   style={{ color: 'red', fontSize: '14px' }}
   key="key"
   ref="ref"
   // assign the `ref` is used on elements/components with v-for
   refInFor
   slot="slot">
  </div>
 )
}

However, Vue's jsx syntax cannot support Vue's built-in directives, with the only exception being v-show, which can use the syntax of v-show={value}. Most instructions can be implemented programmatically, for examplev-ifIt's a ternary expression.v-forIt's just one()wait.

If it is a custom directive, you can use the v-name={value} syntax, but this syntax does not support the directive's arguments and modifier modifier. There are two solutions:

  • Pass everything in as an object, such as: v-name={{ value, modifier: true }}
  • Use native vnode instruction data formats, such as:
const directives = [
 { name: 'my-dir', value: 123, modifiers: { abc: true } }
]

return <div {...{ directives }}/>

So, when do we use jsx and when do we template? It is obvious that when faced with such complex and changeable view rendering, we can use jsx syntax to be more handy, and when faced with simple views, we can use template to develop faster.

Status Management

Feature comparison

For state management, Vue's Vuex and React's Redux are very similar, both are Flow data streams.

For React, the state needs to pass the state into the component's props through mapStateToProps, and the action needs to inject the action into the component's props through mapDispatchToProps, and then get and execute it in the component's props.

In Vue, the store can be directly in the $store of the componentthis.$(actionType)To distribute the action, the attribute can also be mounted to the component's computed through mapState or mapGetter.this.$orthis.$Get it very convenient.

Component transformation

In order to be more appropriate to the es6 class writing method and better cooperate with vue-class-component, we need to inject store data into the component in other ways.

vuex-class

vuex-class, the emergence of this package is to better connect Vuex and Vue components in the class method.

As follows, we declare a store

import Vuex from 'vuex';

const store = new ({
 modules: {
  foo: {
   namespaced: true,
   state: {
    text: 'hello world',
   },
   actions: {
    setTextAction: ({commit}, newText) => {
     commit('setText', newText);
    }
   },
   mutations: {
    setText: (state, newText) => {
      = newText;
    } 
   }
  }
 }
})

For this store, we rewrite the components from our previous chapter

&lt;template&gt;
 &lt;div&gt;
  &lt;h1&gt;{{title}}&lt;/h1&gt;
  &lt;span&gt;{{text}}&lt;span&gt;
  &lt;button @click="setText"&gt;Button&lt;/button&gt;
 &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
import { Vue, Component, Watch, Prop } from 'vue-property-decorator';
import { namespace } from 'vuex-class';

const fooModule = namespace('foo');

@Component
export default class Demo extends Vue {

 @('text') text;
 @('setTextAction') setTextAction;

 @Prop({type: String, default: 'Vue Demo'}) title;

 @Watch('title')
 titleChange(newTitle, oldTitle) {
  (`Title from ${oldTile} Turned into ${newTitle}`)
 }

 setText(e) {
  ('Clicked the button');
 }
}
&lt;/script&gt;

Here we can find that the store declares a foo module, and then removes the foo module from the store when using it, and then injects state and action into the component in the form of a decorator. We can omit the dispatch code and let syntax sugar help us dispatch. Such code looks more appropriate and object-oriented. . . OK, I admit that the code becomes more and more Java-like the more I write it.

However, before, I did not use Redux to develop React, but Mobx, so this form of dispatch -> action -> matation -> state is not very pleasant for me. I still prefer to write state management in the form of class. At this time, I found another package.vuex-module-decoratorsLet me rewrite mine.

Let's rewrite the above store:

import Vuex from 'vuex';
import { Module, VuexModule, Mutation, Action } from 'vuex-module-decorators';
 
@Module
class foo extends VuexModule {
 text = 'hello world'
 
 @Mutation
 setText(text) {
   = text;
 }
 
 @Action({ commit: 'setText' })
 setTextAction(text) {
  return text;
 }
}

const store = new ({
 modules: {
  foo: foo
})
export default store;

In this way, our project preparation is basically completed, and Vue components and Vuex state management are written in the form of a class. Maybe I think the writing style of es5 is not as elegant as that of es6.

Finish

The class syntax and decorators syntax are both proposals of ES6, and they both bring different programming experiences to the front-end. It is probably a relatively big change in the front-end. We should embrace such changes.

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.