Vue3 introduced composition API and officially supported JSX, which makes Vue3 very similar to React. Students who are familiar with React can use Vue3 directly. I’ll probably write a series on the differences between React and VUe3 functionality.
State hooks
What is a state? React and vue3 implement an increment button
// React
const Button = () = > {
const [count, setCount] = useState(0);
return <button onClick={()= > setCount(prev => prev+1)}>{count}</button>
}
Copy the code
// Vue
const Button = defineComponent({
setup() {
const count = ref(0);
return () = > <button onClick={()= > count.value++}>{count.value}</button>}})Copy the code
This is a simple example. React maintains count through the useState hook and vue maintains count through the REF API
Let’s see the difference
immutable VS mutable
The React state is immutable, so you cannot modify it directly. In this example, you can only change count by setCount, the next time you render, the reference address of count will have changed.
Vue is a mutable state, you can modify it directly, in this case count. Value++ will work, and the next rendering will not change the reference address of count.
I personally like the mutable nature of vue.
Vue is more convenient for deep state changes.
Let’s upgrade count to bookList[0].store.count
// React
const Button = () = > {
const [bookList, setBookList] = useState([{
store: {
count: 0,}}]);const handleClick = useCallback(() = > {
setBookList(prev= > prev.map((book, index) = >index ! = =0? book : ({ ... book,store: {
...book.store,
count: book.store.count + 1}}))); } []);return <button onClick={handleClick}>{count}</button>
}
Copy the code
React is cumbersome to write without the help of third-party tools.
// Vue
const Button = defineComponent({
setup() {
const bookList = reactive([{
store: {
count: 0,}}])return () = > (
<button onClick={()= > bookList[0].store.count++}>
{count.value}
</button>)}})Copy the code
Vue introduces another composition API: Reactive. React is much easier to write than react. You just assign it.
Vue can get the latest value of the state synchronously.
Here’s another example:
// React
const Button = () = > {
const [count, setCount] = useState(0);
const handleClick = useCallback(() = > {
setCount(count + 1);
// or setCount(prev => prev + 1)
console.log(count); // The output of count is lagged,
}, [count]);
return <button onClick={handleClick}>{count}</button>
}
Copy the code
After you update count, get the value of count, and get the old value. This is a corollary of the IMmutable + closure.
Closures cause references to variables inside to be immutable, and immutable values cause variables to be immutable, making it impossible to obtain the latest value of a state.
The next best thing is that we can only get it indirectly, such as setCount(prev => prev + 1), where prev must be the latest value. But it limits you to only get the latest value of one state, which is a bit of a mind-set when components get complicated, you need to adjust state Settings, adjust execution order, set temporary variables, etc.
This is one of the reasons why some students like to unify state management, such as using Redux. However, I have always been against centralized management of state, which is to write the logical code of many components together, making the code difficult to read and maintain. We should decentralize, which means componentize.
// Vue
const Button = defineComponent({
setup() {
const count = ref(0);
const handleClick = () = > {
count.value++;
console.log(count.value); // This is synchronized
}
return () = > <button onClick={handleClick}>{count.value}</button>}})Copy the code
In VUE, there is no such worry at all; the state is always synchronized.
no setup vs setup
Unlike React, there is a setup function in the vue code. This function is initialized only once before a component is first rendered.
The react function returns the setup function, which is also a function, i.e., a render function. It is executed every time it is rendered.
The benefit of having setup is obvious, since you only execute it once, you’re bound to get all the speed improvements.
React you’ll often need to write useCallback to cache a function. In VUe3, this is completely unnecessary, as all functions defined in setup are executed only once, with no need to cache.
Proxy vs raw object
In contrast to React, Vue uses Proxy to track state changes and monitor state usage and modification. This has the advantage of reducing the mental burden of deciding when to update. All are controlled internally by VUE. React you might have to constantly consider whether to add memo, useCallback, and useMemo
But Proxy also presents some writing problems:
The ref state is going to keep writing.value
Proxy can only be applied to objects, but cannot be applied to basic types. For primitive types, VUe3 presents ref as a solution to store these primitive types in the value attribute of an object. But the problem is that when you reference and modify, you write.value. This is really troublesome.
Of course, there are some special cases where vue3 doesn’t need to write.value
- Do not write.value in the template. This doesn’t work for me, because I don’t like templates as much as JSX. The biggest problem with templates is that they don’t use variables defined in JS directly. Instead, they require you to return the variables used, which is not very cool.
- When you access a ref type through Reactive, you do not need to write.value.
const count = ref(10);
const data = reactive({ count });
console.log(data.count) / / 10
console.log(isRef(toRaw(data).count)) // true
Copy the code
You can’t deconstruct it
Destruct is the syntax const {name, id} = user
Again, proxies only work on Object, so when you deconstruct a variable of primitive type, that variable can’t be a Proxy, and it loses its ability to trace.
When you deconstruct an object variable from Reactive, it will still be a proxy, and it will still be able to respond to tracing, but it may not be correct because the variable will be deleted by the top layer. For this reason, one of vuE3’s ESLint rules is not to deconstruct props.
const data = reactive({
a : {
b: 1}});const { a } = data;
data.a = { b: 10 };
console.log(data.a === a) // false
// no change after click.
return () = > <button onClick={()= > a.b = 100}>{data.a.b}</button>
Copy the code
Of course, structuring can be done safely under some conditions: for example, if no assignment is required, it can be done in the Render function of return, computed, watchEffect, and so on.
const data = reactive({
count: 0
});
setInterval(() = > {
data.count++;
}, 1000);
return () = > {
const { count } = data;
return <div>{count}</div>
}
Copy the code
conclusion
Vue3 uses a Proxy to solve React’s problems, such as the difficulty of obtaining the latest state values, the difficulty of modifying deep objects, and the mental burden of handling updates. At the same time it also has some disadvantages, ref troublesome.value, there are potential problems in deconstruction.