Switching to Preact (from React)
preact/compat
is our compatibility layer that allows you to leverage the many libraries of the React ecosystem and use them with Preact. This is the recommended way to try out Preact if you have an existing React app.
This lets you continue writing React/ReactDOM code without any changes to your workflow or codebase. preact/compat
adds somewhere around 2kb to your bundle size, but has the advantage of supporting the vast majority of existing React modules you might find on npm. The preact/compat
package provides all the necessary tweaks on top of Preact's core to make it work just like react
and react-dom
, in a single module.
Setting up compat
To set up preact/compat
you need to alias react
and react-dom
to preact/compat
. The Getting Started page goes into detail on how aliasing is configured in various bundlers.
PureComponent
The PureComponent
class works similar to Component
. The difference is that PureComponent
will skip rendering when the new props are equal to the old ones. To do this we compare the old and new props via a shallow comparison where we check each props property for referential equality. This can speed up applications a lot by avoiding unnecessary re-renders. It works by adding a default shouldComponentUpdate
lifecycle hook.
import { render } from 'preact';
import { PureComponent } from 'preact/compat';
class Foo extends PureComponent {
render(props) {
console.log("render")
return <div />
}
}
const dom = document.getElementById('root');
render(<Foo value="3" />, dom);
// Logs: "render"
// Render a second time, doesn't log anything
render(<Foo value="3" />, dom);
Note that the advantage of
PureComponent
only pays off when then render is expensive. For simple children trees it can be quicker to just do therender
compared to the overhead of comparing props.
memo
memo
is equivalent to functional components as PureComponent
is to classes. It uses the same comparison function under the hood, but allows you to specify your own specialized function optimized for your use case.
import { memo } from 'preact/compat';
function MyComponent(props) {
return <div>Hello {props.name}</div>
}
// Usage with default comparison function
const Memoed = memo(MyComponent);
// Usage with custom comparison function
const Memoed2 = memo(MyComponent, (prevProps, nextProps) => {
// Only re-render when `name' changes
return prevProps.name === nextProps.name;
})
The comparison function is different from
shouldComponentUpdate
in that it checks if the two props objects are equal, whereasshouldComponentUpdate
checks if they are different.
forwardRef
In some cases when writing a component you want to allow the user to get hold of a specific reference further down the tree. With forwardRef
you can sort-of "forward" the ref
property:
import { createRef, render } from 'preact';
import { forwardRef } from 'preact/compat';
const MyComponent = forwardRef((props, ref) => {
return <div ref={ref}>Hello world</div>;
})
// Usage: `ref` will hold the reference to the inner `div` instead of
// `MyComponent`
const ref = createRef();
render(<MyComponent ref={ref} />, dom)
This component is most useful for library authors.
Portals
In rare circumstances you may want to continue rendering into a different DOM node. The target DOM node must be present before attempting to render into it.
<html>
<body>
<!-- App is rendered here -->
<div id="app"></div>
<!-- Modals should be rendered here -->
<div id="modals"></div>
</body>
</html>
import { createPortal } from 'preact/compat';
import MyModal from './MyModal';
function App() {
const container = document.getElementById('modals');
return (
<div>
I'm app
{createPortal(<MyModal />, container)}
</div>
)
}
Keep in mind that due to Preact reusing the browser's event system, events won't bubble up through a Portal container to the other tree.
Suspense
The main idea behind Suspense
is to allow sections of your UI to display some sort of placeholder content while components further down the tree are still loading. A common use case for this is code-splitting where you'll need to load a component from the network before you can render it.
import { Suspense, lazy } from 'preact/compat';
const SomeComponent = lazy(() => import('./SomeComponent'));
// Usage
<Suspense fallback={<div>loading...</div>}>
<Foo>
<SomeComponent />
</Foo>
</Suspense>
In this example the UI will display the loading...
text until SomeComponent
is loaded and the Promise is resolved.
Suspense in both React and Preact isn't quite finalized or set it stone as of yet. While the React team still actively discourages users interfacing with it directly for data fetching, it's a pattern some Preact users have been happily using over the last few years. There are a few known issues (please see our tracker for an up-to-date reference) but it's generally considered stable enough for use in production if you so wish.
This site, for instance, is built using a Suspense-based data fetching strategy used to load all content you see.