# All files / lib render-component.js

100% Statements 151/151
95.23% Branches 20/21
100% Functions 4/4
100% Lines 151/151

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
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    1522x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    2x
    118x
    118x
    118x
    118x
    118x
    118x
    118x
    118x
    118x
    8x
    8x
    8x
    5x
    5x
    8x
    8x
    8x
    7x
    8x
    5x
    5x
    13x
    9x
    9x
    5x
    5x
    5x
    5x
    5x
    5x
    5x
    5x
    5x
    5x
    8x
    8x
    8x
    8x
    118x
    118x
    82x
    82x
    82x
    82x
    82x
    82x
    82x
    71x
    71x
    82x
    82x
    82x
    82x
    82x
    82x
    82x
    82x
    82x
    82x
    82x
    82x
    82x
    82x
    7x
    7x
    82x
    82x
    82x
    82x
    118x
    118x
    118x
    118x
    118x
    118x
    118x
    28x
    28x
    118x
    118x
    118x
    118x
    118x
    118x
    31x
    31x
    118x
    118x
    118x
    118x
    118x
    118x
    118x
    118x
    118x
    118x
    118x
    118x
    118x
    118x
    118x
    118x
    118x
    118x
    118x
    118x
    118x
    6x
    6x
    118x
    118x
    118x
    118x
    115x
    115x
    115x
    115x
    57x
    136x
    57x
    57x
    115x
    115x
    115x
    115x
    115x
    115x
    115x
    2x
     import {
      ComponentTreeCache,
      ActiveRenderState,
      InstanceCache,
      VTree,
    } from './util/types';
    import { $$vTree } from './util/symbols';
    import diff from './util/binding';
    import Component from './component';

    const { createTree } = diff;

    /**
     * Used during a synchronization flow. Takes in a vTree and a context object
     * and renders the component as a class or a function. Calls standard lifecycle
     * methods.
     *
     * @param {VTree} vTree - tree to render
     *
     * @returns {VTree | null}
     */
    export default function renderComponent(vTree) {
      const RawComponent = vTree.rawNodeName;
      const props = vTree.attributes;
      const isNewable = RawComponent.prototype && RawComponent.prototype.render;

      /** @type {VTree|null} */
      let renderedTree = (null);

      // Existing class component rerender.
      if (InstanceCache.has(vTree)) {
        const instance = InstanceCache.get(vTree);

        if (instance.componentWillReceiveProps) {
          instance.componentWillReceiveProps(props);
        }

        if (
          instance.shouldComponentUpdate &&
          instance.shouldComponentUpdate(props, instance.state)
        ) {
          // Wipe out all old references before re-rendering.
          ComponentTreeCache.forEach((parentTree, childTree) => {
            if (parentTree === vTree) {
              ComponentTreeCache.delete(childTree);
            }
          });

          ActiveRenderState.push(instance);
          renderedTree = createTree(instance.render(props, instance.state));
          ActiveRenderState.length = 0;

          if (instance.componentDidUpdate && instance.componentDidUpdate) {
            instance.componentDidUpdate(instance.props, instance.state);
          }
        }
        else {
          return null;
        }
      }
      // New class instance.
      else if (isNewable) {
        const instance = new RawComponent(props);

        // Associate the instance to the vTree.
        InstanceCache.set(vTree, instance);

        // Signal the component is about to mount.
        if (instance.componentWillMount) {
          instance.componentWillMount();
        }

        ActiveRenderState.push(instance);

        // Initial render of the class component, this should not be called again
        // for the same component in the same position. It will be picked up
        // automatically as a class component and rendered via its own Transaction.
        const renderRetVal = instance.render(props, instance.state);

        ActiveRenderState.length = 0;

        renderedTree = createTree(renderRetVal || '#text');

        // Set up the HoC parent/child relationship.
        if (typeof renderedTree.rawNodeName === 'function') {
          ComponentTreeCache.set(renderedTree, vTree);
        }

        // Associate the instance with the vTree.
        instance[$$vTree] = vTree;
      }
      // Function component, upgrade to a class to make it reactive.
      else {
        class FunctionComponent extends Component {
          /**
           * @param {any} props
           */
          constructor(props) {
            super(props);
          }

          /**
           * @param {any} props
           * @param {any} state
           */
          render(props, state) {
            return createTree(RawComponent(props, state));
          }

          /** @type {VTree | null} */
          [$$vTree] = null;
       }

        const instance = new FunctionComponent(props)

        // Associate the instance to the vTree.
        InstanceCache.set(vTree, instance);

        // Allow hooks to "hook" into the active rendering component.
        ActiveRenderState.push(instance);

        const renderRetVal = instance.render(props, instance.state);

        ActiveRenderState.length = 0;

        renderedTree = createTree(renderRetVal || '#text');

        // Set up the HoC parent/child relationship.
        if (typeof renderedTree.rawNodeName === 'function') {
          ComponentTreeCache.set(renderedTree, vTree);
        }

        // Associate the instance with the vTree.
        instance[$$vTree] = vTree;
      }

      if (renderedTree !== vTree) {
        // Map all top-level fragment elements to this parent node.
        if (renderedTree.nodeType === 11) {
          renderedTree.childNodes.forEach(childNode => {
            ComponentTreeCache.set(childNode, vTree);
          });
        }
        // Otherwise directly map the rendered VTree to the component tree.
        else {
          ComponentTreeCache.set(renderedTree, vTree);
        }
      }

      return renderedTree;
    };