45

I created the exact same app in React and Vue

 5 years ago
source link: https://www.tuicool.com/articles/hit/zEBfuum
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

I created the exact same app in React and Vue. Here are the differences.

*Updated on 28th July, 2018.

Having used Vue at my current workplace, I already had a fairly solid knowledge of how it all worked. I was, however, curious to know what the grass was like on the other side of the fence — the grass in this scenario being React.

I’d read the React docs and watched a few tutorial videos and, while they were great and all, what I really wanted to know was how different React was from Vue. By “different”, I didn’t mean things such as whether they both had virtual DOMS or how they went about rendering pages. What I really wanted was a side-by-side code comparison, to really understand the differences when it came to building things in the two frameworks.

fI7jIvz.png!web
Who wore it better?

The annoying thing was that, even after both frameworks being in existence for the past four years, I couldn’t find anything that tackled this — surely I wasn’t the only person who wanted to see a side-by-side code comparison. I came to the realisation that I’d have to go ahead and build this myself in order to see the similarities and differences. In doing so, I thought I’d document the whole process so that an article on this will finally exist.

I decided to try and build a fairly standard To Do App that allows a user to add and delete items from the list. Both apps were built using the default CLIs (create-react-app for React, and vue-cli for Vue). If you’re not already aware, a CLI (short for Command Line Interface) is basically a thing that you can install via npm that allows you to terminal/command line commands that will quickly build a general Vue/React file structure for you, and will include lots of cool extras that would otherwise take a fair bit of time to set up manually.

Anyway, this intro is already longer than I’d anticipated. So let’s start by having a quick look at how the two apps look:

7vemaaq.png!web
Vue vs React: The Irresistible Force meets The Immovable Object

The CSS code for both apps are exactly the same, but there are differences in where these are located. With that in mind, let’s next have a look at the file structure of both apps:

rMfeumV.png!web

You’ll see that their structures are almost identical as well. The only difference here is that the React app has three CSS files, whereas the Vue app doesn’t have any. The reason for this is because, traditionally, a React component will have an accompanying file to hold its styles, whereas Vue adopts an all encompassing approach, where the styles are declared inside the actual component file. Ultimately, they both achieve the same thing and I guess that one is just down to personal preference.

Theoretically, you could abandon both approaches and simply opt to use a good old fashioned style.css file to hold the styles for the entire page, it’s really up to you when it comes to how you choose to style your app. For that reason, I won’t go on about it for much longer — I will show you where you put the styles in a .vue file later though just so you know what it looks like:

QZjmeqa.png!web
A boring picture of a typical Vue component

Okay, now that styles are out of the way, let’s get into the nitty gritty detail!

How do we mutate data?

But first, what do we even mean by “mutate data”? Sounds a bit technical doesn’t it? It basically just means changing the data that we have stored. So if we wanted to change the value of a person’s name from John to Mark, we would be ‘mutating the data’. So this is where a key difference between React and Vue lies. While Vue essentially creates a data object, where data can freely be updated, React creates a state object, where a little more legwork is required to carry out updates. Now React implements the extra legwork with good reason, and we’ll get into that in a little bit. But first, let’s take a look at the state object from React and the data object from Vue:

2aqMrmM.png!web
React state object which holds our ToDo list data
qMrUVrf.png!web
Vue data object which holds our To Do list data

So you can see that we have passed the same data into both, but they’re simply labelled differently. So passing initial data into our components is very, very similar. But as we’ve mentioned, how we go about changing this data differs between both frameworks.

Let’s say that we have an data element called name: ‘Sunil’. In Vue, we reference this by calling this.name . We can also go about updating this by calling this.name = ‘John’ . This would change my name to John. I’m not sure how I feel about being called John, but hey ho, things happen! :)

In React, we would reference the same piece of data by calling this.state.name . Now the key difference here is that we cannot simply write this.state.name = ‘John’, because React has restrictions in place to prevent this kind of easy, care-free mutation-making. So in React, we would write something along the lines of this.setState({name: ‘John’}) . While this essentially does the same thing as we achieved in Vue, the extra bit of writing in there to stop us from accidentally overwriting this.state, as there’s a clear difference between this.state and this.setState. There are actually reasons here for why React makes mutations differently to Vue, but we won’t get into them here.

