UNPKG

14.5 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- :earth_americas: [**preact-router**](https://git.io/preact-router): URL routing for your components.
46- :page_facing_up: [**preact-render-to-string**](https://git.io/preact-render-to-string): Universal rendering.
47- :raised_hands: [**preact-compat**](https://git.io/preact-compat): use any React library with Preact. *([full example](http://git.io/preact-compat-example))*
48- :rocket: [**preact-photon**](https://git.io/preact-photon): build beautiful desktop UI with [photon](http://photonkit.com).
49- :microscope: [**preact-jsx-chai**](https://git.io/preact-jsx-chai): JSX assertion testing _(no DOM, right in Node)_
50- :bookmark_tabs: [**preact-markup**](https://git.io/preact-markup): Render HTML & Custom Elements as JSX & Components
51- :pencil: [**preact-richtextarea**](https://git.io/preact-richtextarea): Simple HTML editor component
52- :repeat: [**preact-cycle**](https://git.io/preact-cycle): Functional-reactive paradigm for Preact.
53- :satellite: [**preact-portal**](https://git.io/preact-portal): Render Preact components into (a) SPACE :milky_way:
54- :construction: [**preact-classless-component**](https://github.com/ld0rman/preact-classless-component): A utility method to create components without the `class` keyword
55- :hammer: [**preact-hyperscript**](https://github.com/queckezz/preact-hyperscript): Hyperscript-like syntax for creating elements
56- :triangular_ruler: [**preact-layout**](https://download.github.io/preact-layout/): Small and simple layout library
57
58
59## Getting Started
60
61> :information_desk_person: You [don't _have_ to use ES2015 to use Preact](https://github.com/developit/preact-without-babel)... but you should.
62
63The 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).
64
65
66### Import what you need
67
68The `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:
69
70##### Named:
71
72```js
73import { h, render, Component } from 'preact';
74
75// Tell Babel to transform JSX into h() calls:
76/** @jsx h */
77```
78
79##### Default:
80
81```js
82import preact from 'preact';
83
84// Tell Babel to transform JSX into preact.h() calls:
85/** @jsx preact.h */
86```
87
88> 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.
89>
90> Instead of declaring the `@jsx` pragma in your code, it's best to configure it globally in a `.babelrc`:
91>
92> **For Babel 5 and prior:**
93>
94> ```json
95> { "jsxPragma": "h" }
96> ```
97>
98> **For Babel 6:**
99>
100> ```json
101> {
102> "plugins": [
103> ["transform-react-jsx", { "pragma":"h" }]
104> ]
105> }
106> ```
107
108
109### Rendering JSX
110
111Out 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.
112
113To render some JSX, just import those two functions and use them like so:
114
115```js
116import { h, render } from 'preact';
117
118render((
119 <div id="foo">
120 <span>Hello, world!</span>
121 <button onClick={ e => alert("hi!") }>Click Me</button>
122 </div>
123), document.body);
124```
125
126This should seem pretty straightforward if you've used [hyperscript] or one of its many friends.
127
128Rendering 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:
129
130
131### Components
132
133Preact 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.
134
135Components 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.
136
137Let's take a look at a very simple `Clock` component, which shows the current time.
138
139```js
140import { h, render, Component } from 'preact';
141
142class Clock extends Component {
143 render() {
144 let time = new Date().toLocaleTimeString();
145 return <span>{ time }</span>;
146 }
147}
148
149// render an instance of Clock into <body>:
150render(<Clock />, document.body);
151```
152
153
154That's great. Running this produces the following HTML DOM structure:
155
156```html
157<span>10:28:57 PM</span>
158```
159
160In 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:
161
162| Lifecycle method | When it gets called |
163|-----------------------------|--------------------------------------------------|
164| `componentWillMount` | before the component gets mounted to the DOM |
165| `componentDidMount` | after the component gets mounted to the DOM |
166| `componentWillUnmount` | prior to removal from the DOM |
167| `componentDidUnmount` | after removal from the DOM |
168| `componentWillReceiveProps` | before new props get accepted |
169| `shouldComponentUpdate` | before `render()`. Return `false` to skip render |
170| `componentWillUpdate` | before `render()` |
171| `componentDidUpdate` | after `render()` |
172
173
174
175So, 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.
176
177```js
178import { h, render, Component } from 'preact';
179
180class Clock extends Component {
181 constructor() {
182 super();
183 // set initial time:
184 this.state.time = Date.now();
185 }
186
187 componentDidMount() {
188 // update time every second
189 this.timer = setInterval(() => {
190 this.setState({ time: Date.now() });
191 }, 1000);
192 }
193
194 componentWillUnmount() {
195 // stop when not renderable
196 clearInterval(this.timer);
197 }
198
199 render(props, state) {
200 let time = new Date(state.time).toLocaleTimeString();
201 return <span>{ time }</span>;
202 }
203}
204
205// render an instance of Clock into <body>:
206render(<Clock />, document.body);
207```
208
209Now we have [a ticking clock](http://jsfiddle.net/developit/u9m5x0L7/embedded/result,js/)!
210
211
212### Props & State
213
214The 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`.
215
216
217---
218
219
220## Linked State
221
222One 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.
223
224One solution to this is to bind component methods declaratively.
225Here is an example using [decko](http://git.io/decko):
226
227```js
228class Foo extends Component {
229 @bind
230 updateText(e) {
231 this.setState({ text: e.target.value });
232 }
233 render({ }, { text }) {
234 return <input value={text} onInput={this.updateText} />;
235 }
236}
237```
238
239While this achieves much better runtime performance, it's still a lot of unnecessary code to wire up state to UI.
240
241Fortunately 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_:
242
243```js
244class Foo extends Component {
245 render({ }, { text }) {
246 return <input value={text} onInput={this.linkState('text')} />;
247 }
248}
249```
250
251Simple 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.
252
253
254## Examples
255
256Here is a somewhat verbose Preact `<Link>` component:
257
258```js
259class Link extends Component {
260 render(props, state) {
261 return <a href={ props.href }>{ props.children }</a>;
262 }
263}
264```
265
266Since this is ES6/ES2015, we can further simplify:
267
268```js
269class Link extends Component {
270 render({ href, children }) {
271 return <a {...{ href, children }} />;
272 }
273}
274
275// or, for wide-open props support:
276class Link extends Component {
277 render(props) {
278 return <a {...props} />;
279 }
280}
281
282// or, as a stateless functional component:
283const Link = ({ children, ...props }) => (
284 <a {...props}>{ children }</a>
285);
286```
287
288
289## Extensions
290
291It is likely that some projects based on Preact would wish to extend Component with great new functionality.
292
293Perhaps 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:
294
295```js
296class BoundComponent extends Component {
297 constructor(props) {
298 super(props);
299 this.bind();
300 }
301 bind() {
302 this.binds = {};
303 for (let i in this) {
304 this.binds[i] = this[i].bind(this);
305 }
306 }
307}
308
309// example usage
310class Link extends BoundComponent {
311 click() {
312 open(this.href);
313 }
314 render() {
315 let { click } = this.binds;
316 return <span onclick={ click }>{ children }</span>;
317 }
318}
319```
320
321
322The possibilities are pretty endless here. You could even add support for rudimentary mixins:
323
324```js
325class MixedComponent extends Component {
326 constructor() {
327 super();
328 (this.mixins || []).forEach( m => Object.assign(this, m) );
329 }
330}
331```
332
333## Developer Tools
334
335You can inspect and modify the state of your Preact UI components at runtime using the
336[React Developer Tools](https://github.com/facebook/react-devtools) browser extension.
337
3381. Install the [React Developer Tools](https://github.com/facebook/react-devtools) extension
3392. Import the "preact/devtools" module in your app
3403. Reload and go to the 'React' tab in the browser's development tools
341
342
343```js
344import { h, Component, render } from 'preact';
345
346// Enable devtools. You can reduce the size of your app by only including this
347// module in development builds. eg. In Webpack, wrap this with an `if (module.hot) {...}`
348// check.
349require('preact/devtools');
350```
351
352## License
353
354MIT
355
356
357
358[![Preact](http://i.imgur.com/YqCHvEW.gif)](https://preactjs.com)
359
360
361
362[ES6 Classes]: https://facebook.github.io/react/docs/reusable-components.html#es6-classes
363[hyperscript]: https://github.com/dominictarr/hyperscript
364[preact-boilerplate]: https://github.com/developit/preact-boilerplate
365[lifecycle methods]: https://facebook.github.io/react/docs/component-specs.html