Angular, as the pioneer of single-page applications, is losing market share to Vue and React, but it is undeniable that Angular provides many lessons for React and Vue. Examples such as bidirectional binding, component decoupling, responsive development, including the use of TypeScript, provide a good way forward for the next two frameworks. React Hook, Vue 3.0, React Hook, React Hook, Vue 3.0, React Hook, React Hook, Vue 3.0, React Hook, React Hook, Vue 3.0, React Hook, React Hook, Vue 3.0, React Hook, React Hook, Vue 3.0, React Hook, React Hook, Vue 3.0, React Hook, React Hook Let’s explore it together.

The motivation

In fact, each framework version update has only two purposes: to solve problems and to solve more problems. Only in this way can the framework keep its vitality and vitality.

Vue 3.0

In the Vue 2.0 code pattern, complex code becomes harder to maintain as it grows in functionality, especially when it comes to accepting code from others. The root reason for this is that Vue’s existing APIS organize code through options, but in real business scenarios we often prefer to use logic to organize code. In addition, there is also a lack of a relatively pure reuse logic mechanism between components, the same type of inference is not friendly, these problems made Vue need to propose a better solution, so, Vue 3.0 design began.

React Hook

In traditional class components, it is difficult to reuse state logic between components. Components composed of providers, consumers, higher-order components, render, props and other abstraction layers will form a “nested hell”, resulting in poor code reusability and readability. As a result, these complex components become difficult to understand, and development and maintenance become increasingly difficult as the project progresses. Hook is designed to solve these problems.

New features

By comparing the design motivations of the two frameworks, it is easy to find that both frameworks need to solve problems such as improving the reusability and readability of code. So the update features and patterns of the two frameworks are like two cars starting from different places and going to the same destination, so some roads must be the same. Let’s take a look at some of the similarities and differences.

Vue 3.0

The release of Vue 3.0 caused a great sensation in the community, and there was a lot of criticism in the community. The most popular criticism was that Vue 3.0 was a copy of React Hook. The new features made Vue look more like React than React. React Hook has some design ideas that Vue 3.0 does borrow from React Hook, because React works well. In fact, as an open source framework designer, willing to learn from others’ advantages, and seriously to learn, which is the basis of the continuous maturity of the framework. Besides, frameworks are just tools, we use them for efficiency, and there’s no need to nitpick. With that said, let’s take a look at what’s new in Vue 3.0.

1. The setup function

Among the new features of the Composition API, the setup function is the unified entry point, and the setup function executes before beforeCreate and Created. In Vue 3.0, the beforeCreate and Created life cycles are also missing, so setup can also be viewed as a life cycle function. Why is this the entrance? In Vue 3.0, we no longer write data, methods, watch, computed and other methods separately. These methods are all put in the setup function. Similarly, we no longer need to use this to fetch data. For example:

<template>
  <div class="example">
    <div class="content">
      <span>{{ count }}</span>
      <span>{{ pushNumber }}</span>
    </div>
    <div class="action">
      <button @click="countNumber">increase</button>
      <button @click="reduce">To reduce</button>
      <button @click="push">Add an array</button>
      <button @click="resetArray">Reset the array</button>
    </div>
  </div>
</template>
<script lang="ts">
import { reactive, ref, toRefs } from 'vue';

export default {
  props: {
    value: String,},setup() {
    const count: number = ref<number>(0);
    const array: any = reactive({
      pushNumber: [],});const countNumber = () = > {
      console.log(this.'this');
      count.value += 1;
    };
    const reduce = () = > {
      const newValue = count.value;
      count.value -= 1;
      return newValue;
    };
          
    const push = () = > {
      array.pushNumber.push(1);
    };
    const resetArray = () = > {
      array.pushNumber.splice(0, array.length);
    };
    return{ count, ... toRefs(array), countNumber, reduce, push, resetArray, }; }};</script>
Copy the code

In the sample code above, we can see that Vue 3.0 has no separate data, method, computed, and other methods, but all integrated into the setup function, and sharp-eyed people will immediately notice that this is missing. It can be called as soon as the data is returned from setup, and Vue 3.0 sets this to undefined in order not to confuse its use. UseEffect setup setup setup setup setup setup setup setup setup setup Ref and Reactive are very similar to setState. It can be said that this part of Vue 3.0 does borrow the React Hook model, but there are some differences. We can compare the details with the React Hook code later. What are refs and Reactive? Let’s discuss it together.

  • Ref (responsive variable)

    In Vue 3.0, there is no data declaration data, but a ref, many people will be confused, what is this thing, it is not a Vue. But if you use ref you’ll see how good it is. Let’s see what the official documentation says about ref: “REF takes the parameter and returns it wrapped in an object with value, property, and can then use that property.”

Here’s another example:

import { ref } from 'vue';

const counter = ref(0);
console.log(counter); // { value: 0 }
console.log(counter.value); / / 0
counter.value += 1;
console.log(counter.value); / / 1
Copy the code

From the example, it is clear that counter is an object and ref encapsulates the value in an object. The value is obtained by the counter. Value method. Because in JavaScript, simple data types such as String and Number are passed by value rather than by reference, wrapping an object around a value ensures that it will not lose its responsiveness at some point in passing. We can understand this by looking at the following diagram:

In general, the ref is used to keep the view layer aware of data changes and render accordingly for responsive references.

  • Reactive (Can listen to all variables)

    Reactive is used to listen for reference data types, pass in an object and return a reactive Proxy based on the original object. This is equivalent to Vue. Observer in Vue 2.0. But in previous Vue 2.0, it only listened for properties of objects, not objects. So Reactive is based on ES2015 Proxy for the responsive processing of data objects, that is, in Vue 3.0 you can add attributes to objects that have a responsive effect.

Again, let’s use an example to see how to use Reactive:

import{reactive, toRefs}from 'vue';

export default {
  const state = reactive({
    newArr: [1.23].newStr: { a: 1.b: 2}});console.log(state); // { newArr:[1, 23], newStr:{ a: 1, b: 2 } };
  console.log(state.newArr); / / [23] 1,
  state.newArr.splice(0.1);
  console.log(state.newArr); / / [23]
  return{
    ...toRefs(state),
  };
};
Copy the code

But what is another toRefs in the code above? Let’s look at the toRefs source code:

function toRefs(object) {
  if((process.env.NODE_ENV ! = ='production') && !isReactive(object)) {
    console.warn(`toRefs() expects a reactive object but received a plain one.`);
  };
  for (const key in object) {
    ret[key] = toProxyRef(object, key);
  };
  return ret;
};
function toProxyRef(object, key) {
  return {
    _isRef: true.get value() {
      return object[key];
    },
    set value(newVal) {
      object[key] = newVal;
    };
  };
};
Copy the code

It is clear from the source code that toRefs returns a normal Proxy object with a get and set. This solves the problem of Proxy objects failing to respond when they encounter deconstruction and expansion operators.

Note: The setup function is executed only once, because ref and Reactive listen for reactive objects, so every time the value changes, the render function compiled from template is reexecuted. The function collects the values as dependencies, and the next time the values are updated, the function is reexecuted.

2. Life cycle functions

Vue 3.0 life cycle changes can be seen in the following picture:

Because setup runs around the beforeCreate and Created lifecycle hooks, except for these two lifecycle functions, the rest of the lifecycle is just on, and the functionality doesn’t change much. Of course, these life cycles are also written directly into the Setup function.

Specific use is as follows:

export default {
  setup() {
    // Specifies the mounted life cycle
    onMounted(() = > {
      console.log('Component is mounted! '); }); }};Copy the code

3. Transfer values between parent and child components

In Vue 2.0, we used props and emit to transfer values to parent-child components. In Vue 3.0, this did not change, but it was still done in setup functions. Let’s take a look at an example:

The parent component:

<template>
  <div class="example">
    <Test :date="date" :name="name" />
  </div>
</template>

<script lang="ts">
import { ref } from 'vue';
import Test from './components/test.vue';

export default {
  components:{
    Test,
  },
  setup() {
    const date = ref<String>("2021");
    const name = ref<String>("古天乐");

    return {
      date,
      name,
    };
  },
};
</script>
Copy the code

