Skip to content

Instantly share code, notes, and snippets.

@developit
Last active August 25, 2017 00:51
Show Gist options
  • Save developit/89e0e6decb8fb5eb00def024b6fb7bd7 to your computer and use it in GitHub Desktop.
Save developit/89e0e6decb8fb5eb00def024b6fb7bd7 to your computer and use it in GitHub Desktop.
Important changes coming in Preact 8

Removed: Element Recycling

DOM Element recycling will be removed in Preact 8.

This should have no effect on most applications. In fact, it fixes a number of known issues related to element state not being fully reset on reuse.

💡 Why? Many DOM properties are stateful, and trying to reset them all when recycling is a game of whack-a-mole. Preact's size makes it infeasible to use whitelists to address these issues, so recycling is being dropped.

Recycling as a performance optimization became less relevant in Preact 4 when Component recycling was modified to account for the majority of the cases where Element recycling had previously been relied on. The Pure Function Components rewrite removed the last meaningful use-case for Element recycling, so we're dropping it and the bugs it brought along with it.


Removed: Object class Values

The following will stop working in Preact 8:

<div class={{ foo: true }} />
<div className={{ [style.foo]: 0 }} />

💡 Why? Serializing objects prevented CSS solutions from using toString casting.

Solution

Install and use classnames. It supports this syntax & more and is around 500 bytes.

import cx from 'classnames';

<div class={cx({ foo: true })} />  // nearly the same
<div className={cx([{ foo: true }, 0, 'test'])} />  // nice

Polyfill

If you're fine with polyfilling, here you go:

import { options } from 'preact';
import cx from 'classnames';

let old = options.vnode;
options.vnode = vnode => {
	let props = vnode.attributes;
	if (props && props.class && typeof props.class==='object') {
		props.class = cx(props.class);
	}
	if (old) old(vnode);
};

Rewritten: Pure Functional Components

Pure Functional Components get backing instances in Preact 8. Outwardly, this means refs on PFC's now point to their backing instance instead of their DOM element.

This means instead of being called inline during rendering, they are persisted in the component tree just like Component instances. In fact, they are Component instances. This is pretty nifty, since it allows us to explore new things like Stateful Functional Components and even shouldComponentUpdate optimization of Pure Functional Components.

Solution

You should avoid using ref on Pure Functional Components. This behavior is Preact-specific and not part of the officially supported API. That said, if you were previously relying on ref pointing at the rendered DOM element from a Pure Functional Component, simply look for .base as you would for a Component instance:

// before:
<PureInput ref={ c => c.focus() } />
// after:
<PureInput ref={ c => c.base.focus() } />

Polyfill

This one's a little trickier:

import { options } from 'preact';

let old = options.vnode;
options.vnode = vnode => {
	let f = vnode.nodeName,
		props = vnode.attributes,
		ref = props && props.ref;
	if (typeof f==='function' && !(f.prototype && f.prototype.render) && ref) {
		props.ref = c => ref(c.base);
	}
	if (old) old(vnode);
};

💡 Why? Preact outgrew its simple method for handling functional components thanks to optimizations in 5.x through 7.x. Rather than penalize developers for choosing the lovely Pure Functional Component approach, we're making them just as good as Component.

This change also enables proper component recycling and inter-component diffing for Functional Components, and considerably simplifies the rendering process. Where previously all Component tests needed to test both Component and PFC's, now only Component need be tested as they share an implementation.


Removed: linkState()

Component.prototype.linkState() is being removed from Preact itself, since it was only used by a fraction of people. Instead, it is now available as a standalone linkstate module.

The linkstate module includes a polyfill (linkstate/polyfill) that installs itself into Preact's Component. This provides the behavior that was present in 7.x and prior.

@rmacklin
Copy link

I'm upgrading an application from preact 7 to 8 right now, and wanted to add this tidbit to help others:

If you're upgrading to preact 8 and you also use preact-jsx-chai, you may run into a test failure like the one in this issue: developit/preact-jsx-chai#46. To fix it, you'll also need to upgrade preact-render-to-string (to 3.6.2 or later).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment