- Notifications
You must be signed in to change notification settings - Fork1
⚛️ Fast 3kb React alternative with the same ES6 API. Components & Virtual DOM.
License
typescript-bot/preact
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Fast3kB alternative to React, with the same ES2015 API.
All the power of Virtual DOM components, without the overhead:
- Familiar React API & patterns:ES6 Class andFunctional Components
- Extensive React compatibility via a simplepreact-compat alias
- Everything you need: JSX, VDOM, React DevTools, HMR, SSR..
- A highly optimized diff algorithm and seamless Server Side Rendering
- Transparent asynchronous rendering with a pluggable scheduler
- 🆕💥 Instant no-config app bundling withPreact CLI
💁 More information at thePreact Website ➞
- Demos
- Libraries & Add-ons
- Getting Started
- Linked State
- Examples
- Extensions
- Developer Tools
- Backers
- Sponsors
- License
Preact supports modern browsers and IE9+:
- ESBench is built using Preact.
- Nectarine.rocks(Github Project) 🍑
- Documentation Viewer(Github Project)
- TodoMVC(Github Project)
- Hacker News Minimal(Github Project)
- Preact Boilerplate(Github Project) ⚡
- Preact Offline Starter(Github Project) 💯
- Preact PWA(Github Project) 🍔
- Preact Mobx Starter(Github Project) ☀️
- Preact Redux Example ⭐
- Flickr Browser (@ CodePen)
- Animating Text (@ CodePen)
- 60FPS Rainbow Spiral (@ CodePen)
- Simple Clock (@ JSFiddle)
- 3D + ThreeJS (@ CodePen)
- Stock Ticker (@ CodePen)
- Create your Own! (@ JSFiddle)
- Preact Coffeescript
- GuriVR(Github Project)
- V2EX Preact
- BigWebQuiz(Github Project)
- Color Picker(Github Project) 🎨
- Rainbow Explorer(Github Project) 🌈
- Offline Gallery(Github Project) 🎈
- Periodic Weather(Github Project) ☀️
- Play.cash 🎶
- 🙌preact-compat: use any React library with Preact(full example)
- 📄preact-render-to-string: Universal rendering.
- ➿preact-render-to-json: Render for Jest Snapshot testing.
- 🌎preact-router: URL routing for your components
- 📑preact-markup: Render HTML & Custom Elements as JSX & Components
- 📡preact-portal: Render Preact components into (a) SPACE 🌌
- 📝preact-richtextarea: Simple HTML editor component
- 🔖preact-token-input: Text field that tokenizes input, for things like tags
- 📇preact-virtual-list: Easily render lists with millions of rows (demo)
- 🔁preact-cycle: Functional-reactive paradigm for Preact
- 📐preact-layout: Small and simple layout library
- 💭preact-socrates: Preact plugin forSocrates
- 🚣preact-flyd: Useflyd FRP streams in Preact + JSX
- 💬preact-i18nline: Integrates the ecosystem aroundi18n-js with Preact viai18nline.
- 🔬preact-jsx-chai: JSX assertion testing(no DOM, right in Node)
- 🎩preact-classless-component: create preact components without the class keyword
- 🔨preact-hyperscript: Hyperscript-like syntax for creating elements
- ✅shallow-compare: simplified
shouldComponentUpdate
helper. - 🍧preact-codemod: Transform your React code to Preact.
- 👷preact-helmet: A document head manager for Preact
- 👔preact-delegate: Delegate DOM events
Want to prototype something or speed up your development? Try one of these toolkits:
- preact-material-components: Material Design Components for Preact (website)
- preact-mdc: Material Design Components for Preact (demo)
- preact-mui: The MUI CSS Preact library.
- preact-photon: build beautiful desktop UI withphoton
- preact-mdl:Material Design Lite for Preact
💁Note: Youdon't need ES2015 to use Preact... but give it a try!
The easiest way to get started with Preact is to installPreact CLI. This simple command-line tool wraps up the best possible Webpack and Babel setup for you, and even keeps you up-to-date as the underlying tools change. Best of all, it's easy to understand! It builds your app in a single command (preact build
), doesn't need any configuration, and bakes in best-practises 🙌.
The following guide assumes you have some sort of ES2015 build set up using babel and/or webpack/browserify/gulp/grunt/etc.
You can also start withpreact-boilerplate or aCodePen Template.
Thepreact
module provides both named and default exports, so you can either import everything under a namespace of your choosing, or just what you need as locals:
import{h,render,Component}from'preact';// Tell Babel to transform JSX into h() calls:/**@jsx h */
importpreactfrom'preact';// Tell Babel to transform JSX into preact.h() calls:/**@jsx preact.h */
Named imports work well for highly structured applications, whereas the default import is quick and never needs to be updated when using different parts of the library.
Instead of declaring the
@jsx
pragma in your code, it's best to configure it globally in a.babelrc
:For Babel 5 and prior:
{"jsxPragma":"h" }For Babel 6:
{"plugins": [ ["transform-react-jsx", {"pragma":"h" }] ]}
Out of the box, Preact provides anh()
function that turns your JSX into Virtual DOM elements(here's how). It also provides arender()
function that creates a DOM tree from that Virtual DOM.
To render some JSX, just import those two functions and use them like so:
import{h,render}from'preact';render((<divid="foo"><span>Hello, world!</span><buttononClick={e=>alert("hi!")}>Click Me</button></div>),document.body);
This should seem pretty straightforward if you've used hyperscript or one of its many friends. If you're not, the short of it is that the h function import gets used in the final, transpiled code as a drop in replacement for React.createElement, and so needs to be imported even if you don't explicitly use it in the code you write. Also note that if you're the kind of person who likes writing your React code in "pure JavaScript" (you know who you are) you will need to use h(...) wherever you would otherwise use React.createElement.
Rendering hyperscript with a virtual DOM is pointless, though. We want to render components and have them updated when data changes - that's where the power of virtual DOM diffing shines. 🌟
Preact exports a genericComponent
class, which can be extended to build encapsulated, self-updating pieces of a User Interface. Components support all of the standard Reactlifecycle methods, likeshouldComponentUpdate()
andcomponentWillReceiveProps()
. Providing specific implementations of these methods is the preferred mechanism for controllingwhen andhow components update.
Components also have arender()
method, but unlike React this method is passed(props, state)
as arguments. This provides an ergonomic means to destructureprops
andstate
into local variables to be referenced from JSX.
Let's take a look at a very simpleClock
component, which shows the current time.
import{h,render,Component}from'preact';classClockextendsComponent{render(){lettime=newDate().toLocaleTimeString();return<span>{time}</span>;}}// render an instance of Clock into <body>:render(<Clock/>,document.body);
That's great. Running this produces the following HTML DOM structure:
<span>10:28:57 PM</span>
In order to have the clock's time update every second, we need to know when<Clock>
gets mounted to the DOM.If you've used HTML5 Custom Elements, this is similar to theattachedCallback
anddetachedCallback
lifecycle methods. Preact invokes the following lifecycle methods if they are defined for a Component:
Lifecycle method | When it gets called |
---|---|
componentWillMount | before the component gets mounted to the DOM |
componentDidMount | after the component gets mounted to the DOM |
componentWillUnmount | prior to removal from the DOM |
componentWillReceiveProps | before new props get accepted |
shouldComponentUpdate | beforerender() . Returnfalse to skip render |
componentWillUpdate | beforerender() |
componentDidUpdate | afterrender() |
So, we want to have a 1-second timer start once the Component gets added to the DOM, and stop if it is removed. We'll create the timer and store a reference to it incomponentDidMount
, and stop the timer incomponentWillUnmount
. On each timer tick, we'll update the component'sstate
object with a new time value. Doing this will automatically re-render the component.
import{h,render,Component}from'preact';classClockextendsComponent{constructor(){super();// set initial time:this.state={time:Date.now()};}componentDidMount(){// update time every secondthis.timer=setInterval(()=>{this.setState({time:Date.now()});},1000);}componentWillUnmount(){// stop when not renderableclearInterval(this.timer);}render(props,state){lettime=newDate(state.time).toLocaleTimeString();return<span>{time}</span>;}}// render an instance of Clock into <body>:render(<Clock/>,document.body);
Now we havea ticking clock!
The concept (and nomenclature) forprops
andstate
is the same as in React.props
are passed to a component by defining attributes in JSX,state
is internal state. Changing either triggers a re-render, though by default Preact re-renders Components asynchronously forstate
changes and synchronously forprops
changes. You can tell Preact to renderprop
changes asynchronously by settingoptions.syncComponentUpdates
tofalse
.
One area Preact takes a little further than React is in optimizing state changes. A common pattern in ES2015 React code is to use Arrow functions within arender()
method in order to update state in response to events. Creating functions enclosed in a scope on every render is inefficient and forces the garbage collector to do more work than is necessary.
One solution to this is to bind component methods declaratively.Here is an example usingdecko:
classFooextendsComponent{@bindupdateText(e){this.setState({text:e.target.value});}render({},{ text}){return<inputvalue={text}onInput={this.updateText}/>;}}
While this achieves much better runtime performance, it's still a lot of unnecessary code to wire up state to UI.
Fortunately there is a solution, in the form of a module calledlinkstate. CallinglinkState(component, 'text')
returns a function that accepts an Event and uses it's associated value to update the given property in your component's state. Calls tolinkState()
with the same arguments are cached, so there is no performance penalty. Here is the previous example rewritten usingLinked State:
importlinkStatefrom'linkstate';classFooextendsComponent{render({},{ text}){return<inputvalue={text}onInput={linkState(this,'text')}/>;}}
Simple and effective. It handles linking state from any input type, or an optional second parameter can be used to explicitly provide a keypath to the new state value.
Note: In Preact 7 and prior,
linkState()
was built right into Component. In 8.0, it was moved to a separate module. You can restore the 7.x behavior by using linkstate as a polyfill - seethe linkstate docs.
Here is a somewhat verbose Preact<Link>
component:
classLinkextendsComponent{render(props,state){return<ahref={props.href}>{props.children}</a>;}}
Since this is ES6/ES2015, we can further simplify:
classLinkextendsComponent{render({ href, children}){return<a{...{ href, children}}/>;}}// or, for wide-open props support:classLinkextendsComponent{render(props){return<a{...props}/>;}}// or, as a stateless functional component:constLink=({ children, ...props})=>(<a{...props}>{children}</a>);
It is likely that some projects based on Preact would wish to extend Component with great new functionality.
Perhaps automatic connection to stores for a Flux-like architecture, or mixed-in context bindings to make it feel more likeReact.createClass()
. Just use ES2015 inheritance:
classBoundComponentextendsComponent{constructor(props){super(props);this.bind();}bind(){this.binds={};for(letiinthis){this.binds[i]=this[i].bind(this);}}}// example usageclassLinkextendsBoundComponent{click(){open(this.href);}render(){let{ click}=this.binds;return<spanonclick={click}>{children}</span>;}}
The possibilities are pretty endless here. You could even add support for rudimentary mixins:
classMixedComponentextendsComponent{constructor(){super();(this.mixins||[]).forEach(m=>Object.assign(this,m));}}
You can inspect and modify the state of your Preact UI components at runtime using theReact Developer Tools browser extension.
- Install theReact Developer Tools extension
- Import the "preact/devtools" module in your app
- Reload and go to the 'React' tab in the browser's development tools
import{h,Component,render}from'preact';// Enable devtools. You can reduce the size of your app by only including this// module in development builds. eg. In Webpack, wrap this with an `if (module.hot) {...}`// check.require('preact/devtools');
Support us with a monthly donation and help us continue our activities. [Become a backer]
Become a sponsor and get your logo on our README on Github with a link to your site. [Become a sponsor]
MIT
About
⚛️ Fast 3kb React alternative with the same ES6 API. Components & Virtual DOM.
Resources
License
Code of conduct
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Languages
- JavaScript99.5%
- TypeScript0.5%