Skip to content

Commit 65d124b

Browse files
tornqvistyoshuawuyts
authored andcommitted
Add documentation on components (#673)
* Add documentation on components * Fix typo
1 parent 0650e64 commit 65d124b

File tree

1 file changed

+100
-0
lines changed

1 file changed

+100
-0
lines changed

README.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
- [State](#state)
9494
- [Routing](#routing)
9595
- [Server Rendering](#server-rendering)
96+
- [Components](#components)
9697
- [Optimizations](#optimizations)
9798
- [FAQ](#faq)
9899
- [API](#api)
@@ -256,6 +257,13 @@ The current name of the route used in the router (e.g. `/foo/:bar`).
256257
### `state.title`
257258
The current page title. Can be set using the `DOMTitleChange` event.
258259

260+
### `state.components`
261+
An object _recommended_ to use for local component state.
262+
263+
### `state.cache(Component, id, [...args])`
264+
Generic class cache. Will lookup Component instance by id and create one if not
265+
found. Usefull for working with statefull [components](#components).
266+
259267
## Routing
260268
Choo is an application level framework. This means that it takes care of
261269
everything related to routing and pathnames for you.
@@ -340,6 +348,93 @@ the `window` object.
340348
</html>
341349
```
342350

351+
## Components
352+
From time to time there will arise a need to have an element in an application
353+
hold a self-contained state or to not rerender when the application does. This
354+
is common when using 3rd party libraries to e.g. display an interactive map or a
355+
graph and you rely on this 3rd party library to handle modifications to the DOM.
356+
Components come baked in to Choo for these kinds of situations. See
357+
[nanocomponent][nanocomponent] for documentation on the component class.
358+
359+
```javascript
360+
// map.js
361+
var html = require('choo/html')
362+
var mapboxgl = require('mapbox-gl')
363+
var Component = require('choo/component')
364+
365+
module.exports = class Button extends Component {
366+
constructor (id, state, emit) {
367+
super(id)
368+
this.local = state.components[id] = {}
369+
}
370+
371+
load (element) {
372+
this.map = new mapboxgl.Map({
373+
container: element,
374+
center: this.local.center
375+
})
376+
}
377+
378+
update (center) {
379+
if (center.join() !== this.local.center.join()) {
380+
this.map.setCenter(center)
381+
}
382+
return false
383+
}
384+
385+
createElement (center) {
386+
this.local.center = center
387+
return html`<div></div>`
388+
}
389+
}
390+
```
391+
392+
```javascript
393+
// index.js
394+
var choo = require('choo')
395+
var html = require('choo/html')
396+
var Map = require('./map.js')
397+
398+
var app = choo()
399+
app.route('/', mainView)
400+
app.mount('body')
401+
402+
function mainView (state, emit) {
403+
return html`
404+
<body>
405+
<button onclick=${onclick}>Where am i?</button>
406+
${state.cache(Map, 'my-map').render(state.center)}
407+
</body>
408+
`
409+
410+
function onclick () {
411+
emit('locate')
412+
}
413+
}
414+
415+
app.use(function (state, emitter) {
416+
state.center = [18.0704503, 59.3244897]
417+
emitter.on('locate', function () {
418+
window.navigator.geolocation.getCurrentPosition(function (position) {
419+
state.center = [position.coords.longitude, position.coords.latitude]
420+
emitter.emit('render')
421+
})
422+
})
423+
})
424+
```
425+
426+
### Caching components
427+
When working with stateful components, one will need to keep track of component
428+
instances – `state.cache` does just that. The component cache is a function
429+
which takes a component class and a unique id (`string`) as it's first two
430+
arguments. Any following arguments will be forwarded to the component contructor
431+
together with `state` and `emit`.
432+
433+
The default class cache is an LRU cache (using [nanolru][nanolru]), meaning it
434+
will only hold on to a fixed amount of class instances (`100` by default) before
435+
starting to evict the least-recently-used instances. This behavior can be
436+
overriden with [options](#app--chooopts).
437+
343438
## Optimizations
344439
Choo is reasonably fast out of the box. But sometimes you might hit a scenario
345440
where a particular part of the UI slows down the application, and you want to
@@ -434,6 +529,9 @@ Initialize a new `choo` instance. `opts` can also contain the following values:
434529
history API.
435530
- __opts.href:__ default: `true`. Handle all relative `<a
436531
href="<location>"></a>` clicks and call `emit('render')`
532+
- __opts.cache:__ default: `undefined`. Override default class cache used by
533+
`state.cache`. Can be a a `number` (maximum number of instances in cache,
534+
default `100`) or an `object` with a [nanolru][nanolru]-compatible API.
437535

438536
### `app.use(callback(state, emitter, app))`
439537
Call a function and pass it a `state`, `emitter` and `app`. `emitter` is an instance
@@ -583,6 +681,8 @@ Become a backer, and buy us a coffee (or perhaps lunch?) every month or so.
583681
## License
584682
[MIT](https://tldrlegal.com/license/mit-license)
585683

684+
[nanocomponent]: https://github.com/choojs/nanocomponent
685+
[nanolru]: https://github.com/s3ththompson/nanolru
586686
[bankai]: https://github.com/choojs/bankai
587687
[bel]: https://github.com/shama/bel
588688
[nanohtml]: https://github.com/choojs/nanohtml

0 commit comments

Comments
 (0)