Version 3.0.0 is coming.
rbiggs opened this issue · 1 comments
rbiggs commented
We are working on version 3.0.0. This has some breaking changes. This is a complete rewrite of the diff algorithm affecting every other part of Composi. 3.0.0 introduces significantly faster render times.
- Adds new virtual node type: Text
- Adds two new functions:
vnodeFromElement
andvnodeFromChild
. These convert a server-rendered DOM tree into a virtual node. This allows Composi to reuse server content, adding events and dynamic behaviors. - Due to changes in the diff algorithm, the
render
function has a new call signature:
import {h, mount, render) from 'composi'
let title = mount(<Title message='New Message'/>, 'header')
/**
* Notice how we re-capture the component in the `title` variable and we also pass in the reference to the component container:
*/
title = render(<Title message='New Message'/>, title, 'header')
- Due to changes in the diff algorithm, we can no longer short circuit the patch process when calling
render
. This means that theonupdate
lifecycle hook will always fire, event if the component did not update. This is possible where the same data is used when re-rendering a functional component. You can use theonupdate
callback to check whatever properties you have to determine if the component actually changed. - Class components require the use of the
hydrate
property to indicate what element in the DOM to hydrate. This tells Composi to create a virtual node from that element and pass it to thepatch
function. - Unlike functional components, when you use
componentWillUpdate
orcomponentDidUpdate
in a class component, if the data is the same, meaning the component will not actually change, these hooks will not execute. - The
componentWillUnmount
now gets passed adone
function. This handles the actual unmounting of the class component. That means if you use thecomponentWilUnmount
lifecycle hook in a class component, you have to also pass in thedone
callback and invoke it. Otherwise, the component will never unmount.
Examples of new behaviors
The new render
behavior:
import { h, mount, render } from 'composi'
let input = null
let key = 104
const fruits = [
{ key: 101, value: 'Apples' },
{ key: 102, value: 'Oranges' },
{ key: 103, value: 'Bananas' }
]
function List(props) {
function init(el) {
input = el.querySelector('input')
input.focus()
}
function addItem() {
const value = input.value
if (value) {
fruits.push({
key: key++,
value
})
// Update the component.
// Pass list from mount and re-capture it.
// Don't forget to pass in container as last argument.
list = render(<List fruits={fruits} />, list, 'section')
input.value = ''
input.focus()
} else {
alert('Please add a value before submitting.')
}
}
return (
<div onmount={el => init(el)}>
<p>
<input type="text"/>
<button onclick={() => addItem()}>Add</button>
</p>
<ul>
{
props.fruits.map(item => <li key={item.key}>{item.value}</li>)
}
</ul>
</div>
)
}
let list = mount(<List fruits={fruits}/>, 'section')
Hydrating a class component:
import { h, Component }
class List extends Component {
// Define list component here...
}
// Instantiate list component:
const list = new List({
state: fruits,
container: 'section',
hydrate: '#old-list-from-server'
})
If your class component is a single use one, you can put the hydrate
property directly in the constuctor:
import { h, Component }
class List extends Component {
constructor(props) {
super(props)
this.state = fruits
this.container = 'section'
this.hydrate = '#old-list-from-server'
}
// Define rest of list component here...
}
// Instantiate list component:
const list = new List()
How to use componentWilUnmount
in a class component:
// This component has a `setInterval` to control clock ticking set up in `componentDidMount`.
// When the component unmounts, we need to clear this in the `componentWillUnmout` hook.
class Clock extends Component {
// Define component here...
// Add lifecycle hooks:
componentDidMount() {
// Store timer referrence so we can clear it later:
this.timerID = setInterval(
() => this.tick(),
1000
);
}
// If component is unmounted, end interval loop.
// Notice the `done` callback.
// This needs to be invoked last.
// Otherwise the component will not unmount.
componentWillUnmount(done) {
clearInterval(this.timerID)
done()
}
}
rbiggs commented
Launched so closing this.