Realar
Installation
npm i -P realar
yarn add realar
After that you need update your babel config:
module.exports = {
"plugins": [
"realar/babel"
]
}
And you need to wrap your react-dom render block, to Realar init
function call:
import React from "react";
import { render } from "react-dom";
import { init } from "realar";
import { App } from "./app";
init(() => render(<App />, document.getElementById("root")));
Usage
Perfect usage :+1:
import React from "react";
import { unit, useUnit } from "realar";
const Ticker = unit({
current: 0,
after: 2,
get next() {
return this.current + 1;
},
tick() {
this.current += 1;
},
synchronize() {
this.after = this.next + 1;
}
});
export default function App() {
const { current, next, after, tick } = useUnit(Ticker);
return (
<>
<h1>Realar ticker</h1>
<p>Current: {current}</p>
<p>Next: {next}</p>
<p>After: {after}</p>
<p>
<button onClick={tick}>tick</button>
</p>
</>
);
}
Redux style usage:
import React from "react";
import { unit, useService } from "realar";
const store = unit({
state: [
{ title: 'Todo 1' },
{ title: 'Todo 2', completed: true }
],
get completed() {
return this.state.filter(i => i.completed);
},
get all() {
return this.state;
},
add(title, completed = false) {
this.state = [ ...this.state, { title, completed }];
},
toggle(i) {
const { state } = this;
const index = state.indexOf(i);
this.state = [
...state.slice(0, index),
{ ...i, completed: !i.completed },
...state.slice(index+1)
];
}
});
function TodoItem({ item }) {
const { title, completed } = item;
return (
<div className="todo-item">
{completed ? <div className="completed"></div> : null>}
<span className="title">{title}</span>
</div>
);
}
function TodoList() {
const { all } = useService(store);
return (
<div className="todo-list">
{all.map(item => <TodoItem item={item} />)}
</div>
);
}
export default function App() {
return <TodoList />;
}
All interface methods in one presentation example:
import React from "react";
import {
action,
call,
changed,
service,
Service,
signal,
unit,
useService,
useUnit,
Zone
} from "realar";
const backend_async_init = event();
const log = event();
const x10 = event();
const GetUser = call();
const counter = signal(-1);
const backend_proc = signal(0);
const logger = unit({
lines: [],
get text() {
return this.lines.join("\n");
},
[log](...args) {
this.lines = [...this.lines, args.join(" ")];
}
});
const backend = unit({
proc: 0,
async [GetUser](id) {
this.proc++;
const res = await new Promise(r => setTimeout(() => r("John Doe " + id), 1000));
this.proc--;
return res;
},
synchronize() {
if (changed(this.proc)) backend_proc(this.proc);
},
construct() {
this.async_init();
},
async async_init() {
await new Promise(r => setTimeout(r, 2000));
backend_async_init();
}
});
const user = unit({
name: "not loaded",
id: 0,
proc: 0,
get loading() {
return this.proc > 0;
},
async load() {
this.proc++;
this.name = await GetUser(++this.id);
this.proc--;
},
construct() {
this.async_construct();
},
async async_construct() {
await backend_async_init;
log("user", this.id, "backend_async_init");
}
});
const stepper = unit({
step: 1,
inc() {
this.step += 1;
},
[x10]() {
log("step:", this.step, "->", this.step * 10);
this.step *= 10;
}
});
const ticker = unit({
user: user(),
backend_proc: 0,
stepper: service(stepper),
after: 0,
current: 0,
get step() {
return this.stepper.step;
},
get next() {
return this.current + this.step;
},
tick() {
this.current += this.step;
},
save: () => counter(this.current),
construct() {},
destruct() {},
synchronize() {
this.after = this.next + this.step;
if (changed(this.after > 5)) {
log("if after > 5");
x10();
}
},
[counter]: val => (this.current = val),
[backend_proc](val) {
this.backend_proc = val;
}
});
function App() {
const { current, next, after, tick, user, save, backend_proc } = useUnit(ticker);
const { step, inc } = useService(stepper);
const { load, loading, name } = user;
return (
<div>
<p>
Current: {current}
<button onClick={tick}>next</button>
<button onClick={save}>save</button>
</p>
<p>Next: {next}</p>
<p>After: {after}</p>
<p>
Step: {step}
<button onClick={inc}>inc</button>
</p>
<p>User: {loading ? "loading..." : name}</p>
<p>Backend: {backend_proc ? "loading..." : "idle"}</p>
<p><button onClick={load}>load</button></p>
</div>
)
}
function Logger() {
const { text } = useService(logger);
return (
<textarea value={text} readOnly />
)
}
const whirl = unit({
cols: [1],
map: fn => this.cols.map(fn),
shift() {
this.cols = this.cols.slice(1);
},
push() {
this.cols = [...this.cols, (this.cols.pop() || 0) + 1];
}
});
function Whirl({ children }) {
const { map, shift, push } = useUnit(whirl);
return (
<>
<button onClick={shift}>-</button>
{map(key => (
<Zone key={key}>
{children}
</Zone>
))}
<button onClick={push}>+</button>
</>
)
}
export function Root() {
return (
<>
<Whirl>
<App />
</Whirl>
<Logger />
<Service unit={backend}/>
</>
);
}
Try this example on your computer:
git clone git@github.com:betula/realar.git
cd realar
npm run start