In comparing the React framework and the Vue framework, let's write the same program in both and examine the differences in their code implementations.
Reprinted from: https://blog.csdn.net/csdnnews/article/details/81880378
Original article: https://medium.com/javascript-in-plain-english/i-created-the-exact-same-app-in-react-and-vue-here-are-the-differences-e9a1ae8077fd
Author: Sunil Sandhu, a web full-stack engineer + dreamer.
Translator: An Xiang, editor: Tu Min
As we all know, Vue and React are currently very famous front-end frameworks. I often use Vue in my work, so I have a deep understanding of it. At the same time, I am also curious about React and want to learn more about it.
So I read the React documentation and watched some video tutorials. Although these resources are great, what I really want to understand are the differences between React and Vue. By "differences," I don't mean whether they both have virtual DOMs or how they render pages, but rather I hope someone can explain the differences between the two from a coding perspective. I wanted to find an article that explains these differences so that beginners in Vue or React can better understand them.
Unfortunately, I did not find such an article. So I realized I had to compare Vue and React myself. During my self-study process, I documented the specific process in this article.
1. Objective#
I will build a standard to-do list application that allows users to add and delete items from the list. Both applications will be built using the default CLI (command-line interface), with React using create-react-app and Vue using vue-cli.
The appearance of both applications is as follows:
The CSS code for both applications is almost identical, but the locations of the code differ. With that in mind, let's take a look at the file structure of both applications:
You will find that their structures are almost identical. The only difference is that the React App has three CSS files, while the Vue App has none. This is because the create-react-app component requires an accompanying file to store its styles, while Vue CLI adopts an all-in-one approach, declaring its styles within the actual component files.
The results from these two different strategies are the same, and I believe developers will quickly master both strategies. Developers can choose based on their preferences, and you will hear a lot of discussions in the development community about how to build CSS. Above, we followed both CLIs to list the code structure.
Before we discuss further, let's quickly look at what typical Vue and React components look like:
Now let's officially begin and delve into the details!
2. How to Modify Data#
First, we need to understand what "modifying data" means. It sounds a bit academic, but it's actually quite simple; it means changing the data we have already stored. For example, if we want to change a person's name variable from "Jhon" to "Mark," we need to perform the "modify data" operation. At this point, React and Vue handle this differently. Vue essentially creates a data object that can be freely modified; React creates a state object, and modifying data requires some additional operations. React needs these extra operations for its own reasons, which I will explain in more detail later. Before that, let's take a look at the data object in Vue and the state object in React:
Vue Data Object
React State Object
From the images, we can see that we passed in the same data, but their marking methods differ. Therefore, the way initial data is passed to components is very similar. But as we mentioned, the way to change data in the two frameworks is different.
Suppose we have a data element named name: 'Sunil'.
In Vue, we reference it by calling this.name. We can also update it by calling this.name = 'John'. This successfully changes the name to "Jhon".
In React, we reference the same piece of data by calling this.state.name. Now the key difference is that we cannot simply write this.state.name = 'John' because React has restrictions that prevent this simple modification. In React, we need to write: this.setState({name: 'John'}).
Although this essentially achieves the same result as we implemented in Vue, the operation in React is more cumbersome because Vue combines its own setState version by default every time data is updated. In simple terms, React requires setState to update its internal data, while for Vue, when you update the value of the data object, it assumes your intention to change it. So why doesn't React simplify this? Why is setState necessary? Revanth Kumar explains:
"This is because React wants to rerun certain lifecycle hooks when the state changes, such as componentWillReceiveProps, shouldComponentUpdate, componentWillUpdate, render, componentDidUpdate. When you call the setState function, it knows the state has changed. If you directly change the state, React will need to do more work to track the changes and run lifecycle hooks, etc. So for simplicity, React uses setState."
3. Adding New To-Do Items#
React Implementation#
createNewToDoItem = () => {
this.setState(({ list, todo }) => ({
list: [
...list,
{
todo
}
],
todo: ''
})
);
};
In React, our input field has a property called value. This value is automatically updated using several functions that are bound together to create two-way binding. We create this form of two-way binding by attaching an onChange event listener to the input field. Let's take a look at the code:
<input type="text"
value={this.state.todo}
onChange={this.handleInput}/>
Whenever the value of the input field changes, the handleInput function runs. It updates the state object’s todo with whatever is in the input field. The handleInput function is as follows:
handleInput = e => {
this.setState({
todo: e.target.value
});
};
Now, whenever the user presses the + button on the page to add a new item, the createNewToDoItem function will run this.setState and pass it a function. This function has two parameters: the entire list array from the state object and the todo updated by the handleInput function. The function then returns a new object that contains the entire previous list and adds todo at the end. The entire list is added using the spread operator.
Finally, we set todo to an empty string, which automatically updates the value in the input field.
Vue Implementation#
createNewToDoItem() {
this.list.push(
{
'todo': this.todo
}
);
this.todo = '';
}
In Vue, our input field has a handle called v-model. This implements two-way binding. The input field code is as follows:
<input type="text" v-model="todo"/>
v-model binds the content of the input field to a key in the data object named toDoItem. When the page loads, we set toDoItem to an empty string, for example: todo: ' '. If there is already data, such as todo: 'Add text here', the input field will load the input content of "Add text here". In any case, as an empty string, any text we type in the input field will bind to todo. This is essentially 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 previous createNewToDoItem() code block, we store the content of todo in the list array and then set todo to an empty string.
4. Deleting To-Do Items#
React Implementation#
deleteItem = indexToDelete => {
this.setState(({ list }) => ({
list: list.filter((toDo, index) => index !== indexToDelete)
}));
};
Although the deleteItem function is located in the ToDo.js file, it is also easy to reference it from the ToDoItem.js file by passing the deleteItem() function as a prop:
<ToDoItem deleteItem={this.deleteItem.bind(this, key)}/>
This passes the function to the child component, allowing it to access it. We bind this and pass the key parameter, so when the user clicks to delete an item, the function distinguishes which ToDoItem the user clicked on by the key. Then, within the ToDoItem component, we do the following:
<div className="ToDoItem-Delete" onClick={this.props.deleteItem}>-</div>
To reference a function located in the parent component, simply reference this.props.deleteItem.
Vue Implementation#
onDeleteItem(todo){
this.list = this.list.filter(item => item !== todo);
}
Vue's implementation is slightly different; we need to do the following three things:
- First, call the function on the element:
<div class="ToDoItem-Delete" @click="deleteItem(todo)">-</div>
- Then we must create an emit function as an internal method of the child component (in this case, ToDoItem.vue), as follows:
deleteItem(todo) {
this.$emit('delete', todo)
}
- After that, you will find that when we add ToDo.vue to ToDoItem.vue, we are actually referencing a function:
<ToDoItem v-for="todo in list"
:todo="todo"
@delete="onDeleteItem" // <-- this :)
:key="todo.id" />
This is called a custom event listener. It listens for any triggered event using the string 'delete'. Once the event is detected, it triggers a function called onDeleteItem. This function is located inside ToDo.vue, not ToDoItem.vue. As mentioned earlier, this function simply filters the todo array within the data object to remove the clicked to-do item.
It is also worth noting in the Vue example that we can write the $emit part in the @click listener, making it simpler, as follows:
<div class="ToDoItem-Delete" @click="$emit('delete', todo)">-</div>
If you prefer, this can reduce the three steps to two.
In React, child components can access parent functions via this.props, while in Vue, you need to emit events from the child component for the parent to collect them.
5. How to Pass Event Listeners#
React Implementation#
Handling event listeners for simple events (like clicks) is very straightforward. We created a click event for the to-do items to create new to-do items, as follows:
<div className="ToDo-Add" onClick={this.createNewToDoItem}>+</div>
Very simple, just like handling inline onClick with vanilla JS. As mentioned earlier, setting up event listeners when pressing the enter key takes longer. This requires handling the onKeyPress event for the input tag, as follows:
<input type="text" onKeyPress={this.handleKeyPress}/>
This function triggers the createNewToDoItem function whenever it detects that the 'enter' key has been pressed, as follows:
handleKeyPress = (e) => {
if (e.key === 'Enter') {
this.createNewToDoItem();
}
};
Vue Implementation#
Vue's event listeners are more straightforward. We just need to use a simple @ symbol to build the event listeners we want. For example, to add a click event listener, the code is:
<div class="ToDo-Add" @click="createNewToDoItem()">+</div>
Note: @click is actually shorthand for v-on. Vue event listeners are powerful; you can choose attributes for them, such as .once to prevent the event listener from being triggered multiple times. Additionally, it includes many shortcuts. When pressing the enter key, React takes longer to create the event listener to create new To-Do items. In Vue, the code is as follows:
<input type="text" v-on:keyup.enter="createNewToDoItem"/>
6. How to Pass Data to Child Components#
React Implementation#
In React, we pass props to the child component at the point of creation. For example:
<ToDoItem key={key} item={todo} />
Here we pass two props to the ToDoItem component. Then, we can reference them in the child component via this.props. Therefore, to access the item.todo prop, we simply call this.props.item.
Vue Implementation#
In Vue, we pass props to the child component at the point of creation as follows:
<ToDoItem v-for="todo in list"
:todo="todo"
:key="todo.id"
@delete="onDeleteItem" />
We pass them to the props array in the child component, such as: props: ['id', 'todo']. Then they can be referenced in the child component by name.
7. How to Send Data Back to Parent Components#
React Implementation#
We first pass a function to the child component by referencing it as a prop when we call the child component. Then we add a call to the function in the child component by referencing this.props.whateverTheFunctionIsCalled, for example, onClick. This triggers the function in the parent component. The entire process is detailed in the section on deleting to-do items.
Vue Implementation#
In the child component, we simply write a function to send a value back to the parent function. In the parent component, we write a function to listen for when the child component emits that value's event, triggering the function call once the event is detected. Again, the entire process is detailed in the section on deleting to-do items.
8. Conclusion#
We explored adding, deleting, and changing data, passing data from parent components to child components as props, and sending data from child components back to parent components through event listeners. Of course, there are some minor differences between React and Vue, and I hope the content of this article helps to understand these two frameworks.
The GitHub addresses for both applications are:
Vue ToDo: https://github.com/sunil-sandhu/vue-todo
React ToDo: https://github.com/sunil-sandhu/react-todo