0.0.8 • Published 7 years ago

quex v0.0.8

Weekly downloads
1
License
MIT
Repository
github
Last release
7 years ago

Quex

State Transition Processor.

Quex is not a Flux that process with Command Pattern but just processor use to state transition with Queue and Task.

Install

npm i -S quex

https://www.npmjs.com/package/quex

Example

import createStore from 'quex';

const store = createStore({ count: 0 });

// Subscribing changing of state.
const unsubscribe = store.subscribe((state, error) => {
	// ...
})

const task = {
    increment: (state count) => ({
        count: s.count + count
    }),

    /*
     * AsyncTask
     *
     * AsyncTask should return TaskFunction, not state,
     * whenever want to update state.
     */
    incrementAsync: async (_, count) => {
        const n = await Promise.resolve(count);
        return (state) => ({
            count: s.count + n
        });
    },

    incrementMulti: (state, count) => ({
        count: s.count * count
    })
};

store.usecase('INCREMENT').use([
	task.increment,
	task.incrementAsync,

	// incrementMult will waiting for the completion of incrementAsync
	task.incrementMulti,

	// currentState will be this
	(state, params) => {
		assert.deepEqual(state, { count: 8 });
		assert.equal(params, 2)
	}
])(2)

API

createStore<S>(initialState: S, option?: Option<S>): store

return: store.

Option
interface Option<S> {
    updater?: (currentState: S, nextState: Partial<S>) => S;
    enhancer?: <T>(name: string | undefined, task: T) => T;
}

option.updater

updater can customize how to assign currentState and nextState.

default: (s1: S, s2: Partial<S>) => Object.assign({}, s1, s2)

option.enhancer

enhancer can enhance all task in all queue.

Example: For logging.

const enhancer = (name, task) => (state, params) => {
    const result = task(state, params);
    console.log(`${name}::${task.name}`, result);
    return result
}

store.getState(): S

store.setState(state: Partial<S>): S

store.subscribe(Listener): () => void

Subscribing changing of state and transition error.

return: Function that remove listener.

interface Listener {
	(state: S, error: Error) => void;
}

store.usecase(name?: string): { use }

store.usecaes copmose a queue by use.

alias: store.dispatch()

return: use()

/* Type of Task */
interface T1<S> {
    (state: S): Partial<S> | void;
}
interface T2<S> {
    (state: S): Promise<T1<S>> | void;
}
interface T3<S, P> {
    (state: S, param: P): Partial<S> | void;
}
interface T4<S, P> {
    (state: S, param: P): Promise<T3<S, P>> | void;
}

/* Type of Queue */
type Q1<S> = (T1<S> | T2<S>)[];
type Q2<S, P> = (T3<S, P> | T4<S, P>)[];

use can chain.

store.usecase()
    .use(task.increment)
    .use(task.incrementAsync)
    .use(task.incrementMulti)

store.listenerCount

 readonly listenerCount: number;

Advanced

About Task

Basicaly, Task is a Function that recieve currentState and parameter then return nextState.

State will be change when Task return nextState.

AsyncTask

AsyncTask should return Promise<Function>, not Promise<State>, whenever want to update state.

type Task = (state: S, params: P) => S
type AsyncTask = (state: S, params: P) => Promise<Task>

How to process task in the queue

All task in the queue are waiting for completition of previous task even if it is AsyncTask.

If task throw Error, Queue processing is aborted.

Transition aborting

To abort state transition, Throw Error in the Task.

Timing of publishing new state to listener

1. When last task in the queue is compoleted.

Notification is reduced when state is updated by the sequence of SyncTask in order to reduce rendering of view.

2. When task return Promise.

Otherwise, view will not updated until async process is completed.

3. When Task throw Error

In this case, State transition is aborted and Listener is called with state and error.

With React.js

If you are using Quex with React.js, you can use react-redux without special settings.

Example:

const store = createStore({count: 0})

<Provider store={store}>
	<Counter>
</Provider>
/* mapUseCaseToProps */
const mapUseCaseToProps = (usecase) => ({
	increment: usecase('INCREMENT').use([
 		task.increment
 	])
})

/* connect */
export default connect(mapStateToProps, mapUseCaseToProps)(Counter)
0.0.8

7 years ago

0.0.7

7 years ago

0.0.6

7 years ago

0.0.5

7 years ago

0.0.4

7 years ago

0.0.3

7 years ago

0.0.2

7 years ago

0.0.1

7 years ago