Reactのstateはどのように推移するのか その4

## 見落としていた点

どうやらhtml要素をmountする段階でpropertyをupdateする時にtransactionをqueueに詰めているのそこを見てみる。

```js:ReactDOMComponent.js
  mountComponent: function(
    transaction,
    nativeParent,
    nativeContainerInfo,
    context
  ) {
    ...,
    
    this._updateDOMProperties(null, props, transaction);
  },

  _updateDOMProperties: function(lastProps, nextProps, transaction) {
    ...,

    for (propKey in nextProps) {
      ...,
      if ... {
        ...,
      } else if (registrationNameModules.hasOwnProperty(propKey)) {
        if (nextProp) {
          enqueuePutListener(this, propKey, nextProp, transaction);
        } else if (lastProp) {
          deleteListener(this, propKey)
      } ...,
    }
  },
```

```js
var registrationNameModules = EventPluginRegistry.registrationNameModules;
```

```js:EventPluginRegistry.js
var EventPluginRegistry = {
  ...,

  registrationNameModules: {},
};
```

空だが、実はinjectの最中に登録されていた。

```js:
function recomputePluginOrdering() {
  ...,

  for (var pluginName in namesToPlugins) {
    var PluginModule = namesToPlugins[pluginName];
    ...,
    EventPluginRegistry.plugins[pluginIndex] = PluginModule;
    var publishedEvents = PluginModule.eventTypes;
    for (var eventName in publishedEvents) {
      invariant(
        publishEventForPlugin(
          publishedEvents[eventName],
          PluginModule,
          eventName
        ),
        'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.',
        eventName,
        pluginName
      );
    }
  }
}

function publishEventForPlugin(dispatchConfig, PluginModule, eventName) {
  ...,
  EventPluginRegistry.eventNameDispatchConfigs[eventName] = dispatchConfig;
  var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames;
  if (phasedRegistrationNames) {
    for (var phaseName in phasedRegistrationNames) {
      if (phasedRegistrationNames.hasOwnProperty(phaseName)) {
        var phasedRegistrationName = phasedRegistrationNames[phaseName];
        publishRegistrationName(
          phasedRegistrationName,
          PluginModule,
          eventName
        );
      }
    }
    return true;
  } else if (dispatchConfig.registrationName) {
    publishRegistrationName(
      dispatchConfig.registrationName,
      PluginModule,
      eventName
    );
    return true;
  }
  return false;
}

function publishRegistrationName(registrationName, PluginModule, eventName) {
  ...,
  EventPluginRegistry.registrationNameModules[registrationName] = PluginModule;
  EventPluginRegistry.registrationNameDependencies[registrationName] =
    PluginModule.eventTypes[eventName].dependencies;
  ...,
}
```

```js:namesToPlugins
namesToPlugins = {
  SimpleEventPlugin: SimpleEventPlugin,
  EnterLeaveEventPlugin: EnterLeaveEventPlugin,
  ChangeEventPlugin: ChangeEventPlugin,
  SelectEventPlugin: SelectEventPlugin,
  BeforeInputEventPlugin: BeforeInputEventPlugin,
}
```

```js:SimpleEventPlugin
var eventTypes = {
  ...,
  click: {
    phasedRegistrationNames: {
      bubbled: keyOf({onClick: true}),
      captured: keyOf({onClickCapture: true}),
    },
  },
  ...,
};

var SimpleEventPlugin = {
  eventTypes: eventTypes,
  ...,
};
```

```js:keyOf
var keyOf = function(oneKeyObj) {
  var key;
  for (key in oneKeyObj) {
    if (!oneKeyObj.hasOwnProperty(key)) {
      continue;
    }
    return key;
  }
  return null;
};
```

keyだけを取り出すfunciton。
ここまでで、`registrationNameModules['onClick']=SimpleEventPlugin`となる。
あとはonChangeなどの基本的なイベントがPluginによって提供されている。
EventHandler用の分岐処理ということがわかった。
よって、`name`や`text`などのpropertyは最後の分岐を通る。

```js:ReactDOMComponent.js
function isCustomComponent(tagName, props) {
  return tagName.indexOf('-') >= 0 || props.is != null;
}

  ...,
  _updateDOMProperties: function(lastProps, nextProps, transaction) {
    ...,

    for (propKey in nextProps) {
      ...,
      if ... {
        ...,
      } else if ..., {
        ...,
      } else if (isCustomComponent(this._tag, nextProps)) {
        ...,
      } else if ..., {
        ...,
      }
    }
  },
```

