@ddlab/renderer
v0.1.0
Published
A tool to build user interfaces with javascript (or typescript) in a declarative fashion.
Readme
@ddlab/renderer
npm i @ddlab/renderer
This lib was written for educational purposes only. Not recommended for production use.
A tool to build user interfaces with javascript (or typescript) in a declarative fashion.
Features:
- Typescript declarations
- JSX support
- uses virtual DOM (no unecessary DOM updates, etc.)
- component state management (
withState()) - simple hash router (
withRoutes())
Usage
Getting Started
The very basic example:
import {h, bootstrap} from '@ddlab/renderer';
const MyComponent = () => h.div([
h.h1('Welcome'),
h.p('to the party')
]);
bootstrap(document.body, MyComponent);The same example in JSX (see JSX setup section):
import {h, bootstrap} from '@ddlab/renderer';
const MyComponent = () => (
<div>
<h1>Welcome</h1>
<p>to the party</p>
</div>
);
bootstrap(document.body, MyComponent);Bootstrapping
Bootstrap the RootComponent to an element using bootstrap(element, RootComponent) function. E.g.:
import {h, bootstrap} from '@ddlab/renderer';
const Home = () => h.div('Hello world!');
bootstrap(document.body, Home);Components
Abstract out your app's UI elements to components and compose out of it. E.g.:
import {h, bootstrap} from '@ddlab/renderer';
const Header = () => h.h1('Welcome');
const Content = () => h.div('This is content.');
const Home = () => h.div([Header(), Content()]);
bootstrap(document.body, Home);Attributes
The first argument accepts the attributes object, i.e. h.div(attributes, 'content...'). E.g.:
const style = {color: 'white', backgroundColor: 'blue'}; // *
h.div({class: 'content', style}, 'content...');* camelCase keys in style object will be converted to kebab-case during rendering.
DOM Events
h.div({
onClick: e => console.log(e),
onKeypress: e => alert(e.key),
// ... any other event
}, 'content...')Hooks
There are few component specific events (hooks):
onCreate()- called on component creationonRemove()- called on component removalonUpdate()- called on props/contents updateshouldUpdate(newConfig, oldConfig)- when it returnsfalse, it prevents the component from being rerendered E.g.:h.div({onCreate: () => console.log('hello world!')}, 'content...')
Dynamic Content (using props)
const Counter = (props) => h.div(`#${props.count} visits.`);
const Home = () => h.div([
Counter({count: 99})
]);State Management (using withState())
const StatefulComponent = withState(Component) - withState is a hoc which wraps a Component in a returned StatefulComponent.
Wrapping a Component with setState(Component) adds state and setState to the Component's props. Calling setState(changes) updates the state object and rerenders the Component. E.g.:
import {h, withState} from '@ddlab/renderer';
const StatefulCounter = () => withState(p => h.div([
h.div(`#${p.state.count} clicks.`),
h.button({
onClick: () => p.setState(p.state.count + 1)
}, 'Click me')
]));Router (using withRoutes())
withRoutes() is a hoc which passes different children for different location hashes to a target component. Example of router configuration:
import {h, withRoutes} from '@ddlab/renderer';
const Home = () => h.div('Home page');
const About = () => h.div('About page');
const RootComponent = withRoutes(h.div, {
'home': Home,
'about': About
});Now setting hash in address bar to '#home' loads Home component & About component for '#about'.
Force rerender
Examine withState & withRoutes source to see how it works.
Type Safety
Use built-in TComponent<TProps> type, e.g.:
import {h, TComponent} from '@ddlab/renderer';
interface ICounterProps {count: number};
const Counter: TComponent<ICounterProps> = (props) =>
h.p(`#${props.count} visits.`);JSX Setup
Set jsx factory function to 'h'. It is still important to import the h function in your jsx/tsx files.
Example tsconfig:
"compilerOptions": {
"jsx": "react",
"jsxFactory": "h"
}Known Issues
withState()uses the same state object for all instances.
