Ways in which I feel Vue.js edges React

Vue.js exposes APIs to leverage the reactive system that automatically tracks changes and dependencies then updates your UI. On the other hand, react does not have

October 12, 20245 min read

I have been writing server-side code for the last couple of years, over the last six months I decided to get out of my comfort zone and try frontend. Turns out frontend development involves a lot more than just styling your interface. A couple of researches down the line and a recommendation from a friend I decided to try Vue.js as my first frontend framework. I would say I loved it, and I still do! I built a couple of projects with it and I was cruising. A few of months into writing Vue a friend was working on a react project and I decided to hop in and have a feel of the most famous frontend framework! It would be easy, the main concepts are the same, reusable components and all, or so I thought! Turns out there is some considerable differences , here are some of the ways in which I feel Vue has the upper hand.

Reactivity vs State management

React and Vue.js have different concepts on how to respond to changes in data. Vue.js exposes APIs to leverage the reactive system that automatically tracks changes and dependencies then updates your UI. On the other hand, react does not have a built-in reactive system, it relies on developers to explicitly call state setters to trigger updates. It has APIs that help you manage state and it’s side effects. I find Vue’s reactivity easier and beginner friendly. To illustrate this difference let us use a simple counter example

Vue

<template>
  <div>
    <h1>Vue Counter: {{ state.count }}</h1>
    <button @click="increment">Increment</button>
  </div>
</template>

<script>
import { reactive } from 'vue';

export default {
  setup() {
    const state = reactive({ count: 0 });

    const increment = () => {
      state.count++; // Automatically updates the UI
    };

    return { state, increment };
  },
};
</script>

The reactive() function creates a reactive state object. When state.count changes, Vue automatically updates the UI

React

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0); // State initialization

  const increment = () => {
    setCount(count + 1); // Explicitly set state
  };

  return (
    <div>
      <h1>React Counter: {count}</h1>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

export default Counter;

useState initializes the state and provides a setter function (setCount). You must explicitly call the setter when changing count or react will not trigger a rerender

Single file components vs Separating concerns

While React's separation of concerns approach is often praised for its modularity and maintainability, Vue.js' Single-File Components (SFCs) offer a compelling alternative for developers who prefer a more streamlined and cohesive development experience. I generally love Vue.js SFC components as opposed to React's separation of concern approach. SFC basically encapsulates all your relevant code (HTML, CSS, and JavaScript) into one file, while separation of concern in React divides separate aspects of the application into their distinct files, in this particular case the CSS file. The growing complexity of separate CSS files can indeed become a challenge. SFCs can alleviate this burden by allowing you to manage your styling directly within the component's context, potentially reducing the need for extensive CSS management outside of the component itself.

Vue

<template>
  <div>
    <h1>{{ title }}</h1>
    <button @click="increment">Click me</button>
    <p>Count: {{ count }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      title: "Vue SFC Example",
      count: 0,
    };
  },
  methods: {
    increment() {
      this.count++;
    },
  },
};
</script>

<style scoped>
h1 {
  color: blue;
}
button {
  margin-top: 10px;
}
</style>

React

import React, { useState } from 'react';

const ReactComponent = () => {
  const [count, setCount] = useState(0);
  const title = "React Component Example";

  const increment = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <h1>{title}</h1>
      <button onClick={increment}>Click me</button>
      <p>Count: {count}</p>
    </div>
  );
};

export default ReactComponent;

A separate css file is imported.

Try Kodaschool for free

Click below to sign up and get access to free web, android and iOs challenges.

Sign Up

Conditional rendering

In Vue.js conditional rendering is typically done through directives that dynamically render elements based on a condition while in react it is done using basic javascript expressions and statements. I find Vue.js’ declarative syntax easy to work with because it lets you define your condition easily in your mark up.

vue

<template>
  <div>
    <h1>Grade Evaluation</h1>
    <input type="number" v-model="score" placeholder="Enter your score" />
    
    <p v-if="score >= 90">You got an A!</p>
    <p v-else-if="score >= 80">You got a B!</p>
    <p v-else-if="score >= 70">You got a C!</p>
    <p v-else>You need to improve your score.</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      score: null,
    };
  },
};
</script>


React

import React, { useState } from 'react';