Child components:

<template>
  <div class="example">
    <span class="content">{{ newName }}</span>
    <span class="content">{{ newDate }}</span>
  </div>
</template>

<script lang="ts">
import { toRefs } from 'vue';

export default {
  props: {
    date: String.name: String,},setup(props: any) {
    const { date, name } = toRefs(props);
    const newName = name.value;
    const newDate = date.value;
    return{ newName, newDate, }; }};</script>
Copy the code

As shown in the code above, if a parent component passes multiple values to a child component, then the child component must use toRefs to ensure that it does not lose responsiveness if it wants to use the deconstruction method. If you don’t want to define additional variables, you can simply return props and use props. Xx.

React Hook

Hook is a new feature in React 16.8. It lets you use state and other React features without having to write a class. React Hook This update is awesome. Instead of writing classes and confusing things like this, let’s look at some of the new features in React Hook.

1. useState

In the new feature, setState controls the rendering of the page. All setStates are stored in the call stack and then called in order of state, so this is why in hook, setStates are mandatory to be written in order to ensure normal rendering.

Specific usage is as follows:

import * as React from 'react';
import { useState } from 'react';

const Test = () = > {
  const [count, setCount] = useState(0);
 
  / / add
  const addCount = () = > {
    setCount(count + 1);
  };
  / / reset
  const reset = () = > {
    setCount(0);
  };

  return (
    <div className="content">
      <span className="text">{ count }</span>
      <button onClick={ addCount } style={{ marginLeft: '12px' }}>increase</button>
      <button onClick={ reset } style={{ marginLeft: '12px' }}>reset</button>
    </div>
  );
};
export default Test;
Copy the code

It is clear from the above code that we change the state by defining the initial state and then setState, and only setState can cause the view to change. Vue 3.0’s ref and Reactive are very similar to setState. This is one of the reasons why people say that Vue 3.0 copies React Hook. But a big difference is that Vue 3.0 subdivides the data definition into simple and complex data types and is real-time responsive. Unlike setState, which is called sequently, This is also an optimization point for Vue 3.0.

2. useEffect

UseEffect is an Effect Hook that gives function components the ability to manipulate side effects. It serves the same purpose as componentDidMount, componentDidUpdate, and componentWillUnmount in the Class component, but has been consolidated into an API. So let’s look at the following code sample:

import * as React from 'react';
import { useEffect, useState } from 'react';

const Father = () = > {
  const [count, setCount] = useState(0);
  useEffect(() = > {
    console.log(count,'count');
  }, [count]);
    / / add
  const addCount = () = > {
    setCount(count + 1);
  };
  / / reset
  const reset = () = > {
    setCount(0);
  };
  return (
    <div className="content">
      <span className="text">{count}</span>
      <button onClick={addCount} style={{ marginLeft: '12px' }}>increase</button>
      <button onClick={reset} style={{ marginLeft: '12px' }}>reset</button>
    </div>
  );
};
Copy the code

UseEffect is useful because you can tell the React component that something needs to be done after rendering, but why put it in the component? This allows us to access the count, state variables (or other props) directly in effect. Unlike Vue 3.0, useEffect renders after the first and every update. How do you control its rendering? The key is its second parameter, which listens for a property and only when that property changes will the page be rerendered.

3. Transfer values between parent and child components

React is a one-way data stream, so it can only be transmitted from parent to child in one direction. This is much more difficult than Vue. Examples are as follows:

<! -- Parent component -->import * as React from 'react';
import { useEffect, useState } from 'react';
import './index.css';
import Children from '.. /children/index';

const Father = () = > {
  const [color, setColor] = useState('red');

  // Change the color
  const changeColor = () = > {
    setColor(color === 'red' ? 'green' : 'red');
  };

   return (
    <div className="content">
      <button onClick={changeColor} style={{ marginLeft: '12px' }}>Change the child component color</button>
      <Children value={color} />
    </div>
  );
}
export defaultFather; <! -- Subcomponent -->import * as React from 'react';
import { useEffect } from 'react';
import './index.css';

