0.4.5 • Published 11 months ago

express-react-vanilla-adapter v0.4.5

Weekly downloads
-
License
MPL-2.0
Repository
github
Last release
11 months ago

React-vanilla as express template adapter

This package compiles react-vanilla jsx as templates for express.

Get all profits from react-vanilla DOM h function that is fully compatible with react h function.

Usage

Basic server example is presented in example folder.

Here is server.js file contents:

var express = require("express");
var { ExpressAdapter } = require('express-react-vanilla-adapter');

var path = require("path");

const app = express();

// Create `ExpressAdapter` and pass `app` for setting `GET` routes for built scripts
new ExpressAdapter({
  app: app,
  
  // default properties can be passed here
  html: 'html/index.html'
});

app.set("views", path.resolve(__dirname, "./views"));


app.get("/", (req, res) => {
  res.render("main", {
    message: "Hello World"
    // can use other `html` if needed
  });
});

app.use(express.static("public/"));

app.listen(3030, () => {
  console.log("express-react-vanilla example server listening on: 3030");
});

DOM

React-vanilla DOM generates native dom elements.

const myDiv = <div class="myDiv"></div>;
  
console.log(myDiv instanceof HTMLElement) // true

Under the hood this would be converted to code that do this:

const myDiv = document.createElement('div');
myDiv.className = 'myDiv';
  
console.log(myDiv instanceof HTMLElement) // true

Event subscription implemented in a straight way. In this example after div would be clicked — it would change the text.

const someValue = new Store.Value.String('Hello');

const myDiv = <div class="myDiv" onclick={_ => someValue.set('updated')}>{someValue}</div>;

Only changed properties would be changed.

Class

You can use class, className, and cls for defining element's class.

Object can be passed as class. In this case not falsy keys would be used as a class name.

const useCls2 = new Store.Value.Boolean(true);

<div class={{cls1: true, cls2: useCls2}} onclick={_ => useCls2.toggle()}> Text </div>

Arrays can also be used

const useCls2 = new Store.Value.Boolean(true);

<div class={['cls1', {cls2: useCls2}]} onclick={_ => useCls2.toggle()}> Text </div>

Arrays of elements would be inserted as children:

var items = [1,2,3,4,5];

// list of items
<ul>
  {items.map(num => <li>{num}</li>)}
</ul>

ArrayStore

Are items from upper example reactive? Yes and no. There is Store.ArrayStore is implemented. It is returned as a result of array method:

var s = new Store({
  a: [10,100,1000]
});

// This would return ArrayStore
s.array('a')

// would return 100
s.array('a').get(1)

You can subscribe to adding and removing elements to ArrayStore. push, pop, shift, unshift, shift, slice, splice, toArray methods are implemented.

There is a List component that add, remove DOM children and does not modify unchanged elements.

Store and Reactivity

Store.Value.[Boolean|String|Number] are handy simple atoms for creating components.

In more complicated cases use the full Store instance.

var s = new Store({
  key1: false, 
  key2: 'Some value', 
  obj: { key3: true }
});

s.set('obj.key3', false); // values can be modified in this way
console.log( s.get('obj.key3') )// getting the value

// this would log initial value and  log them on all updates 
s.sub(['obj.key3', 'key1'], (key3, key1) => console.log({key3, key1}) );

new Store.Value.***** is actually returning typed hinted hook similar to s.val('obj.key3')

Hook functions

Hook function is a function that takes some outer callback as it's value and call it on every change.

Example:

s.val('obj.key3')(console.log) // would log all changes of obj.key3

// similar concept:
s.sub(['obj.key3'], function(newVal){
  console.log(newVal);
});

A lot of usage test cases can be found in Store tests.

How it actually works?

When h function take get any property — it checks if this property is a function. If it is a function — this function would be fed with a callback that would update the actual value when would be called.

Example:

// would set div's class to "cls1"
<div class={ update => update('cls1') }></div>

// would update class every second and set cls1, cls2, ...
<div class={ update =>{
  var num = 1;
  setInterval(_ => { num++; update('cls'+num) }, 1000)
} }></div>

// TextNodes values would be setted in the same way
<div>{ update => update('Hello') } world</div>

Summing up — Store is just gives values that can be updated later.

Conditions

IF tag can be used for switching DOM nodes:

// can be defined globally
const {IF, AND, OR, NOT} = Store;

const cond = new Store.Value.Boolean(true);

<IF condition={s.val(['obj.key3'])}>
  Branch1
<ELSE/>
  Branch2
  <IF condition={cond}>
    SubBranch
  </IF>
</IF>

Logical operations

AND, OR, NOT are built-in logical functions

const a = new Store.Value.Boolean(true);
const b = new Store.Value.Boolean(false);

<IF condition={AND(a, b)}>
  A and B are true
</IF>

<IF condition={AND(a, NOT(b))}>
  A is true and B is false
</IF>

AND and OR can consume more arguments:

var a1 = new Store.Value.Boolean(true);
var a2 = new Store.Value.Boolean(true);
var a3 = new Store.Value.Boolean(true);

AND(a1,a2,a3)(console.log)
// prints true

a2.set(false)
// prints false