Differences Between Composi and React

Although Composi and React share many API features, there are substantial differences. The following tables show what they share and how they differ.

API

Composi React
h React.createElement
mount ReactDOM.hydrate
render ReactDOM.render
Component React.Component
Component.render React.Component.render
Component.state React.Component.state
Component.setState React.Component.setState
Component.update React.Component.forceUpdate
Component.unmount N/A
Fragment React.Fragment

Composi uses mount to render a functional component the first time. This returns a reference to the component tree. You can pass that reference to the render function in order to update that functional component efficiently.

mount is also used to hydrate server-side rendered DOM with functional components, similar to ReactDOM.hydrate. Just pass a DOM reference for the structure to hydrate as the third argument to mount:

// Hydrate H1 inside header tag:
  mount(<Title message='Amazing Title'/> 'header', 'h1')

Use render to update an already mounted functional component:

const title = mount(<Title message='Boring!'/>, 'header')
// Sometime later update the title.
// Pass in the 'title' variable from above:
render(<Title message='An Amazing Title!!!'/>, title)

Properties

Composi React
class className
inline events inline events (synthesized)
onclick onClick
oninput onUpdate
for htmlFor
xlink-href or xlinkHref xlinkHref
innerHTML (string) dangerouslySetInnerHTML (callback)
style (accepts object or standard inline string value) style (accepts object)

Inline events are just inline events, same as they've always been since DOM Level 0. Composi uses standard HTML attributes. No need for camel case or non-standard terms. For SVG icons you can use xlink-href. innerHTML works as it normally does with DOM elements. It accepts a string as its value. No need for a complicated function like with React. style can take a JavaScript object literal of key value pairs, or you can use a string as you normally would with HTML. React and friends only accept an object.

For inserting arbitrary markup into the DOM, Composi uses innerHTML. React uses dangerouslySetInnerHTML, which requires a callback.

function Title() {
  return (
    <h1>Original Content</h1>
  )
}
const title = mount(<Title/>, 'header')
// Later update the title:
title = render(title, <Title innerHTML='The New Title!'/>, 'header')

Lifecycle Hooks for Class Components

Composi React
componentWillMount componentWillMount/UNSAFE_componentWillMount
componentDidMount componentDidMount
componentWillUpdate componentWillUpdate/UNSAFE_componentWillUpdate
componentDidUpdate componentDidUpdate
componentWillUnmount componentWillUnmount/UNSAFE_componentWillUnmount
N/A componentWillReceiveProps/UNSAFE_componentWillReceiveProps
N/A getDerivedStateFromProps
componentShouldUpdate (attribute) componentShouldUpdate (callback)

componentShouldUpdate is an attribute that accepts a boolean value. By default it is true. Setting this property to false will prevent it from updating, event when its state changes. After making state changes, you can flag the component to update again by setting this property to true. The next update will show the changes. In contrast, this is a function that meeds to return a boolean.

class Title extends Component {
  render(data) {
    return (
      <h1>{data}</h1>
    )
  }
}
// Create instance.
// Because it has no state, it does not yet render.
const title = new Title({
  state: 'A Great Title',
  container: 'header'
})
title.componentShouldUpdate = false

// Sometime later you want to change the title.
// Because 'componentShouldUpdate' was set to false, nothing will happen.
title.setState('A Brand New Title!')

// To update the component, set 'componentShouldUpdate' to true, 
// then run 'update' on the component instance:
title.componentShouldUpdate = true
title.update()

Lifecycle Events for Functional Components

Composi provides lifecycle hooks for functional components. These are used like inline events. React has n equivalent.

Composi React
onmount N/A
onupdate N/A
onunmount N/A

onComponentDidMount gets passed the root element of the functional component. componentDidUpdate gets passed the old props, the new props and the root element of the component. onComponentWillUnmount gets passed the parent element of the component.

// Use 'onComponentDidMount' to register event on component:
function List(props) {
  return (
    <div class='container-list' onComponentDidMount={(element)=> initEvent(element)}>
      <ListForm />
      <ul class='list-fruit'>
        {props.items.map(item => <ListItem {...{item}}/>)}
      </ul> 
    </div>
  )
}
// Access the component element to register event:
function initEvent(element) {
  element.addEventListener('click', callBack)
}

Codepen Example:

See the Pen Composi functional-components-4 by Robert Biggs (@rbiggs) on CodePen.

createRef/Ref

Composi React
N/A (use this.element with componentDidMount to access DOM) React.createRef
N/A (same as above) ref

Composi does not have createRef like React, and so it does not support the ref property on elements. But you don't need it. Instead you can take advantage of a component's element property in the componentDidUpdate lifecycle hook to access elements in the DOM:

See the Pen Composi No Ref by Robert Biggs (@rbiggs) on CodePen.

Instantiation

Composi React
mount (for functional components) ReactDOM.hydrate/ReactDOM.render
new - use to instatiate class component React.DOM.render

To render a functional component the first time, use mount:

function Title({message}) {
  return (
    <nav>
      <h1>{message}</h1>
    </nav>
  )
}
// Mount the custom tag in the header:
const title = mount(<Title message='A Great Title'/>, 'header')

To mount a class component, instantiate it with the new keyword. If the class component has state, it will render to the DOM automatically when you instantiate it. If it is stateless, you'll need to run update on the instance to render it.

Here we create a stateful component. By instantiating it witht he new keyword, the component renders immediately:

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

Here we create a stateless component. When we instantiate it, we provide state. This causes the component to render immediately:

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

Here we create a stateless component. When we instantiate it, nothing happens. However, when we set state on the component instance with the setState method, the component renders immediately:

See the Pen Composi Instantiation - 3 by Robert Biggs (@rbiggs) on CodePen.

Here we create a stateless component. It will never have state. When we instantiate it, nothing happens. We provide it data to render by passing the data to the update method. This is therefore a "pure" component.

See the Pen Composi Instantiation - 4 by Robert Biggs (@rbiggs) on CodePen.