const Children = (props) = > {
  const { value } = props;
  useEffect(() = > {
    if(! value) {return 'Props value does not exist';
    };
  }, [value]);
  return(
    <div className="box" style={{backgroundColor: value}} >Child components</div>
  );
};

export default Children;
Copy the code

In the example above, we can clearly see useEffect in action. UseEffect listens for changes in the props value when the props value changes. In fact, this part of Vue 3.0 is similar to Hook, but it is undeniable that this way of processing makes the data look more intuitive and the code structure is more clear. Parent can pass values through props.

a. useRef

<! -- Parent component -->import * as React from 'react';
import { useRef } from 'react';
import ChildrenRef from '.. /childrenRef/index';

const FatherRef = () = > {
  const childRef = useRef(null);
  const handleGetChildData = () = > {
    const data = childRef.current.getFromData();
    console.log('data', data);
  };
  return (
    <div>
      <ChildrenRef ref = { childRef} / >     
      <button onClick = {()= >HandleGetChildData ()}> I want to get the child component's data</button>
    </div>
  );
};

export defaultFatherRef; <! -- Subcomponent -->import { useState, forwardRef, useImperativeHandle } from 'react';

function ChildRef(props, ref) {
  const [formValue, setFormValue] = useState({ name: 'ky'.age: 18 });
  useImperativeHandle(ref, () = > ({
    getFromData: () = > {
      returnformValue; }}));return <div>I am the information for the child component</div>;
};

ChildRef = forwardRef(ChildRef);
Useforward must be a function declaration, not a variable declaration

export default ChildRef;
Copy the code

UseImperativeHandle is a forward of ref using the React. ForwardRef method, which returns a component with functions (props, callback, not function components). The first parameter of the function is props passed by the parent component, and the second parameter is ref passed by the parent component. The purpose of this function is to allow the outer component to use ref to directly control the behavior of the inner component or element when encapsulating the component.

b. setState

<! -- Parent component -->import * as React from 'react';
import { useEffect, useState } from 'react';
import './index.css';
import Children from '.. /children/index';

const Father = () = > {
  const [color, setColor] = useState('red');

  // Change the color
  const changeColor = () = > {
    setColor(color === 'red' ? 'green' : 'red');
  };

  return (
    <div className="content">
      <Children value= {color} setColor= {setColor} />
    </div>
  );
};
export defaultFather; <! -- Subcomponent -->import * as React from 'react';
import { useEffect } from 'react';
import './index.css';

const Children = (props) = > {
  const { value, setColor } = props;
  useEffect(() = > {
    if(! value) {return 'Props value does not exist';
    }
    console.log(value, 'value');
  }, [value]);

  // The child component changes color
  const changeColor = () = >{
    setColor('black');
  };
  return(
    <>
    <div className="box" style={{backgroundColor: value}} >Child components</div>
    <button onClick={changeColor}>Child components change color</button>
    </>
  );
};

export default Children;
Copy the code

In addition to the above two methods, there is also a way to pass the value to the parent through the click event of the child component, and the specific implementation is very similar to the setState method, not to mention. React is a one-way data flow framework, so it is more difficult to transfer values between parent and child components than Vue. Therefore, it is usually used with redux or MOBx data management libraries.

4. UseMemo useCallback

React Hook also adds two performance tuning functions. These two functions are also performance tuning functions. We can use the following example to get an intuition:

<! -- useMemo -->const memoizedValue = useMemo(
  () = >computeExpensiveValue(a, b), [a, b] ); <! -- useCallback -->const memoizedCallback = useCallback(
  () = > {
    doSomething(a, b);
  },
  [a, b],
);
Copy the code

The two functions are very similar, except that useCallback caches the first incoming parameter (callback) according to the dependency (DEPS). UseMemo caches the value of the first input argument (callback) after execution based on a dependency (DEPS). In a nutshell, useMemo is typically used to specify that a variable’s value changes before it is evaluated, and is typically used for computation-intensive caches. UseCallback is used to cache functions.

conclusion

React Hook: useState: useRef: useReactive: There are also similarities between the setup function and the useEffect function, but subtle differences. But in general, the two frameworks are still very useful, each has its own advantages, to look at the similarities and differences objectively, in order to better progress.