Gia
Minimalistic JavaScript library for managing component lifecycle with server rendered websites.
Install / Use
/learn @giantcz/GiaREADME
Gia
Minimalistic JavaScript framework for server rendered websites.
2.68 Kb minified gzipped with all it’s parts loaded with a script tag.
Gia is modular in it’s nature. Following is the table of module sizes.
| 4.88 Kb | Component (with code splitting support) | | ----------- | --------------------------------------- | | 1.80 Kb | BaseComponent | | 1.62 Kb | eventbus | | 1.39 Kb | loadComponents | | 1.26 Kb | removeComponents | | 0.88 Kb | destroyInstance | | 0.79 Kb | createInstance | | 0.69 Kb | config | | 0.56 Kb | getComponentFromElement |
Following sizes are for modules included separately (bundled separately). Modules often include common code, so when included and bundled together, final sizes are smaller and don't just add up.
- loadComponents
- removeComponents
- createInstances
- destroyInstances
- getComponentFromElement
- config
- eventbus
Installation
Include Gia with scripts tag
<script src="./dist/gia.min.js"></script>
<!-- exposes all modules under global gia object -->
<!-- also possible to include only parts -->
<script src="./dist/BaseComponent.min.js"></script>
<script src="./dist/loadComponents.min.js"></script>
or with npm and import
npm install gia --save
// import needed modules from npm
import Component from 'gia/Component';
import loadComponents from 'gia/loadComponents';
Usage
First, a component needs to be created.
class SampleComponent extends Component {
mount() {
console.log("Hello world!");
}
}
Define the element where the component needs to be attached:
<div g-component="SampleComponent">
...
</div>
And let the magic begin.
const components = {
"SampleComponent": SampleComponent
}
loadComponents(components);
This simple setup will give you component with a simple lifecycle, scoped to the DOM element, plus some other super powers!
Component
Component is the building stone of Gia architecture. Gia only works with your HTML through components. To create new component, extend Gia default Component, or modified Gia component. If you’re really trying to go for minimal size and code splitting is not going to be needed, it is also possible to use BaseComponent, which does not include polyfills needed for code splitting.
import Component from 'gia/Component';
class SampleComponent extends Component {
mount() {
console.log("Hello world!");
}
}
Variables
There are several variables available in component by default.
element
Variable holding the root element of the component.
this.element; // DOM element
ref
Variable holding object with all the elements marked with g-ref attribute within the root element, where the contents of the attribute is used as ref name. By setting the ref variable, component gets a signal to look for the elements available within the root element of component. So this..
<div g-component="SampleComponent">
<div g-ref="singleRef">
<div g-ref="multipleRefs">
<div g-ref="multipleRefs">
</div>
constructor(element) {
super(element);
this.ref = {
singleRef: null, // looks for single element
multipleRefs: [], // looks for multiple element
}
}
…will end up in following value of the ref variable.
console.log(this.ref);
// { "multipleRefs": [DOM element, DOM element], "singleRef": DOM element }
In case an empty object is set, component will look for any elements available and assume for all to be multiple (store in array).
constructor(element) {
super(element);
this.ref = {};
console.log(this.ref);
// { "multipleRefs": [DOM element, DOM element], singleRef: [ DOM element ] }
}
In case some components are overlapping, but you would still like to use a same names for the ref elements, it is also possible to define the component for which the element is intended for inside of g-ref attribute.
<div g-component="SampleComponent">
<div g-component="AnotherComponent">
<div g-ref="SampleComponent:refElement">
</div>
</div>
The refElement will only be selected and stored by SampleComponent, and no others.
options
Variable holding options of the component. Default options can be set in constructor of the component. Options get automatically rewritten from the g-options attribute.
<div g-component="SampleComponent" g-options='{"someOption": "customValue"}'>
constructor(element) {
super(element);
this.options = {
someOptions: "defaultValue"
};
console.log(this.options); // {someOption: "customValue"}
}
state
Variable holding state of the component. It is not necessary to use state at all, as components are not used to actually render HTML. However, in combination with setState and stateChange methods, state can be useful for certain components, like some sort of filter where simple state can be helpful. Another use case is component which often updates DOM, as by using setState and stateChange methods, modifications of DOM are made only when the state actually changed. State should only be changed by setState function and takes a form of object.
console.log(this.state); // {}
Methods
Component has a set of methods that can be used through it's lifecycle.
require
Method used for code splitting to require any libraries needed for the component to work. This method is asynchronous and after it is resolved, the execution of mount method follows.
async require() {
this.throttle = await import('lodash/throttle');
}
mount
Method called after all assets are loaded - if any defined (after require method is resolved). This is where you would add all your listeners and such...
mount() {
this.scrollHandler = this.handleScroll.bind(this);
this.element.addEventListener('click', this.handleClick.bind(this));
window.addEventListener('scroll', this.scrollHandler);
}
unmount
Method called before the component is destroyed (on removeComponents call).
This is where you would remove any global listeners.
Note that any listeners attached on or within the component root element are removed when the element is removed from DOM, as the component instance is stored within the element, so there is no need to remove those listeners, in case the element is removed from DOM.
unmount() {
this.element.removeEventListener('click', this.handleClick); // mostly not needed
window.removeEventListener('scroll', this.scrollHandler);
}
setState
Method called to update state of the component. Only the changes of state are required to be passed in a form of object. Component will merge the changes with current state on it's own.
this.setState({
a: "a"
});
Note that it is recommended to only use simple state with one layer for the state to work correctly. State is here to allow some simple manipulation powered with state, not to store a complex state of whole application.
this.setState({
a: "a",
b: ["a"],
c: {a: "a"}
}); // all fine
this.setState({
a: {
b: {c: "c"}
}
}); // not recommended
stateChange
This function gets called by setState method and any changes to state are passed as an argument. Ideally, any manipulation with DOM would be done within this function, as only the actual changes to state are passed on to here in a form of object.
stateChange(stateChanges) {
if('a' in stateChanges) {
// "a" property of state was updated
}
console.log(stateChanges, this.state);
}
this.setState({ a: "a", b: "b" }); // { a: "a", b: "b" } { a: "a", b: "b" }
this.setState({ a: "a", b: "c" }); // { b: "c" } { a: "a", b: "c" }
this.setState({ b: "d" }); // { b: "d" } { a: "a", b: "d" }
Helpers
loadComponents
Initialises components within defined scope. In case an instance of the component already exists on the element, function skips initialisation. That means loadComponents can be always called without a context, but context should be defined for best performance.
import loadComponents from 'gia/loadComponents';
const components = {
"SampleComponent": SampleComponent,
}
loadComponents(components [, context]); // context is optional and defaults to document.documentElement
removeComponents
Calls destroy method on every component within the context and removes component instance from the element.
import removeComponents from 'gia/removeComponents';
removeComponents([context]); // context is optional and defaults to document.documentElement
createInstances
Creates and returns instance of component. This function is used by loadComponents, but can be helpful in case of manually creating component instances. Classic use case would be using a set of components with one parent component controlling the others.
import createInstance from 'gia/createInstance';
let instance = createInstance(element, componentName, component[, options]);
// options are optional and are passed into component contructor as second argument
instance._load(); // this is necessary
Note that calling instance._load() is required to start the lifecycle o
