# 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
    963x
    963x
    963x
    963x
    963x
    938x
    938x
    963x
    963x
    29x
    29x
    934x

    934x

    2x
    2x
    2x
    793x
    963x
    963x
    963x
    963x
    963x
    963x
    963x
    963x
    293x
    293x
    963x
    963x
    847x
    847x
    847x
    963x
    963x
    963x
    963x
    963x
    793x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    500x
    500x
    500x
    500x
    500x
    500x
    707x
    252x
    252x
    500x
    500x
    500x
    500x
    500x
    500x
    500x
    500x
    22x
    22x
    500x
    500x
    428x
    428x
    500x
    500x
    500x
    500x
    500x
    500x
    500x
    61x
    61x
    72x
    72x
    72x
    72x
    500x
    9x
    9x
    72x
    72x
    72x
    500x
    500x
     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();
    }