Mount

Class-based components provide a powerful and convenient way for you to create modular chunks of UI. However, sometimes they are overkill. If you just need to output some static markup, a component is not necessary. Instead you can define a function that returns the markup. This is sometimes called a functional component. You can read the docs for functional components to learn more about how to create and use them. Once you've created a function component, you can inject it into the document with this mount function. To use it, you will need to import it into your code:

import { h, mount } from 'composi'

mount takes two parameters: tag and container. Tag is either a JSX tag or an h function. container is the DOM node or a valid CSS selector to query that node. If no container is provided or the DOM query finds no match, it will append the tag to the document body.

The mount function always returns an element which you can use as a reference to the DOM tree that needs to be updated by the render function. We show how to do this below when we go into details about the render function.

Here is an example of how to mount a functional component:

import { h, mount } from 'composi'

// Define functional component:
function Title({message}) {
  return(
    <nav>
      <h1>{message}</h1>
    </nav>
  )
}

// Mount the functional component:
mount(<Title message='This is the Title!'/>, 'header')

Hydration with Mount

You use the mount function to hydrate content rendered on the server. This means users will see content load faster. Hydration is performed by passing a third argument to mount for the element you want to hydrate. Composi takes that element, creates a virtual node from it and uses that virtual node to patch the DOM.

import { h, mount } from 'composi'
// Hydrate a server-renered list:
function List(props) {
  return (
    
    { props.data.map(item =>
  • {item.value}
  • ) }
) } const items = ['One', 'Two', 'Three'] // There's a list rendered by the server with an id of #hydratable-list: let list = mount(, 'section', '#hydratable-list')

Using hydration on server-rendered content allows you to embue it with events and dynamic behaviors with Composi. This means you page loads faster and it reaches interactivity faster.

Render

The render function is used to update a mounted functional component. This is done with a reference to the mounted component that you saved, as illustrated in the first mount example above. To use it, you will need to import it into your code:

import { h, mount, render } from 'composi'

render takes three parameters:

  1. vnode: The virtual node returned when a component was mounted.
  2. tag: the function or JSX tag used to mount the component.
  3. container: the element in the DOM of a mounted functional component that you want to update

In the example below we are going to mount a component and then update it with the render function using setTimeout. Notice how we assign the mounted functional component to the title variable:

import { h, mount } from 'composi'

// Define functional component:
function Title({message}) {
  return(
    <nav>
      <h1>{message}</h1>
    </nav>
  )
}

// Store the mounted element in a variable:
const title = mount(<Title message='This is the Title!'/>, 'header')

// Update mounted component.
// Pass in `title` from above as second argument.
// Don't forget to reassign the result to `render` 
// back to the component variable "title".
setTimeout(() => {
  title = render(title, <Title message='A New Message Was Used.'/>, 'header')
}, 5000)

Using render and passing a reference to the DOM tree lets us update the DOM tree in place.

Rendering Functional Components

Codepen Example:

See the Pen Composi render-1 by Robert Biggs (@rbiggs) on CodePen.

We could use the mount function above to make several lists. To do that, we're going to use what's called a custom tag. This is a feature of JSX where when you define a functional component that begins with an uppercase letter, you can use it as a tag. Notice how we pass the CreateList function to mount as a JSX tag, <CreateList data={fruits} />. At build time, Babel will convert that into a function that returns the virtual node for the render function to insert in the DOM.

Since we are using a custom JSX tag, the data that would normally be passed as a parameter to the functional component instead gets passed as a prop. That's the reason we inclosed the parameter data in curly braces when we defined CreateList. We used the term data because the data is generic. Use whatever term makes sense for what you are using.

Codepen Example:

See the Pen Composi render-2 by Robert Biggs (@rbiggs) on CodePen.

In the above example, each subsequent call of the render function will patch and update whatever was previously rendered. Be aware that the inital invocation of mount will not replace any static content already in the container.

Gotchas

mount always appends to the provided container. If you want to have server-side rendered content and replace it with new content, you'll need to use render and pass it a reference to the server-rendered element. Notice in the following example how we query the DOM for the element and then pass it as the second argument of render:

// In the index.html:
<nav class='header'>
  <h1>Server-Rendered Content</h1>
</nav>

// JavaScript:
import { h, mount } from 'composi'

// Define functional component:
function Title({message}) {
  return(
    <nav class='header'>
      <h1>{message}</h1>
    </nav>
  )
}

// Get reference to server-rendered nav at load time:
const header = document.querySelector('.header')

// Update server-rendered component.
// Pass in `header` from above as second argument:
setTimeout(() => render(<Title message='A New Message Was Used.'/>, header), 5000)

Hydration

You can use functional components to hydrate markup that was rendered on the server. Of course this needs to happen at load time. You can do this using the mount function. Please read the API documentation for mount for more details about how to use it to hydrate server-rendered markup with functional components.

If you want to be able to create multiple instances of the same component, you can use mount to inject the functional component into different containers while providing different data for each component, and then use the mount reference to update the functional components later with render.

Unmount

The unmount function allows you to remove the rendered component from the DOM. This does not effect the value of the reference returned by mount and render for that component.

To unmount a component, you pass unmount the value returned by the mount function.

After unmounting a component, you can use mount to mount the component again. If the component has an onmount lifecycle hook, this will also run again.

If your component has events attached with addEventListener, you need to remove those with removeEventListener before unmounting. Otherwise unmounting will create memory leaks that could eventually crash the browser. If you are using inline events, this is not a problem.

Here is a simplified example of mounting and unmounting and remounting to show how to do it:

import { h, mount, unmount } from 'composi'

function Title(props) { 
  return (
    <nav>
      <h1>Hello, {props.greet}!</h1>
    </nav>
  ) 
}
// We will use `title` to unmount later:
let title = mount(<Title greet='Joe' />, 'header') 

// Unmount the component in two seconds:
setTimeout(() => { 
  unmount(title) 
}, 2000) 

// Remount the component in four seconds:
setTimeout(() => { 
  title = mount(<Title greet='Jill'/>, 'header') 
}, 4000)

When to Use Unmount

In most cases you can handle whether a component renders or not using conditional logic. unmount is for those rare cases where that is not an option. For more information about conditional rendering, visit this link.

Summary

Use mount to inject a functional component into the DOM.

render is similar to ReactDOM.render, allowing you to update a mounted component.

unmount lets you remove a mounted component from the DOM, but conditional logic with mount and render is often a better choice.

mount and render make it easy to use functional components. However, class-based components offer more functionality and versitility. If you find you are having a hard time making a functional component do what you want, you should look at using a class component instead. You can learn more about them by reading the docs about how to extend the Component class.