UNPKG

15.6 kBMarkdownView Raw
1<a href="https://preactjs.com">
2<img alt="Preact" title="Preact" src="https://cdn.rawgit.com/developit/b4416d5c92b743dbaec1e68bc4c27cda/raw/3235dc508f7eb834ebf48418aea212a05df13db1/preact-logo-trans.svg" width="550">
3</a>
4
5**Preact is a fast, `3kB` alternative to React, with the same ES2015 API.**
6
7Preact retains a large amount of compatibility with React, but only the modern ([ES6 Classes] and [stateless functional components](https://facebook.github.io/react/blog/2015/10/07/react-v0.14.html#stateless-functional-components)) interfaces.
8As one would expect coming from React, Components are simple building blocks for composing a User Interface.
9
10### :information_desk_person: Full documentation is available at the [Preact Website ➞](https://preactjs.com)
11
12[![CDNJS](https://img.shields.io/cdnjs/v/preact.svg)](https://cdnjs.com/libraries/preact)
13[![npm](https://img.shields.io/npm/v/preact.svg)](http://npm.im/preact)
14[![travis](https://travis-ci.org/developit/preact.svg?branch=master)](https://travis-ci.org/developit/preact)
15[![gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/developit/preact)
16
17[![Browsers](https://saucelabs.com/browser-matrix/preact.svg)](https://saucelabs.com/u/preact)
18
19
20---
21
22
23## Demos
24
25- [**ESBench**](http://esbench.com) is built using Preact.
26- [**Nectarine.rocks**](http://nectarine.rocks) _([Github Project](https://github.com/developit/nectarine))_ :peach:
27- [**Documentation Viewer**](https://documentation-viewer.firebaseapp.com) _([Github Project](https://github.com/developit/documentation-viewer))_
28- [**TodoMVC**](https://preact-todomvc.surge.sh) _([Github Project](https://github.com/developit/preact-todomvc))_
29- [**Hacker News Minimal**](https://developit.github.io/hn_minimal/) _([Github Project](https://github.com/developit/hn_minimal))_
30- [**Preact Boilerplate**](https://preact-boilerplate.surge.sh) _([Github Project](https://github.com/developit/preact-boilerplate))_ :zap:
31- [**Preact Redux Example**](https://github.com/developit/preact-redux-example) :star:
32- [**Flickr Browser**](http://codepen.io/developit/full/VvMZwK/) (@ CodePen)
33- [**Animating Text**](http://codepen.io/developit/full/LpNOdm/) (@ CodePen)
34- [**60FPS Rainbow Spiral**](http://codepen.io/developit/full/xGoagz/) (@ CodePen)
35- [**Simple Clock**](http://jsfiddle.net/developit/u9m5x0L7/embedded/result,js/) (@ JSFiddle)
36- [**3D + ThreeJS**](http://codepen.io/developit/pen/PPMNjd?editors=0010) (@ CodePen)
37- [**Stock Ticker**](http://codepen.io/developit/pen/wMYoBb?editors=0010) (@ CodePen)
38- [**Create your Own!**](https://jsfiddle.net/developit/rs6zrh5f/embedded/result/) (@ JSFiddle)
39- [**Preact Coffeescript**](https://github.com/crisward/preact-coffee)
40- [**GuriVR**](https://gurivr.com) _([Github Project](https://github.com/opennewslabs/guri-vr))_
41- [**V2EX Preact**](https://github.com/yanni4night/v2ex-preact)
42
43## Libraries & Add-ons
44
45- :raised_hands: [**preact-compat**](https://git.io/preact-compat): use any React library with Preact *([full example](http://git.io/preact-compat-example))*
46- :repeat: [**preact-cycle**](https://git.io/preact-cycle): Functional-reactive paradigm for Preact
47- :page_facing_up: [**preact-render-to-string**](https://git.io/preact-render-to-string): Universal rendering.
48- :earth_americas: [**preact-router**](https://git.io/preact-router): URL routing for your components
49- :bookmark_tabs: [**preact-markup**](https://git.io/preact-markup): Render HTML & Custom Elements as JSX & Components
50- :satellite: [**preact-portal**](https://git.io/preact-portal): Render Preact components into (a) SPACE :milky_way:
51- :pencil: [**preact-richtextarea**](https://git.io/preact-richtextarea): Simple HTML editor component
52- :bookmark: [**preact-token-input**](https://github.com/developit/preact-token-input): Text field that tokenizes input, for things like tags
53- :card_index: [**preact-virtual-list**](https://github.com/developit/preact-virtual-list): Easily render lists with millions of rows ([demo](https://jsfiddle.net/developit/qqan9pdo/))
54- :triangular_ruler: [**preact-layout**](https://download.github.io/preact-layout/): Small and simple layout library
55- :thought_balloon: [**preact-socrates**](https://github.com/matthewmueller/preact-socrates): Preact plugin for [Socrates](http://github.com/matthewmueller/socrates)
56- :rowboat: [**preact-flyd**](https://github.com/xialvjun/preact-flyd): Use [flyd](https://github.com/paldepind/flyd) FRP streams in Preact + JSX
57- :speech_balloon: [**preact-i18nline**](https://github.com/download/preact-i18nline): Integrates the ecosystem around [i18n-js](https://github.com/everydayhero/i18n-js) with Preact via [i18nline](https://github.com/download/i18nline).
58- :white_square_button: [**preact-mdl**](https://git.io/preact-mdl): Use [MDL](https://getmdl.io) as Preact components
59- :rocket: [**preact-photon**](https://git.io/preact-photon): build beautiful desktop UI with [photon](http://photonkit.com)
60- :microscope: [**preact-jsx-chai**](https://git.io/preact-jsx-chai): JSX assertion testing _(no DOM, right in Node)_
61- :tophat: [**preact-classless-component**](https://github.com/ld0rman/preact-classless-component): create preact components without the class keyword
62- :hammer: [**preact-hyperscript**](https://github.com/queckezz/preact-hyperscript): Hyperscript-like syntax for creating elements
63- :white_check_mark: [**shallow-compare**](https://github.com/tkh44/shallow-compare): simplified `shouldComponentUpdate` helper.
64
65
66## Getting Started
67
68> :information_desk_person: You [don't _have_ to use ES2015 to use Preact](https://github.com/developit/preact-without-babel)... but you should.
69
70The following guide assumes you have some sort of ES2015 build set up using babel and/or webpack/browserify/gulp/grunt/etc. If you don't, start with [preact-boilerplate] or a [CodePen Template](http://codepen.io/developit/pen/pgaROe?editors=0010).
71
72
73### Import what you need
74
75The `preact` 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:
76
77##### Named:
78
79```js
80import { h, render, Component } from 'preact';
81
82// Tell Babel to transform JSX into h() calls:
83/** @jsx h */
84```
85
86##### Default:
87
88```js
89import preact from 'preact';
90
91// Tell Babel to transform JSX into preact.h() calls:
92/** @jsx preact.h */
93```
94
95> 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.
96>
97> Instead of declaring the `@jsx` pragma in your code, it's best to configure it globally in a `.babelrc`:
98>
99> **For Babel 5 and prior:**
100>
101> ```json
102> { "jsxPragma": "h" }
103> ```
104>
105> **For Babel 6:**
106>
107> ```json
108> {
109> "plugins": [
110> ["transform-react-jsx", { "pragma":"h" }]
111> ]
112> }
113> ```
114
115
116### Rendering JSX
117
118Out of the box, Preact provides an `h()` function that turns your JSX into Virtual DOM elements _([here's how](http://jasonformat.com/wtf-is-jsx))_. It also provides a `render()` function that creates a DOM tree from that Virtual DOM.
119
120To render some JSX, just import those two functions and use them like so:
121
122```js
123import { h, render } from 'preact';
124
125render((
126 <div id="foo">
127 <span>Hello, world!</span>
128 <button onClick={ e => alert("hi!") }>Click Me</button>
129 </div>
130), document.body);
131```
132
133This should seem pretty straightforward if you've used [hyperscript] or one of its many friends.
134
135Rendering 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. :star2:
136
137
138### Components
139
140Preact exports a generic `Component` class, which can be extended to build encapsulated, self-updating pieces of a User Interface. Components support all of the standard React [lifecycle methods], like `shouldComponentUpdate()` and `componentWillReceiveProps()`. Providing specific implementations of these methods is the preferred mechanism for controlling _when_ and _how_ components update.
141
142Components also have a `render()` method, but unlike React this method is passed `(props, state)` as arguments. This provides an ergonomic means to destructure `props` and `state` into local variables to be referenced from JSX.
143
144Let's take a look at a very simple `Clock` component, which shows the current time.
145
146```js
147import { h, render, Component } from 'preact';
148
149class Clock extends Component {
150 render() {
151 let time = new Date().toLocaleTimeString();
152 return <span>{ time }</span>;
153 }
154}
155
156// render an instance of Clock into <body>:
157render(<Clock />, document.body);
158```
159
160
161That's great. Running this produces the following HTML DOM structure:
162
163```html
164<span>10:28:57 PM</span>
165```
166
167In 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 the `attachedCallback` and `detachedCallback` lifecycle methods._ Preact invokes the following lifecycle methods if they are defined for a Component:
168
169| Lifecycle method | When it gets called |
170|-----------------------------|--------------------------------------------------|
171| `componentWillMount` | before the component gets mounted to the DOM |
172| `componentDidMount` | after the component gets mounted to the DOM |
173| `componentWillUnmount` | prior to removal from the DOM |
174| `componentDidUnmount` | after removal from the DOM |
175| `componentWillReceiveProps` | before new props get accepted |
176| `shouldComponentUpdate` | before `render()`. Return `false` to skip render |
177| `componentWillUpdate` | before `render()` |
178| `componentDidUpdate` | after `render()` |
179
180
181
182So, 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 in `componentDidMount`, and stop the timer in `componentWillUnmount`. On each timer tick, we'll update the component's `state` object with a new time value. Doing this will automatically re-render the component.
183
184```js
185import { h, render, Component } from 'preact';
186
187class Clock extends Component {
188 constructor() {
189 super();
190 // set initial time:
191 this.state.time = Date.now();
192 }
193
194 componentDidMount() {
195 // update time every second
196 this.timer = setInterval(() => {
197 this.setState({ time: Date.now() });
198 }, 1000);
199 }
200
201 componentWillUnmount() {
202 // stop when not renderable
203 clearInterval(this.timer);
204 }
205
206 render(props, state) {
207 let time = new Date(state.time).toLocaleTimeString();
208 return <span>{ time }</span>;
209 }
210}
211
212// render an instance of Clock into <body>:
213render(<Clock />, document.body);
214```
215
216Now we have [a ticking clock](http://jsfiddle.net/developit/u9m5x0L7/embedded/result,js/)!
217
218
219### Props & State
220
221The concept (and nomenclature) for `props` and `state` 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 for `state` changes and synchronously for `props` changes. You can tell Preact to render `prop` changes asynchronously by setting `options.syncComponentUpdates` to `false`.
222
223
224---
225
226
227## Linked State
228
229One 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 a `render()` 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.
230
231One solution to this is to bind component methods declaratively.
232Here is an example using [decko](http://git.io/decko):
233
234```js
235class Foo extends Component {
236 @bind
237 updateText(e) {
238 this.setState({ text: e.target.value });
239 }
240 render({ }, { text }) {
241 return <input value={text} onInput={this.updateText} />;
242 }
243}
244```
245
246While this achieves much better runtime performance, it's still a lot of unnecessary code to wire up state to UI.
247
248Fortunately there is a solution, in the form of `linkState()`. Calling `component.linkState('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 to linkState() with the same state property are cached, so there is no performance penalty. Here is the previous example rewritten using _Linked State_:
249
250```js
251class Foo extends Component {
252 render({ }, { text }) {
253 return <input value={text} onInput={this.linkState('text')} />;
254 }
255}
256```
257
258Simple 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.
259
260
261## Examples
262
263Here is a somewhat verbose Preact `<Link>` component:
264
265```js
266class Link extends Component {
267 render(props, state) {
268 return <a href={ props.href }>{ props.children }</a>;
269 }
270}
271```
272
273Since this is ES6/ES2015, we can further simplify:
274
275```js
276class Link extends Component {
277 render({ href, children }) {
278 return <a {...{ href, children }} />;
279 }
280}
281
282// or, for wide-open props support:
283class Link extends Component {
284 render(props) {
285 return <a {...props} />;
286 }
287}
288
289// or, as a stateless functional component:
290const Link = ({ children, ...props }) => (
291 <a {...props}>{ children }</a>
292);
293```
294
295
296## Extensions
297
298It is likely that some projects based on Preact would wish to extend Component with great new functionality.
299
300Perhaps automatic connection to stores for a Flux-like architecture, or mixed-in context bindings to make it feel more like `React.createClass()`. Just use ES2015 inheritance:
301
302```js
303class BoundComponent extends Component {
304 constructor(props) {
305 super(props);
306 this.bind();
307 }
308 bind() {
309 this.binds = {};
310 for (let i in this) {
311 this.binds[i] = this[i].bind(this);
312 }
313 }
314}
315
316// example usage
317class Link extends BoundComponent {
318 click() {
319 open(this.href);
320 }
321 render() {
322 let { click } = this.binds;
323 return <span onclick={ click }>{ children }</span>;
324 }
325}
326```
327
328
329The possibilities are pretty endless here. You could even add support for rudimentary mixins:
330
331```js
332class MixedComponent extends Component {
333 constructor() {
334 super();
335 (this.mixins || []).forEach( m => Object.assign(this, m) );
336 }
337}
338```
339
340## Developer Tools
341
342You can inspect and modify the state of your Preact UI components at runtime using the
343[React Developer Tools](https://github.com/facebook/react-devtools) browser extension.
344
3451. Install the [React Developer Tools](https://github.com/facebook/react-devtools) extension
3462. Import the "preact/devtools" module in your app
3473. Reload and go to the 'React' tab in the browser's development tools
348
349
350```js
351import { h, Component, render } from 'preact';
352
353// Enable devtools. You can reduce the size of your app by only including this
354// module in development builds. eg. In Webpack, wrap this with an `if (module.hot) {...}`
355// check.
356require('preact/devtools');
357```
358
359## License
360
361MIT
362
363
364
365[![Preact](http://i.imgur.com/YqCHvEW.gif)](https://preactjs.com)
366
367
368
369[ES6 Classes]: https://facebook.github.io/react/docs/reusable-components.html#es6-classes
370[hyperscript]: https://github.com/dominictarr/hyperscript
371[preact-boilerplate]: https://github.com/developit/preact-boilerplate
372[lifecycle methods]: https://facebook.github.io/react/docs/component-specs.html