VjIjEv6.jpg!web
Bean knew best

Now that we have mutations out of the way, let’s get into the nitty, gritty by looking at how we would go about adding new items to both of our To Do Apps.

How do we create new To Do Items?

React:

createNewToDoItem = () => {
this.setState( ({ list, todo }) => ({
list: [
...list,
{
todo
}
],
todo: ''
})
);
};

Vue:

createNewToDoItem() {
this.list.push(
{
'todo': this.todo
}
);
this.todo = '';
}

How did React do that?

In React, our input field has a handle on it called value. This value gets added automatically updated through the use of a couple of functions that tie together to create two-way binding (if you’ve never heard of this before, there’s a more detailed explanation in the How did Vue do that section after this). React handles two-way binding by having an additional onChange function attached to the input field. Let’s quickly take a look at the input field so that you can see what is going on:

<input type="text" 
value={this.state.todo}
onChange={this.handleInput}/>

The handleInput function is ran whenever the value of the input field changes. It updates the todo that sits inside the state object by setting it to whatever is in the input field. This function looks as such:

handleInput = e => {
this.setState({
todo: e.target.value
});
};

Now, whenever a user presses the + button on the page to add a new item, the createNewToDoItem function essentially runs this.setState and passes it a function. This function takes two parameters, the first being the entire list array from the state object, the second being the todo (which gets updated by the handleInput function). The function then returns a new object, which contains the entire list from before and then adds todo at the end of it. The entire list is added through the use of a spread operator (Google this if you’ve not seen this before — it’s ES6 syntax).

Finally, we set todo to an empty string, which automatically updates the value inside the input field.

How did Vue do that?

In Vue, our input field has a handle on it called v-model . This allows us to do something known as two-way binding . Let’s just quickly look at our input field, then we’ll explain what is going on:

<input type="text" v-model="todo"/>

V-Model ties the input of this field to an key we have in our data object called toDoItem. When the page loads, we have toDoItem set to an empty string, as such: todo: ‘’ . If this had some data already in there, such as todo: ‘add some text here’ , our input field would load with add some text here already inside the input field. Anyway, going back to having it as an empty string, whatever text we type inside the input field gets bound to the value for todo . This is effectively two-way binding (the input field can update the data object and the data object can update the input field).

So looking back at the createNewToDoItem() code block from earlier, we see that we push the contents of todo into the list array and then update todo to an empty string.

How do we delete from the list?

React:

deleteItem = indexToDelete => {
this.setState(({ list }) => ({
list: list.filter((toDo, index) => index !== indexToDelete)
}));
};

Vue:

this.$on(‘delete’, (event) => {
    this.list = this.list.filter(item => item.todo !== event)
})

How did React do that?

So whilst the deleteItem function is located inside ToDo.js , I was very easily able to make reference to it inside ToDoItem.js by firstly, passing the deleteItem() function as a prop on <ToDoItem/> as such:

<ToDoItem deleteItem={this.deleteItem.bind(this, key)}/>

This firstly passes the function down to make it accessible to the child. You’ll see here that we’re also binding this as well as passing the key parameter, as key is what the function is going to use to be able to differentiate between which ToDoItem is attempting to delete when clicked. Then, inside the ToDoItem component, we do the following:

<div className=”ToDoItem-Delete” onClick={this.props.deleteItem}>-</div>

All I had to do to reference a function that sat inside the parent component was to reference this.props.deleteItem .

How did Vue do that?

A slightly different approach is required in Vue. We essentially have to do three things here:

Firstly, on the element we want to call the function:

<div class=”ToDoItem-Delete” @click=”deleteItem(todo)”>-</div>

Then we have to create an emit function as a method inside the child component (in this case, ToDoItem.vue), which looks like this:

deleteItem(todo) {
this.$parent.$emit(‘delete’, todo)
}

Then our parent function, which is the this.$on(‘delete’) event listener triggers the filter function when it is called upon.

