preface

Since I started writing Vue recently, it was a challenge for me as a react veteran. In fact, I prefer to write native JS now, because most of the best framework libraries on the market are almost inseparable from the Vitrual DOM.

What we do know is that the performance of updating the real DOM through the Vitrual DOM is certainly not as good as that of manipulating the native DOM directly. How about document.getelementById (ID).xx if I know exactly which DOM is changing?

The value of the Vitrual DOM has never been about performance. emmm… Today’s topic is a detoxification of Vue source code, the purpose is to be able to clearly know what Vue does, and where are the advantages and disadvantages.

1. Start with the diff algorithm of Vue

Anyone who takes the Vitrual DOM route can’t escape the Diff algorithm. Diff algorithm every family, that Vue3 diff algorithm is what it looks like.

Let’s start with chestnuts.

    <ul key="ul1"> < li > cheat philandering emotional man < li > < li > fat < li > < li > to know eat < li > < ul >Copy the code

Needs to be converted into:

    <ol key="ul1"> <li> cheat on a woman's feelings man <li> <li> fat <li> <li> just know eat? <div> You are a cheating and philandering man! </div><li> <ol>Copy the code

Q: what is theulbecomeol, the key doesn't change, even its children don't change. How to render Vue again?

A: Re-render everything.

So, does it make sense? If existence makes sense, then why design this way? Someone here is going to diss me, which is very rare in actual development. We’ll talk about that later. It’s really possible to solve this problem… 😂)

Diff’s execution strategy

  • Fine diff comparison is performed only on the same virtual node.
// Look at a method in the source code
function isSameVNodeType(n1, n2) { 
// ... 
return n1.type === n2.type && n1.key === n2.key 
}
Copy the code

Check whether two VNodes are the same. If you look at the return value of the function, you can see that two VNodes must have the same node type and key.

  • Comparisons are made within layers, not across layers

Let’s go back to the question above and continue with this:

    <ul key="ul1"> <li> cheat on a woman's feelings man <li> <li> fat <li> <li> just know eat? <div> You are a cheating and philandering man! </div><li> <ul>Copy the code

Q: If ul does not change, only the contents of one of the Li elements have changed. How do you render it?

A: If LI sends a change, only the diff comparison of the li layer is performed, not the LI child div diff. I’m sure those of you who have used Vue know the answer.

PatchChildren – Updates children

On the source code.


      const patchChildren = (n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized = false) = > {
          const c1 = n1 && n1.children;
          const prevShapeFlag = n1 ? n1.shapeFlag : 0;
          const c2 = n2.children;
          const { patchFlag, shapeFlag } = n2;
          // fast path
          if (patchFlag > 0) {
              if (patchFlag & 128 /* KEYED_FRAGMENT */) {
                  // this could be either fully-keyed or mixed (some keyed some not)
                  // presence of patchFlag means children are guaranteed to be arrays
                  /* *1 - patchKeyedChildren */ 
                  patchKeyedChildren(c1, c2, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized);
                  return;
              }
              else if (patchFlag & 256 /* UNKEYED_FRAGMENT */) {
                  // unkeyed
                  /* * 2 - patchUnkeyedChildren */ 
                  patchUnkeyedChildren(c1, c2, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized);
                  return; }}// children has 3 possibilities: text, array or no children.
          if (shapeFlag & 8 /* TEXT_CHILDREN */) {
              // text children fast path
              if (prevShapeFlag & 16 /* ARRAY_CHILDREN */) {
                  unmountChildren(c1, parentComponent, parentSuspense);
              }
              if (c2 !== c1) {
                  hostSetElementText(container, c2);
              }
          }
          else {
              if (prevShapeFlag & 16 /* ARRAY_CHILDREN */) {
                  // prev children was array
                  if (shapeFlag & 16 /* ARRAY_CHILDREN */) {
                      // two arrays, cannot assume anything, do full diff
                      
                      patchKeyedChildren(c1, c2, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized);
                  }
                  else {
                      // no new children, just unmount old
                      unmountChildren(c1, parentComponent, parentSuspense, true); }}else {
                  // prev children was text OR null
                  // new children is array OR null
                  if (prevShapeFlag & 8 /* TEXT_CHILDREN */) {
                      hostSetElementText(container, ' ');
                  }
                  // mount new if array
                  if (shapeFlag & 16 /* ARRAY_CHILDREN */) { mountChildren(c2, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized); }}}};Copy the code

Look at this source code you will know:

  1. Node ispatchFlag.shapeFlagTwo properties.
  2. patchChildrenN1 is the old node, andprevShapeFlag = n1.shapeFlag.
  3. N2 is the new node (after updating the old node)
  4. patchFlagIs the fast channel flag, once there is this flag on the node and its value > 0, the diff processing with key is directly carried out.
  5. Non-fast channels make three judgments: text nodes, children, and no children. When an array node is encountered, recursive processing is performed.

I annotated two places in it (too much source code, just showing the key parts)

  • 1 – patchKeyedChildren: Process nodes with keys

  const patchKeyedChildren = (c1Old vnode / * * /, c2New vnode / * * /, container, parentAnchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized) = > {
          let i = 0;/* Record index */
          const l2 = c2.length; /* Number of new vNodes */
          let e1 = c1.length - 1; // prev ending index: index of the last vnode
          let e2 = l2 - 1; // Next ending index: index of the new node
          // 1. sync from start
         
          while (i <= e1 && i <= e2) { // ### 1
              const n1 = c1[i];
              const n2 = (c2[i] = optimized
                  ? cloneIfMounted(c2[i])
                  : normalizeVNode(c2[i]));
              if (isSameVNodeType(n1, n2)) {
                  patch(n1, n2, container, null, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized);
              }
              else {
                  break;
              }
              i++;
          }
          // 2. sync from end
         
          while (i <= e1 && i <= e2) { // ### 2
              const n1 = c1[e1];
              const n2 = (c2[e2] = optimized
                  ? cloneIfMounted(c2[e2])
                  : normalizeVNode(c2[e2]));
              if (isSameVNodeType(n1, n2)) {
                  patch(n1, n2, container, null, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized);
              }
              else {
                  break;
              }
              e1--;
              e2--;
          }
          // 3. common sequence + mount
        
          // All patches of the old node, as well as new nodes
          if (i > e1) {  // / The new node is larger than the old node
              if (i <= e2) { // // If the pointer to e2 of the new node is still running, a node needs to be added
                  const nextPos = e2 + 1;
                  const anchor = nextPos < l2 ? c2[nextPos].el : parentAnchor;
                  while (i <= e2) {
                      patch(null, (c2[i] = optimized ? cloneIfMounted(c2[i]) : normalizeVNode(c2[i])), container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized); i++; }}}// 4. common sequence + unmount
         // All patches of new nodes, and old nodes
          else if (i > e2) { // The e2 pointer of the new node is completely patched
              while (i <= e1) { // The number of new nodes is smaller than the number of old nodes, and nodes need to be uninstalled
                  unmount(c1[i], parentComponent, parentSuspense, true); i++; }}// 5. Unknown sequence: remaining uncertain elements
          // [i ... e1 + 1]: a b [c d e] f g
          // [i ... e2 + 1]: a b [e d c h] f g
          // i = 2, e1 = 4, e2 = 5
          else {
              const s1 = i; // prev starting index
              const s2 = i; // next starting index
              // 5.1 build key:index map for newChildren
              const keyToNewIndexMap = new Map(a);for (i = s2; i <= e2; i++) {
                  const nextChild = (c2[i] = optimized
                      ? cloneIfMounted(c2[i])
                      : normalizeVNode(c2[i]));
                  if(nextChild.key ! =null) {
                      if (keyToNewIndexMap.has(nextChild.key)) {
                          warn(`Duplicate keys found during update:`.JSON.stringify(nextChild.key), `Make sure keys are unique.`); } keyToNewIndexMap.set(nextChild.key, i); }}// 5.2 loop through old children left to be patched and try to patch
              // matching nodes & remove nodes that are no longer present
              // code ....
              
              // move and mount
              // generate longest stable subsequence only when nodes have moved
              // code ...}};Copy the code

Pro, first look at the source code with a number of citation notes, are the source code. If you don’t understand it, look at the Chinese notes. I added them.

Well, if looking at the source code gives you headaches, let me summarize the number 5 in this method.

5.1 Build Key: Record new nodes

Let’s look at the variables declared in the code:

Const s1 = I const s2 = I const keyToNewIndexMap = new Map() // Save for (I = s2; i <= e2; i++) { if (nextChild.key ! = null) { keyToNewIndexMap.set(nextChild.key, I)}} let j // new pointer j let patched = 0 const toBePatched = E2-s2 + 1 // Number of new nodes that have not passed the path let moved = false // Whether to move Let maxNewIndexSoFar = 0 const newIndexToOldIndexMap = new Array(toBePatched) // Create an Array, Each child element is 0 [0, 0, 0, 0, 0, 0] for (I = 0; i < toBePatched; i++) newIndexToOldIndexMap[i] = 0;Copy the code

In the keyToNewIndexMap variable, we get :(assuming the key of node e is e).

keyToNewIndexMap = {"e" => 2, "d" => 3, "c" => 4, "h" => 5}
Copy the code

Use the new pointer J to record the index of the remaining new node.

NewIndexToOldIndexMap is used to store new node indexes and old node indexes.

5.2 Matching a Node, delete a node that does not exist

for (i = s1; i <= e1; I ++) {/* Start over old nodes */ const prevChild = c1[I] // C1 is old node if (patched >= toBePatched) {/* The number of patched nodes is greater than or equal to the number of remaining nodes, Unmount old nodes */ prevChild, parentComponent, parentSuspense, True) continue} let newIndex // the index of the new node /* If the old key exists, find the index of the new node */ if (prevchild.key! = null) {newIndex = keytonewindexmap. get(prevchild.key)} else {/* If the old key does not exist, iterate over the remaining new nodes. S2 =2 e2=5, */ for (j = s2; j <= e2; J++) {if (newIndexToOldIndexMap[j-s2] === 0 && isSameVNodeType(prevChild, c2[j])) { NewIndex */ newIndex = j break}}} if (newIndex === undefined) { Unmount (prevChild, parentComponent, parentSuspense, true)} else {/* Keep the index of the old node in the array where the new node is  */ newIndexToOldIndexMap[newIndex - s2] = i + 1 if (newIndex >= maxNewIndexSoFar) { maxNewIndexSoFar = newIndex } else Patch */ patch(prevChild, c2[newIndex], container, null, parentComponent, ParentSuspense, isSVG, Optimized) Patch ++ // Record how many old nodes are found in the new node}Copy the code

So you can think of it as basically doing 2 steps:

Step 1:

Find index of new node by key of old node, there are two cases:

  1. The old node does not have a key, and traverses all the remaining new nodes to try to find the index
  2. The old node has a key inkeyToNewIndexMapFind index in

Step 2:

  1. If Index is still not found in the first step, it indicates that there is no old node corresponding to the new node. Delete the current old node.
  2. If Index is found, it indicates that there is a corresponding node in the old node, and the new node is assigned the Index tonewIndex. Index the old node to the new node arraynewIndexToOldIndexMapIndex +1, because the initial value is 0, if you store the index directly, it changes from the first one then the stored index will be 0, and it will be treated as if there are no old nodes matching.

NewIndex >= maxNewIndexSoFar

Because traversing the old array is traversing from front to back, if the position of the node in the new node array is recorded during traversing, if there is inversion, then it is maxNewIndexSoFar > newIndex, which means that a node of the new and old nodes has been switched. Movement of elements is definitely involved in the diff process.

// For example
ifOld node = [a, b, c, f];ifNew node = [a, f, b, c]; So loop over old nodes: when Pointer -> b, newIndex =2 and maxNewIndexSoFar = 0When Pointer -> c, newIndex =3 and maxNewIndexSoFar = 2When Pointer -> f, newIndex =1 and maxNewIndexSoFar = 3 

result ->  moved = true

// string the process togetherOld node: a b [c d e] f G, c key exists, d, e key ===undefinedNew node: a b [e d c h] f g Get the node to be processed: [e d c h] follow the above logic, first traverse [c d e]. when when Pointer -> c, newIndex =4 s2 = 2 newIndexToOldIndexMap = [0.0.3.0]. Run patch when when Pointer -> d, newIndex =undefinedD when when Pointer -> e, newIndex =undefined, delete the eCopy the code

What a horrible fact. If the key doesn’t exist, delete the old node. When writing Vue code, you must pay attention to the key? I almost believe myself 😂

A very important concept is proposed: longest increasing subsequence

I will write Chinese notes for you. 😊

// move and mount
// generate longest stable subsequence only when nodes have moved

// Move the old node and create a new node
const increasingNewIndexSequence = moved
    ? getSequence(newIndexToOldIndexMap)
    : EMPTY_ARR;
// // Used to check node movement
j = increasingNewIndexSequence.length - 1;
// looping backwards so that we can use last patched node as anchor
// loop backwards, i.e. loop backwards. Because we insert nodes using insertBefore, we insert forward so that we can use the last updated node as an anchor point
for (i = toBePatched - 1; i >= 0; i--) {
    const nextIndex = s2 + i;
    const nextChild = c2[nextIndex];
    const anchor = nextIndex + 1 < l2 ? c2[nextIndex + 1].el : parentAnchor;
    if (newIndexToOldIndexMap[i] === 0) { // If the default value is 0, the node is completely new
        // mount new
        patch(null, nextChild, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized);
    }
    else if (moved) {
        // move if:
        // There is no stable subsequence (e.g. a reverse)
        // OR current node is not among the stable sequence: the current index is not a value in the longest increasing subsequence and needs to be moved
        if (j < 0|| i ! == increasingNewIndexSequence[j]) { move(nextChild, container, anchor,2 /* REORDER */);
        }
        else {
        // is the value in the longest increasing subsequence, which points to the next onej--; }}}Copy the code
  • 2 – patchUnkeyedChildren: Processes nodes with or without keys

Nodes that do not have keys…

Spicy chicken. It’s so rough, you can’t even look at it. Look at the source code yourself. Compare the length of the new node with the length of the old node. Umount old

To summarize:

  1. If a node with no key changes, go straight to the crematorium.
  2. The node with the key changes
    • Compare heads to heads
    • Let’s compare tails to tails
    • Compare the heads and tails
    • Find the longest increasing subsequence, move around at any time, create new nodes at any time.

2. Time Slicing

Vue3 ditched time slicing, which made me… . Monica: Emmmm, what can I say?

Yuxi has a detailed answer in Vuejs Issue about why Vue3 doesn’t use Time Slicing. The original address of the reply of yuxi

All right. Let me translate (I was thinking, I don’t translate let the old iron people directly read the original will be beaten? .


In Web applications, update content loss frames (JANKY) are typically caused by a large amount of CPU time + synchronization of the original DOM updates. Time slicing is an attempt to keep the application responsive while the CPU is working, but it only affects the CPU. But the refresh of DOM updates must still be synchronous to ensure consistency in the final DOM state.

So, imagine two scenarios for dropping frames:

1.CPU running time is less than 16ms, but there is a lot of native DOM update operations (e.g., mount a lot of new DOM content). With or without time slicing, the application still feels “stiff”.

  1. The CPU task is heavy and takes more than 16ms. In theory, time slicing comes into play. However, HCI’s research shows that unless it’s animating, most people won’t feel the difference for normal user interaction unless the update takes more than 100 milliseconds.

That is, time slicing becomes practically useful only when frequent updates require more than 100 milliseconds of pure CPU time.

That is, time slicing is only really useful if you are frequently updating pure CPU tasks over 100ms.

The interesting thing is that this scenario happens more often with React because:

  • I. React’s virtual DOM operation (reconciliation algorithm) is inherently slow because it uses a lot of Fiber architecture;

  • React Rendering functions using JSX are more difficult to optimize than rendering with templates, which are easier to statically analyze.

  • Iii. React Hooks leave most of the component tree-level optimization (that is, preventing unnecessary re-rendering of child components) to developers, who in most cases need to use useMemo explicitly. Also, whenever React receives the children property, it almost always rerenders because each time the child is a new VDOM tree. This means that a React app that uses hooks will overrender in its default configuration. To make matters worse, optimizations like useMomo cannot easily be applied automatically because:

    1. It needs the correct DEPS array;
    2. Using it blindly and arbitrarily can block updates that should be made, similarlyPureComponent.

    Unfortunately, most developers are lazy and don’t actively optimize their applications. So most React applications that use hooks do a lot of unnecessary CPU work.

In contrast, Vue makes a comparison with the above question:

  1. Simpler in nature, hence faster virtual DOM operation (no time slice -> noFiber -> lower overhead);

  2. A lot of AOT optimization is done by analyzing templates, which reduces the basic overhead of virtual DOM operations. Benchmark shows that for a typical DOM code block, the ratio of dynamic to static content is about 1:4, and Vue3’s native execution is even faster than Svelte’s, taking less than 1/10 of the CPU time of React.

  3. Smart component tree optimization compiles slots into functions (to avoid repeated rendering of child elements) and automatically caches inline handles (to avoid repeated rendering of inline functions) through reactive tracing. Child components never need to be rerendered unless necessary. All this without any manual optimization by the developers.

    This means that the React application may cause multiple components to be re-rendered for the same update, but in Vue it will most likely only cause one component to be re-rendered.

By default, Vue3 apps consume less CPU time than React apps, and the chances of CPU time exceeding 100ms are significantly reduced, except in extreme cases where DOM can be a more significant bottleneck.

Now, time slicing or concurrent patterns introduce another problem: because the framework now schedules and coordinates all updates, it creates a lot of additional complexity in terms of prioritization, invalidation, re-instantiation, and so on. All of these logical processes are unlikely to be shaken by tree-shaken, which will cause the size of the CPU memory occupied by the runtime to swell. Even with Suspense and all tree-shaken, the Vue 3 runtime is still only 1/4 the size of the current React + React DOM.

Note that this is not to say that concurrent patterns as a whole are a bad idea. It does provide interesting new ways of dealing with certain kinds of problems (particularly related to coordinating asynchronous state transitions), but time slicing (as a subfeature of concurrency) specifically addresses issues that are more salient in React than in other frameworks, while also creating costs of its own. For Vue 3, this trade-off doesn’t seem worth it.


If you’re an old React player, you’re probably not convinced. The react response seems to point out some drawbacks and shortcomings. There is just a low step on others to raise their own rhythm.

Yu Yuxi points out:

  1. React + React DOM takes up more CPU memory in runtime than Vue4:1
  2. React Hooks don’t workUseMemo, memo,You also have to get the DEPS right.
  3. React operates in the virtual DOMReactThe scheduling algorithm is slow. whileVueBy analyzing templates, a lot ofOptimization of AOTTo reduce the basic overhead of virtual DOM operation.So Vue can operate the virtual DOM faster than React.
  4. Concurrent mode is not necrotic, but time slicing is not, at least React time slicing is not.

As someone who has lived through React, I know some of its drawbacks. Let’s look at points 1-4 from a different perspective.

  1. To be honest, he who runs fast scores the time. If React takes 4 hours and Vue takes 1 hour, who do you think is faster? React runs 400ms and Vue runs 100ms. Who do you think is faster? In other words, is it really necessary to address this problem? How can front-end performance bottlenecks be optimized? React better or Vue better?

  2. React Hooks are easy to use, but not easy to get right. But if I use it well, does the problem still exist?

  3. React scheduling algorithm is slow, Vue is faster, so there are two aspects

    • React can be manipulated by writing code, such as using as few VDOM operations as possible. Can Vue’s AOT optimizations be done by developers? Obviously, Vue can’t.
    • Is React really slow? Or is Vue really better than React when dealing with a lot of DOM?
  4. Explain a little bit about the so-called React time slice. React assigns the Fiber task to the browser’s idle time. This process can be interrupted at any time, and the task can be picked up again next time.

    • The application of “time slicing” in React is not about speed, but about recoverability. For example, when users are doing responsible interactions or complex animations, do you think React is worth it if it increases its own consumption while ensuring smooth interaction and animations?

The subtotal

In fact, there are a lot of heated discussions about React and Vue in the market, which are generated due to their advantages and disadvantages.

For example, many people are attacking each other on the Internet:

“Vue is only suitable for small projects, not big projects.”

React countless callbacks, countless select expressions, this binding… Disorderly! “

“Vue is easy to learn, many posts”

React, not Vue

So in terms of usage, EMMM, let’s put a box here.

The problem Vue React
This confusion The source code implementation already handles this, so you don’t need to do anything about it React Hooks don’t have this anymore.
Get started easy normal
The use of good normal hard
The novice friendly Extremely friendly Don’t friendly
scalability general strong
The underlying implementation Hardcore, doing everything he can Hardcore, but much more
hook Fine speak Fine speak

Vue3 & React17 comparison

When the Vue 3.0 Beta was first released, there was a lot of noise. Two things impressed me.

  • Make fun of the spaghetti code structure
    • In a bunch of shitsetupI might as well just use React
    • The code structure is not clear, semantic is not clear, this operation is tantamount to throwing away vue’s own advantages
    • The structure is not clear, worry about the code quantity is not good maintenance
  • Copying the React
    • Vue-Composition-ApiThe main source of inspiration isReact HooksCreativity (and this is where the teasing is most vicious)

In fact, people who have actually used React hooks and know them will recognize them when they see thisVue Composition API (VCA)withhooksEssential difference.VCAIn fact, the implementation of Vue’s own responsive system is more explicitly exposed. If anything,VCAMobXMore like it.

(Here I Vue vexonerated, which shows that I am still very considerable. After all, I have studied the Vue source code.

For example, the Vue CLI UI File Explorer is a complex file browser component in the VUE-CLI GUI (that is, the graphical console we normally type Vue UI on the command line). This is Vue official team big guy wrote, believe is a more convincing case.

On Github, I won’t post the code. It’s 1:00 in the morning.

Then, look at the official picture and you can see.

Original style on the left and original style on the righthookStyle.

One hook style approach:

function useCreateFolder(openFolder) {
  // originally data properties
  const showNewFolder = ref(false);
  const newFolderName = ref("");

  // originally computed property
  const newFolderValid = computed(() = > isValidMultiName(newFolderName.value));

  // originally a method
  async function createFolder() {
    if(! newFolderValid.value)return;
    const result = await mutate({
      mutation: FOLDER_CREATE,
      variables: {
        name: newFolderName.value,
      },
    });
    openFolder(result.data.folderCreate.path);
    newFolderName.value = "";
    showNewFolder.value = false;
  }

  return {
    showNewFolder,
    newFolderName,
    newFolderValid,
    createFolder,
  };
}

Copy the code

Let’s take a look at some code in the Vue Hook style:

export default {
  setup() {
    // ...}};function useCreateFolder(openFolder){
// ...
}
function useCurrentFolderData(networkState) {
  // ...
}

function useFolderNavigation({ networkState, currentFolderData }) {
  // ...
}

function useFavoriteFolder(currentFolderData) {
  // ...
}

function useHiddenFolders() {
  // ...
}

function useCreateFolder(openFolder) {
  // ...
}
Copy the code

Now look at the setup function.

export default { setup() { // Network const { networkState } = useNetworkState(); // Folder const { folders, currentFolderData } = useCurrentFolderData(networkState); const folderNavigation = useFolderNavigation({ networkState, currentFolderData }); const { favoriteFolders, toggleFavorite } = useFavoriteFolders(currentFolderData); const { showHiddenFolders } = useHiddenFolders(); const createFolder = useCreateFolder(folderNavigation.openFolder); // Current working directory resetCwdOnLeave(); const { updateOnCwdChanged } = useCwdUtils(); // Utils const { slicePath } = usePathUtils(); return { networkState, folders, currentFolderData, folderNavigation, favoriteFolders, toggleFavorite, showHiddenFolders, createFolder, updateOnCwdChanged, slicePath, }; }};Copy the code

🐂🍺, clean?

Compare this to the Hook principle.

Let me give you an example.


<template>
  <div>
    <span>{{count}}</span>
    <button @click="add"> Add By 1 </button>
  </div>
</template>

export default {
    setup() {
        const count = ref(0)

        const add = () = > count.value++

        effect(function active(){
            console.log('count changed! ', count.value)
        })

        return { count, add }
    }
}
Copy the code

Very simple chestnut.

  1. Setup is executed only once,
  2. If you need tocountWhen something changes, we just introduce iteffectFunction.
  3. thisactiveThe function is only produced once, the function is readingcount.valueWill collect it as a dependency, then next timecount.valueAfter the update, it will automatically triggeractiveThe function is re-executed.

To sum up: hook is initialized once, then infinite.

Here’s another chestnut.


export default function Counter() {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('A man who cheats on a woman's affections');
  const add = () = > setCount((prev) = > prev + 1);

  useEffect(() = >{
      setName('Cheating on philandering male scum${count}Time `)
  },[count])

  return (
    <div>
      <span>{count}</span>
      <span>{name}</span>
      <button onClick={add}>+ 1</button>
    </div>
  );
}

Copy the code

Obviously, it does the same thing, but it’s a React component. Introduced by reference to
, we know that JSX is JS, and Babel will actually compile it to execute functions like react.createElement (Counter).

This means that the function will be executed in full every time it is rendered.

The count and setCount returned by useState are stored on the Fiber node of the component, and each React function must execute hooks in the same order.

The React Hooks function can be called multiple times, which is the most developer-friendly idea I have so far. I can take advantage of these hook functions to granulate my logic to a high degree of reuse without affecting each other.

The disadvantages of DEPS dependency are mentioned above. Many Hooks depend on state variables. Simply put, the dependent state variable changes, and the corresponding operation can be performed. Sounds nice, right? But one might be closures that sink… You use good, cow. If you don’t use it, you’re spicy chicken.

So if you’re a big fan of the functional programming style, React Hooks are your favorite.

In addition, I suddenly thought of a saying on the Internet: Vue gives you permanence, React gives you freedom.

So, when doing technical research, think about your scenario. Other really nothing, the code is always written by people, Vue can be written as SI, React is difficult to use, written can be god.

1:26 in the morning, the technical article is to write up no edge, because can talk about really a lot of… React source code detoxification can be found in previous articles. On Vue remaining source code, in fact, really not much, compared to Vue source code really too little, notes are also rich (more people write English easier to understand some). So, catch up sometime.

end