# All files / lib/lifecycle component-will-unmount.js

96.15% Statements 100/104
84.61% Branches 22/26
100% Functions 3/3
96.15% Lines 100/104

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    1052x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    1000x
    1000x
    1000x
    1000x
    1000x
    974x
    974x
    1000x
    1000x
    30x
    30x
    970x

    970x

    2x
    2x
    2x
    830x
    1000x
    1000x
    1000x
    1000x
    1000x
    1000x
    1000x
    1000x
    305x
    305x
    1000x
    1000x
    873x
    873x
    873x
    1000x
    1000x
    1000x
    1000x
    1000x
    830x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    525x
    525x
    525x
    525x
    525x
    525x
    718x
    263x
    263x
    525x
    525x
    525x
    525x
    525x
    525x
    525x
    525x
    22x
    22x
    525x
    525x
    442x
    442x
    525x
    525x
    525x
    525x
    525x
    525x
    525x
    72x
    72x
    83x
    83x
    83x
    83x
    525x
    9x
    9x
    83x
    83x
    83x
    525x
    525x
     import { EMPTY, ComponentTreeCache, InstanceCache, VTree } from '../util/types';
    import diff from '../util/binding';
    import { $$hooks } from '../util/symbols';

    const { release, Internals } = diff;

    /**
     * @param {any} target
     * @param {VTree} vTree
     */
    const invokeRef = (target = EMPTY.OBJ, vTree) => {
      let { ref } = target.props || target;

      // Allow refs to be passed to HTML elements. When in a DOM environment
      // a Node will be passed to the ref function and assigned.
      if (!ref) {
        ref = vTree.attributes.ref;
      }

      if (typeof ref === 'function') {
        ref(null);
      }
      else if (typeof ref === 'object' && ref) {
        ref.current = null;
      }
      else if (typeof ref === 'string') {
        target.refs = { ...target.refs, [ref]: null };
      }
    };

    const invokeRefsForVTrees = (/** @type {(VTree | null)[]} */ ...vTrees) => {
      for (let i = 0; i < vTrees.length; i++) {
        const vTree = vTrees[i];

        if (!vTree) continue;

        const componentTree = ComponentTreeCache.get(vTree);
        const instance = InstanceCache.get(componentTree || vTree);

        if (vTree.childNodes.length) {
          invokeRefsForVTrees(...vTree.childNodes);
        }

        if (!instance) {
          invokeRef(Internals.NodeCache.get(vTree), vTree);
          continue;
        }

        // If any instances exist, loop through them and invoke the respective `ref`
        // logic.
        invokeRef(instance, vTree);
      }
    }

    /**
     * Called whenever a component is being removed.
     *
     * @param {VTree} vTree - The respecting tree pointing to the component
     */
    export default function componentWillUnmount(vTree) {
      const componentTree = ComponentTreeCache.get(vTree);

      /** @type {VTree[]} */
      const childTrees = [];

      ComponentTreeCache.forEach((parentTree, childTree) => {
        if (parentTree === componentTree) {
          childTrees.push(childTree);
        }
      });

      invokeRefsForVTrees(vTree);

      const domNode = Internals.NodeCache.get(vTree);

      // Clean up attached Shadow DOM.
      if (domNode && /** @type {any} */ (domNode).shadowRoot) {
        release(/** @type {any} */ (domNode).shadowRoot);
      }

      if (!InstanceCache.has(componentTree)) {
        return;
      }

      const instance = InstanceCache.get(componentTree);
      InstanceCache.delete(componentTree);

      // Empty out all hooks for gc. If using a stateless class or function, they
      // may not have this value set.
      if (instance[$$hooks]) {
        instance[$$hooks].length = 0;
      }

      ComponentTreeCache.delete(vTree);

      // If there is a parent, ensure it is called recursively.
      if (ComponentTreeCache.has(componentTree)) {
        componentWillUnmount(componentTree);
      }

      // Ensure this is a stateful component. Stateless components do not get
      // lifecycle events yet.
      instance && instance.componentWillUnmount && instance.componentWillUnmount();
    }