gibbon.js
Flexible JavaScript framework.
Introduction
In application frameworks state management is used to instantiate and destroy a collection of components and services. Many frameworks go further than this to enforce patterns for how you manage data, write components, declare your routing etc.
Gibbon only provides a framework for state management.
Quick Start
var gibbon = new Gibbon()
class Header{
constructor(){
this.handle = document.createElement(`div`)
this.handle.id = `header`
document.body.appendChild(this.handle)
}
}
class About{
constructor(){
this.handle = document.createElement(`div`)
this.handle.id = `about`
this.handle.innerHTML = `<h1>Swing like noboby is watching.</h1>`
document.body.appendChild(this.handle)
}
}
gibbon.define('app', [ Header ])
gibbon.define('app.home', [ About ])
gibbon.go('app.home')
API
gibbon.define(name, components)
Defines a new state that can be instantiated.
Arguments
name <String>
The name
argument is used to define a state. Compose child states using .
as a separator.
components <Array>
The components
argument is used to configure a state with an array of Component.
Example
gibbon.define('app', [ Header ])
gibbon.define('app.home', [ About ])
gibbon.go(name)
Instantiates a defined state.
name <String>
The name
argument is used to define a state.
Component
A component is a JavaScript Class.
component.resolved <Bool>
The resolved
property is used to indicate a component is asynchronous.
The State Lifecycle will wait to destroy components with a property resolved
until it's set to true
.
component.destroy <Function>
The destroy
function is executed at the end of a State Lifecycle.
Useful for cleaning up things like event listeners and intervals.
Example
class Movies{
constructor(){
this.resolved = false
this.init()
}
async init(){
await this.getMovies()
this.createHandle()
this.updateMovies()
this.createMoviesWorker()
this.resolved = true
}
createHandle(){
this.handle = document.createElement('div')
this.handle.id = 'movies'
document.body.appendChild(this.handle)
}
updateMovies(){
this.handle.innerHTML = `<pre>${JSON.stringify(this.movies)}</pre>`
}
createMoviesWorker(){
this.moviesWorker = setInterval(async () => {
await this.getMovies()
this.updateMovies()
}, 10000)
}
getMovies(){
this.movies = await fetch('http://example.com/movies.json')
}
destroy(){
clearInterval(this.moviesWorker)
}
}
State Lifecycle
When a state is instansiated is constructs each Component from the components array.
States and their components are automatically destroyed after each transition to the next state.
Example
gibbon.define('app', [ Header ])
gibbon.define('app.home', [ About ])
gibbon.define('app.contact', [ EmailForm ])
gibbon.go('app.home')
gibbon.go('app.contact')
This includes top level state trees.
Example
gibbon.define('app1', [ Header1 ])
gibbon.define('app1.home', [ About2 ])
gibbon.define('app2', [ Header1 ])
gibbon.define('app2.home', [ About2 ])
gibbon.go('app1.home')
gibbon.go('app2.home')
The same state can be instansiated multiple times in parallel. This is useful when one instance of a state is waiting to be destroyed while another is being created. For example, when a user toggles back and forth between the same pages that have asynchronous dependencies.
Example
gibbon.define('app', [ Header ])
gibbon.define('app.home', [ About ])
gibbon.define('app.movies', [ Movies ])
gibbon.go('app.home')
gibbon.go('app.movies')
gibbon.go('app.home')
gibbon.go('app.movies')
Events
stateChange
Emits the <State>
object that has fully resolved.
License
MIT
Copyright (c) 2019-present, Daniel Kanze