In short, child components in React will have access to parent functions via this.props (providing you are passing props down — but this is fairly standard practice anyway and you’ll come across this loads of times in other React examples), whilst in Vue, you have to emit events from the child back to the parent. The parent then needs to listen out for this and run the function when it gets called upon.

It’s also worth noting here that in the Vue example, I could have simply written the $emit part inside of the @click listener, as such:

<div class=”ToDoItem-Delete” @click=”this.$parent.$emit(‘delete’, todo)”>-</div>

This would have reduced the number of steps down from 3 to 2, and this is simply down to personal preference.

How do we pass event listeners?

Vue:

In Vue it is super straight-forward. We simply use the @ symbol, and then the type of event-listener we want to do. So for example, to add a click event listener, we could write the following:

<div class=”ToDo-Add” @click=”createNewToDoItem()”>+</div>

Note: @click is actually shorthand for writing v-on:click . The cool thing with Vue event listeners is that there are also a bunch of things that you can chain on to them, such as .once which prevents the event listener from being triggered more than once. There are also a bunch of shortcuts when it comes to writing specific event listeners for handling key strokes. I found that it took quite a bit longer to create an event listener in React to create new ToDo items whenever the enter button was pressed. In Vue, I was able to simply write:

<input type=”text” v-on:keyup.enter=”createNewToDoItem”/>

React:

Event listeners for simple things such as click events are straight forward. Here is an example of how we created a click event for a button that creates a new ToDo item:

<div className=”ToDo-Add” onClick={this.createNewToDoItem}>+</div>.

Super easy here and pretty much looks like how we would handle an in-line onClick with vanilla JS. As mentioned in the Vue section, it took a little bit longer to set up an event listener to handle whenever the enter button was pressed. This essentially required an onKeyPress event to be handled by the input tag, as such:

<input type=”text” onKeyPress={this.handleKeyPress}/>.

This function essentially triggered the createNewToDoItem function whenever it recognised that the ‘enter’ key had been pressed, as such:

handleKeyPress = (e) => {
if (e.key === ‘Enter’) {
this.createNewToDoItem();
}
};

How do we pass data through to a child component?

Vue:

In react, we pass props onto the child component at the point where it is created. Such as:

<ToDoItem v-for="item in this.list"
          :todo="item.todo"
          :key="list.indexOf(item)"
          :id="list.indexOf(item)"
>
</ToDoItem>

Once this is done, we then pass them into the props array in the child component, as such: props: [ ‘id’, ‘todo’ ] . These can then be referenced in the child by their names, so ‘ id ’ and ‘todo ’.

React:

In react, we pass props onto the child component at the point where it is created. Such as:

<ToDoItem key={key} item={todo} />

Here we see two props passed to the ToDoItem component. From this point on, we can now reference them in the child component via this.props. So to access the item.todo prop, we simply call this.props.todo.

How do we emit data back to a parent component?

Vue:

In our child component, we simply write a function that emits a value back to the parent function. In our parent component, we write a function that listens for when that value is emitted, which can then trigger a function call. We can see an example of this entire process in the section ‘How do we delete from the list’

React:

We firstly pass the function down to the child component by referencing it as a prop in the place where we call the child component. We then add the call the function on the child by whatever means, such as an onClick , by referencing this.props.whateverTheFunctionIsCalled . This will then trigger the function that sits in the parent component. We can see an example of this entire process in the section ‘How do we delete from the list’.

And there we have it! :tada:

We’ve looked at how we add, remove and change data, pass data in the form of props from parent to child, and send data from the child to the parent in the form of event listeners. There are, of course, lots of other little differences and quirks between React and Vue, but the hopefully the contents of this article has helped to serve as a bit of a foundation for understanding how both frameworks handle stuff

Github links to both apps:

Vue ToDo: https://github.com/sunil-sandhu/vue-todo

React ToDo: https://github.com/sunil-sandhu/react-todo

This article was updated on July 28th 2018, following suggestions from Dan Charousek , who kindly made recommendations for improving the Vue ToDo app, and Lucas Everett who made some fantastic suggestions for the React ToDo app (he also rewrote the createNewToDoItem and deleteItem functions)


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK