Front-end development has evolved tremendously over time. The constant need for large-scale web app development at a faster pace has led to the inception of many JavaScript frameworks.
Of the many, React has become one of the most popular with time. It has large community adoption, easy-to-use APIs, and is developer-friendly, especially for newbies. According to the StackOverflow developer survey, it is the most popular framework for web app development.
Despite its popularity, React is still considered a slow framework because of its virtual DOM and the large file size of its core implementation, especially for large applications.
These drawbacks of React inspired a new framework named Preact, which is custom-tailored for certain types of applications as an alternative to React.
Preact is a 3KB but uses the same cutting-edge API and has the same support for ECMAScript. Its small size is due to the fact that it was created to function in a browser with the DOM, incorporating the virtual DOM like many frameworks. Additionally, it beats other JavaScript frameworks in terms of speed.
The popularity of Preact is reflected by the fact that it has 33,100 stars on GitHub and 1,799,020 weekly downloads on npm at the time of writing this article.
React is the best choice when we have to build complex and highly scalable apps, especially SPAs. It has kept functional programming at the core, still infusing declarative and component-based styles, making it easier to distribute and develop applications in a large team.
The virtual DOM ensures high speed and minimum change re-renders of components when there is an update in the application.
React also provides effective server-side rendering, making it the ideal JavaScript framework for building apps that are simple to optimize for search engines.
Having extensive community support is the cherry on top.
If performance, speed, and size of the application are important factors to you, Preact is the ideal option. It is mainly utilized to create advanced web apps. For instance, Uber moved to Preact in production to make its PWA lightweight and powerful.
Aside from this, Preact is a tiny library, and it is built on top of React, so there is not much additional learning required. It is simple to use and can be used with the current React package with some aliasing, i.e., using preact/compat, due to its compatibility and likeness to React.
Preact is not the reimplementation of React. Rather, it is a booster dose that aims to fix certain bottlenecks that hamper performance.
preact/compat adds a thin layer on Preact in an effort to make Preact completely compatible with React.
The primary difference between React and Preact is that React uses synthetic events, which are wrapped around the actual events that React has added to make all the events work seamlessly across all browsers.
Preact has discarded these for their performance and code-size issues.
It registers event handlers using the browser’s standard addEventListener. Event nomenclature and behavior are identical to those of simple JavaScript/DOM.
With a few minor exceptions, the standard browser events function similarly to how they operate in React:
Preact adheres more closely to the DOM specification, custom events are supported with case-sensitive names, and custom elements are handled similarly to standard elements (as they are in the DOM).
If you want to use the existing APIs of React in Preact, you can do so with the help of preact/compat.
Hooks are not part of the core in Preact. They have been separated out to keep the main bundle small and thus need to be imported separately.
We can import Hooks either from preact/hooks or preact/compat.
import { useState } from 'preact/hooks'; const App = () => { const [number, setNumber] = useState(0); const increment = () => setNumber(count + 1); // callback can be passed to the setter const decrement = () => setNumber((currentNumber) => currentNumber - 1); return ( <div> <p>Number: {Number}</p> <button onClick={increment}>Increment</button> <button onClick={decrement}>Decrement</button> </div> ) };
Preact is one of the quickest virtual DOM libraries available thanks to its small size as well as its simple and reliable implementation of the diff.
Preact was one of the earliest frameworks to support ES modules because it was designed with the module system in mind. We can load ES modules directly in browsers using the import keyword without going via a bundler first.
<script type="module"> import { h, Component, render } from 'https://unpkg.com/preact?module'; import htm from 'https://unpkg.com/htm?module'; // initialize htm with Preact const html = htm.bind(h); function App (props) { return html`<h1>Hello ${props.name}!</h1>`; } // render App with bypassing prop name=”world” render(html`<${App} name="World" />`, document.body); </script>
Preact has conveniently given this.props and this.state to the class component’s render() method.
In React and Preact, using preact/compat.
class App extends Component { state = { count: 1 }; render() { return <div>Name: {this.props.name}, Count: {this.state.count}</div>; } }
In Preact without preact/compat.
class App extends Component { state = { count: 1 }; render({ name }, { count }) { return <div>Name: {name}, Count: {count}</div>; } }
Preact strives to resemble the DOM specification that is accepted by all significant browsers. Preact internally determines whether each prop should be set as an HTML attribute or a property when applying props to an element. This not only allows complex properties to be put on custom elements, but also allows attribute names like the class in JSX.
//Preact <div class="foo" /> //React <div className="foo" />
SVG are the JavaScript of the HTML tags when it comes to properties and attributes.
A few properties and their attributes are camelCased such as the clipPathUnits on a clipPath element. Others are kebab-cased, such as clip-path on many SVG elements), while those inherited from the DOM, such as oninput, are all lowercase.
Preact supports the SVG natively. You can copy any SVG snippet and have it go as expected. This makes developers’ life easy, as they can directly pick things from mockups rather than converting attributes or properties to camel case.
SVG in React
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"> <circle fill="none" strokeWidth="2" strokeLinejoin="round" cx="24" cy="24" r="20" /> </svg>
SVG in Preact
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"> <circle fill="none" stroke-width="2" stroke-linejoin="round" cx="24" cy="24" r="20" /> </svg>
We no longer have to use the onChange event on form elements. You can use the native input, and it will work the same.
React
<input onChange={e => console.log(e.target.value)} />
Preact
<input onInput={e => console.log(e.target.value)} />
The majority of onChange events are internally transformed to onInput when using preact/compat to mimic React’s behavior. This is one of the techniques to make sure the React ecosystem is as compatible as possible.
Simply put, JSX is the JavaScript syntactic extension that transforms JSX into nested functional calls.
Preact promotes the original universal community standard that the hyperscript project popularized in JavaScript and makes use of nested function calls to construct tree structures.
JSX
<a href=”/”> <span>Home</span> </a>
React output
React.createElement( 'a', { href:'/' }, React.createElement('span', null, 'Home') );
Preact output
h( 'a', { href:'/' }, h('span', null, 'Home') );
In React, for interacting with the value of props.children, there is a specific collection of methods called the Children API. Preact normally does not need this, so they advise using the built-in array methods.
In Preact, props.children can be a virtual DOM node, a value that is empty, such as null, or an array of virtual DOM nodes. Since children can be used or returned in their current state, the first two scenarios are the most straightforward and frequent.
React
function App(props) { return <Element content={Children.only(props.children)} /> }
Preact
// Preact: use props.children directly: function App(props) { return <Element content={props.children} /> }
If you want to iterate over the children received, you can use the toChildArray() method. It accepts any props.children value and return a flattened and normalized array of virtual DOM nodes.
React
function App(props) { const cols = Children.count(props.children); return <div data-columns={cols}>{props.children}</div> }
Preact
function App(props) { const cols = toChildArray(props.children).length; return <div data-columns={cols}>{props.children}</div> }
There are also some specialized components in Preact designed for special cases.
In order to use them, we have to set up the preact/compat.
The simplest way is to use the alias and partly migrate the features of React with Preact while still continuing to use the existing libraries of React.
To set any package in the webpack as the alias, update or add the resolve.alias section in your webpack config.
"resolve": { "alias": { "react": "preact/compat", "react-dom/test-utils": "preact/test-utils", // should always be below the test-utils "react-dom": "preact/compat", "react/jsx-runtime": "preact/jsx-runtime" }, }
Our setup is done, and now we can use these extra features of Preact in the existing app:
PureComponent: Component rerenders or updates only when the props or state have changed.
import { render } from 'preact'; import { PureComponent } from 'preact/compat'; class App extends PureComponent { render(props) { console.log("called") return <div /> } }; const dom = document.getElementById('root'); render(<App name="syncfusion" />, dom); // Logs: "called" // second time, doesn't log anything render(<App name="syncfusion" />, dom);
memo: Similar to PureComponent, but memo lets you use a custom comparison function for deciding the updates conditionally.
import { memo } from 'preact/compat'; function App(props) { return <div>Hello {props.name}</div> } // normal memoization const Memoed = memo(App); // memoizing with custom comparison function const Memoed2 = memo(App, (prevProps, nextProps) => { // re-render when `name' changes return prevProps.name === nextProps.name; });
forwardRef: Passes the reference to the child components.
import { createRef, render } from 'preact'; import { forwardRef } from 'preact/compat'; const App = forwardRef((props, ref) => { return <div ref={ref}>Hello world</div>; }) // `ref` will reference to the div child rather than the `App` const ref = createRef(); render(<App ref={ref} />, dom);
Portals: Allows us to render components in different DOM elements.
<html> <body> <!-- app will render here --> <div id="app"></div> <!-- modal will render 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 {/*modal will render in its container outside the app*/} {createPortal(<MyModal />, container)} </div> ) }
Preact also has a built-in CLI and we can use it to scaffold a new project, similar to the create-react-app.
npm install -g preact-cli
preact create default my-project
Here, the default keyword refers to the one you would like to use for your project.
Popular available choices are:
I hope you now have a clear idea of differences between Preact and React. React is a popular JavaScript library among web developers, while Preact is an enhanced version of React that makes applications lighter and faster.
The Syncfusion Essential Studio® for React suite offers high-performance, lightweight, modular, and responsive UI components in a single package. It’s the only suite you’ll ever need to construct a complete app.
If you have questions, contact us through our support forum, support portal, or feedback portal. We are always happy to assist you!