function render(oldTree, newTree, transaction) {
  let oldComponentTree = null;

  // When there is an oldTree and it has childNodes, attempt to look up first
  // by the top-level element, or by the first element.
  if (oldTree) {
    // First try and lookup the old tree as a component.
    oldComponentTree = ComponentTreeCache.get(oldTree);

    // If that fails, try looking up its first child.
    if (!oldComponentTree && oldTree.childNodes) {
      oldComponentTree = ComponentTreeCache.get(oldTree.childNodes[0]);
    }
  }

  // If there is no old component, or if the components do not match, then we
  // are rendering a brand new component.
  if (!oldComponentTree || oldComponentTree.rawNodeName !== newTree.rawNodeName) {
    return renderComponent(newTree, transaction);
  }

  // Otherwise re-use the existing component if the constructors are the same.
  if (oldComponentTree) {
    // Update the incoming props/attrs.
    assign(oldComponentTree.attributes, newTree.attributes);

    return renderComponent(oldComponentTree, transaction);
  }

  return oldTree;
}
@param {VTree} oldTree
@param {VTree} newTree
@param {Transaction} transaction

@returns {VTree | null}