Option 1: createVNode(component, props) and render(vnode, container)
Creating: Use createVNode() to create a VNode of a component definition (e.g., imported SFC from *.vue) with props, which could be passed to render() to render it on a given container element.
Destroying: Calling render(null, container) destroys the VNode attached to the container. This should be called as cleanup when the parent component unmounts (via unmounted lifecycle hook).
// renderComponent.js
import { createVNode, render } from 'vue'
export default function renderComponent({ el, component, props, appContext }) {
  let vnode = createVNode(component, props)
  vnode.appContext = { ...appContext }
  render(vnode, el)
  return () => {
    // destroy vnode
    render(null, el)
    vnode = undefined
  }
}
Caveat: This approach relies on internal methods (createVNode and render), which could be refactored or removed in a future release.
demo 1
Option 2: createApp(component, props) and app.mount(container)
Creating: Use createApp(), which returns an application instance. The instance has mount(), which can be used to render the component on a given container element.
Destroying: The application instance has unmount() to destroy the app and component instances. This should be called as cleanup when the parent component unmounts (via unmounted lifecycle hook).
// renderComponent.js
import { createApp } from 'vue'
export default function renderComponent({ el, component, props, appContext }) {
  let app = createApp(component, props)
  Object.assign(app._context, appContext) // must use Object.assign on _context
  app.mount(el)
  return () => {
    // destroy app/component
    app?.unmount()
    app = undefined
  }
}
Caveat: This approach creates an application instance for each component, which could be non-trivial overhead if there's a need to instantiate many components simultaneously in the document.
demo 2
Example usage
<script setup>
import { ref, onUnmounted, getCurrentInstance } from 'vue'
import renderComponent from './renderComponent'
const { appContext } = getCurrentInstance()
const container = ref()
let counter = 1
let destroyComp = null
onUnmounted(() => destroyComp?.())
const insert = async () => {
  destroyComp?.()
  destroyComp = renderComponent({
    el: container.value,
    component: (await import('@/components/HelloWorld.vue')).default
    props: {
      key: counter,
      msg: 'Message ' + counter++,
    },
    appContext,
  })
}
</script>
<template>
  <button @click="insert">Insert component</button>
  <div ref="container"></div>
</template>