const GradeEvaluation = () => {
  const [score, setScore] = useState(null);

  const renderMessage = () => {
    if (score >= 90) {
      return <p>You got an A!</p>;
    } else if (score >= 80) {
      return <p>You got a B!</p>;
    } else if (score >= 70) {
      return <p>You got a C!</p>;
    } else {
      return <p>You need to improve your score.</p>;
    }
  };

  return (
    <div>
      <h1>Grade Evaluation</h1>
      <input 
        type="number" 
        value={score || ''} 
        onChange={(e) => setScore(e.target.value)} 
        placeholder="Enter your score" 
      />
      {renderMessage()}
    </div>
  );
};

export default GradeEvaluation;

Iteration

Just like conditional rendering, Vue.js iteration is done using directives, this allows you to loop over arrays and objects while in react it is done using javascript inbuilt map method. I particularly prefer Vue because reactivity automatically updates changes on the data while react updates on state change.

Vue

<template>
  <div>
    <h1>Fruit List</h1>
    <ul>
      <li v-for="fruit in fruits" :key="fruit.id">
        {{ fruit.name }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data() {
    return {
      fruits: [
        { id: 1, name: 'Apple' },
        { id: 2, name: 'Banana' },
        { id: 3, name: 'Cherry' }
      ],
    };
  },
};
</script>


React

import React from 'react';

const FruitList = () => {
  const fruits = [
    { id: 1, name: 'Apple' },
    { id: 2, name: 'Banana' },
    { id: 3, name: 'Cherry' },
  ];

  return (
    <div>
      <h1>Fruit List</h1>
      <ul>
        {fruits.map(fruit => (
          <li key={fruit.id}>{fruit.name}</li>
        ))}
      </ul>
    </div>
  );
};

export default FruitList;

Pinia vs Redux

The biggest challenge I faced when I started frontend development was state management, I first started with Vuex before shifting to a lightweight alternative Pinia. Pinia, a state management library built for vue, provides a simple and intuitive API built on top of Vue.js composition API. It feels less verbose compared to redux that has more boiler plate code due to the need for actions and reducers, which can be hectic for newcomers.

Vue

Setting up a Pinia store:

// store.js
import { defineStore } from 'pinia';

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
  }),
  actions: {
    increment() {
      this.count++;
    },
    decrement() {
      this.count--;
    },
  },
});

Using the Pinia store in a Vue component:

<template>
  <div>
    <p>Count: {{ count }}</p>
    <button @click="increment">Increment</button>
    <button @click="decrement">Decrement</button>
  </div>
</template>

<script setup>
import { useCounterStore } from './store';

const store = useCounterStore();
const { count, increment, decrement } = store;
</script>

React

Setting up a Redux store:

// store.js
import { createStore } from 'redux';

// Initial state
const initialState = {
  count: 0,
};

// Reducer function
const counterReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 };
    case 'DECREMENT':
      return { ...state, count: state.count - 1 };
    default:
      return state;
  }
};

// Create the Redux store
const store = createStore(counterReducer);

export default store;

Creating actions:

// actions.js
export const increment = () => ({ type: 'INCREMENT' });
export const decrement = () => ({ type: 'DECREMENT' });

Using the Redux store in a React component

// Counter.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement } from './actions';

const Counter = () => {
  const count = useSelector((state) => state.count);
  const dispatch = useDispatch();

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => dispatch(increment())}>Increment</button>
      <button onClick={() => dispatch(decrement())}>Decrement</button>
    </div>
  );
};

export default Counter;

Conclusion

There is a steeper learning curve when you switch from writing vue.js to writing react, even though both use component based architecture the way in which components are structured and managed differs. Vue.js has a better developer experience and it is easy to learn for beginners, on the other hand the flexibility of react in terms of choosing libraries and tools can lead to decision fatigue. In terms of project requirements, react would be a more suitable choice for complex and larger projects that require total control over performance and scalability. Finally I have learnt that switching frameworks can be an opportunity for professional growth.

Peace!

Jackson Obere

About Jackson Obere

I enjoy working with front-end technologies like Vue, React, and Vanilla JavaScript, with some Python on the side. I love building interactive web experiences and breaking down tricky concepts to make them easier to understand. I'm always curious and enjoy learning new things in the ever-evolving tech space.