`-`をtagが含んでいればCusotmComponentと判断されるようだ。

```js:ReactDOMComponent.js
  _updateDOMProperties: function(lastProps, nextProps, transaction) {
    ...,

    for (propKey in nextProps) {
      ...,
      if ... {
        ...,
      } else if ..., {
        ...,
      } else if ..., {
        ...,
      } else if 
          DOMProperty.properties[propKey] ||
          DOMProperty.isCustomAttribute(propKey)) {
        var node = getNode(this);
        // If we're updating to null or undefined, we should remove the property
        // from the DOM node instead of inadvertently setting to a string. This
        // brings us in line with the same behavior we have on initial render.
        if (nextProp != null) {
          DOMPropertyOperations.setValueForProperty(node, propKey, nextProp);
        } else {
          DOMPropertyOperations.deleteValueForProperty(node, propKey);
        }
      }
    }
  },
```

```js
DOMProperty.properties = HTMLDOMPropertyConfig.Properties = {
  // 色々ある
}

DOMProperty.properties = SVGDOMPropertyConfig.Properties = {
  // 色々ある
  // attributeに実際のpropertyは含まれている
  // property自体はすべて0が詰められている
}
```

```js:DOMPropertyOperations.js
var DOMPropertyOperations = {
  ...,
  setValueForProperty: function(node, name, value) {
    ...,
    var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ?
        DOMProperty.properties[name] : null;
    if (propertyInfo) {
      var mutationMethod = propertyInfo.mutationMethod;
      if (mutationMethod) {
        mutationMethod(node, value);
      } else if (shouldIgnoreValue(propertyInfo, value)) {
        this.deleteValueForProperty(node, name);
      } else if (propertyInfo.mustUseProperty) {
        var propName = propertyInfo.propertyName;
        // Must explicitly cast values for HAS_SIDE_EFFECTS-properties to the
        // property type before comparing; only `value` does and is string.
        if (!propertyInfo.hasSideEffects ||
            ('' + node[propName]) !== ('' + value)) {
          // Contrary to `setAttribute`, object properties are properly
          // `toString`ed by IE8/9.
          node[propName] = value;
        }
      } else {
        ...,
      }
    } else if ... {
      ...,
    }
  },
  ...,
};
```

```js:DOMProperty.js
var DOMPropertyInjection = {
      ...,
      var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {};
      ...,
      if (DOMMutationMethods.hasOwnProperty(propName)) {
        propertyInfo.mutationMethod = DOMMutationMethods[propName];
      }
      ...,
};
```

DOMMutationMethodsはnullなので無視。

```js
node.setAttribute(attributeName, '' + value);
```

普通のpropertyの場合はこちら。

```js:
node = getNode(ReactDOMComponent) = ReactDOMComponentTree.getNodeFromInstance(ReactDOMComponent)
```

```js:ReactDOMComponentTree.js
function getInstanceFromNode(node) {
  var inst = getClosestInstanceFromNode(node);
  if (inst != null && inst._nativeNode === node) {
    return inst;
  } else {
    return null;
  }
}

var ReactDOMComponentTree = {
  ...,
  getNodeFromInstance: getNodeFromInstance,
  ...,
};
```

```js:ReactDOMComponentTree.js
function getClosestInstanceFromNode(node) {
  if (node[internalInstanceKey]) {
    return node[internalInstanceKey];
  }

  // Walk up the tree until we find an ancestor whose instance we have cached.
  var parents = [];
  while (!node[internalInstanceKey]) {
    parents.push(node);
    if (node.parentNode) {
      node = node.parentNode;
    } else {
      // Top of the tree. This node must not be part of a React tree (or is
      // unmounted, potentially).
      return null;
    }
  }

  var closest;
  var inst;
  for (; node && (inst = node[internalInstanceKey]); node = parents.pop()) {
    closest = inst;
    if (parents.length) {
      precacheChildNodes(inst, node);
    }
  }

  return closest;
}
```

internalInstance(wrapされたComponent)を持つ親があればそれを返す。
なければ持つ親を探して、それをキャッシュして返すだけ。
最終的にはnodeのpropsに値を詰めているだけのように思える。