@nikmen/directorr v0.8.0
Directorr
Like Redux but using decorators
Why
Actually, Redax is the implementation of the command pattern and therefore it can be implemented through class decorators.
What
The design principle is very simple: decorators + action + middleware(and redux like). And it works well with observable libraries like MobX
Installation
Run npm install @nikmen/directorr --save
or yarn add @nikmen/directorr --save
and enable decorators for babel or typescript
API
action(type: ActionType)
import { action } from "directorr";
const CHANGE_TEXT = 'change_text';
class TodoItem {
text = ''
@action(CHANGE_TEXT) toChangeText = (newText) => newText
}
const todo = new TodoItem();
todo.toChangeText('someText');
If the decorated property(toChangeText) of the class instance is called, then the action object will be created and dispatched. The action object will have fields:
{
type: CHANGE_TEXT,
payload: 'someText'
}
If toChangeText returns null, then the action will not be dispatched.
effect(type: ActionType)
import { action, effect } from "directorr";
const CHANGE_TEXT = 'change_text';
class TodoItem {
text = ''
@action(CHANGE_TEXT) toChangeText = (newText) => newText
@effect(CHANGE_TEXT) changeText = (newText) => {
this.text = newText;
}
@effect(CHANGE_TEXT) andChangeLog = (newText) => {
console.log('andChangeSome');
}
}
const todo = new TodoItem();
todo.toChangeText('someText');
expect(todo.text === 'someText');
After calling toChangeText, all property(changeText, andChangeSome) decorated with an effect with the same action type will be called.
connectStore(prefix: ActionType)
import { action, effect, connectStore } from "directorr";
const CHANGE_TEXT = 'change_text';
class TodoItem {
text = ''
@action(CHANGE_TEXT) toChangeText = (newText) => newText
@effect(CHANGE_TEXT) changeText = (newText) => {
this.text = newText;
}
}
class Store {
someText = ''
@connectStore(CHANGE_TEXT) todo = new TodoItem()
@effect([TodoItem, CHANGE_TEXT])
changeText = (newText) => {
this.someText = newText;
}
}
const store = new Store();
store.todo.toChangeText('someText');
expect(store.someText === 'someText');
Dispatch all actions from TodoItem in the Store.
Directorr
import { action, effect, Directorr } from "directorr";
const CHANGE_TEXT = 'change_text';
class TodoItem {
text = ''
@action(CHANGE_TEXT) toChangeText = (newText) => newText
@effect(CHANGE_TEXT) changeText = (newText) => {
this.text = newText;
}
}
const director = new Directorr();
const logMiddleware = () => (next: any) => (action: any) => {
console.log('log action:', action);
next(action);
};
director.addReduxMiddlewares(logMiddleware);
director.addStores(PageStore, TotalStore);
const todo = director.stores.get(TodoItem);
todo.toChangeText('someText');
expect(todo.text === 'someText');
log action: {type: "change_text", payload: 'someText'}
injectStore(class: SomeClass)
import { action, effect, Directorr } from "directorr";
const ACTION_ONE = 'action_one';
class FirstStore {
text = ''
@action(ACTION_ONE) toChangeText = (newText) => newText
@effect(ACTION_ONE) changeText = (newText) => {
this.text = newText;
}
}
const ACTION_TWO = 'action_two';
class SecondStore {
@injectStore(OneStore) injectFirstStore: FirstStore
text = ''
@action(ACTION_TWO) toChangeText = (newText) => newText
@effect(ACTION_TWO) changeText = (newText) => {
this.text = newText;
}
}
const director = new Directorr();
director.addStores(FirstStore, SecondStore);
const firstStore = director.stores.get(FirstStore);
const secondStore = director.stores.get(SecondStore);
firstStore.toChangeText('someText');
expect(firstStore.text === 'someText');
expect(secondStore.injectFirstStore.text === 'someText');