axr

1.0.13 • Public • Published

AXR

Asynchronous stream development util. It's more convenient, modulized and typesafe to develop redux style application with AXR.

AXR takes the first character from each role of redux:

  • A: Redux action
  • X: Asyncchronous stream lib, maybe saga or thunk
  • R: Redux reducer

AXR is based on redux-saga. redux is not the required, you still can use AXR will your own state management style.

How to use

Install

Use npm:

npm install axr

or use yarn:

yarn add axr

Initialized

AXR dependents on two apis: dispatch and getState, so you need to set them first:

// in setup.js
// 1: import axrSetOptions(), axrSetOptions will tell what axr needed
import { axrSetOptions } from 'axr/dist/ASR';

// 2: Setup the two api, just delegate to redux store
axrSetOptions({
    getState: () => {
        return store.getState();
    },
    dispatch: (action) => {
        return store.dispatch(action);
    }
});

// 3: Now, export anything from axr
export * from 'axr/dist/ASR';

After setup options, just import apis from setup.js to create an AXR module. NB: Don't import apis from AXR directly.

// in AXR.js
import { actionCreator, sagaCreator, reducerCreator, axr } from './setup.js';

// Create an action
const appStart = actionCreator<string>('appStart');

// Create an saga
const sagaAppStart = sagaCreator(appStart, function*(payload, getState) {
	console.log(payload);
});

// Create a reducer
const startInfo = reducerCreator('Hello World', appStart, (state, payload) => {
	return payload;
})

// Export axr
export default axr(
{
	appStart,
},
[
	sagaAppStart,
],
{
	startInfo,
});

Now setup saga and redux in application!

import AXR from './AXR';

// Create redux sagaMiddleware
const sagaMiddleware = createSagaMiddleware();
// Create root reducer
const rootReducer = combineReducers(AXR.reducer);
// Create store
const store = createStore(rootReducer, applyMiddleware(sagaMiddleware));

// Start saga
const sagas = AXR.handler;
const rootSaga = function*() {
	yield all(sagas.map(saga => spawn(saga.saga)));
};
sagaMiddleware.run(rootSaga);

Trigger an action:

import AXR from './AXR';

// Trigger the appStart action
AXR.action.appStart.dispatch('Hello AXR');

This is all of AXR.

API

actionCreatorFactory(prefix)

Create an actionCreator with prefix.

// Create an actionCreator with prefix 'BZ_A'
const actionCreator = actionCreatorFactory('BZ_A');

actionCreator(type)

Create an action object, the type of action object is type. If the actionCreator is from actionCreatorFactory(prefix), the type will automatically prefixed.

The action object is a function in fact, and has some properties as bellow:

  • type: The type of action object (prefixed)
  • match(type): Check action type
  • dispatch(payload): Trigger an action with payload data

Example:

// Create an action object
const appStart = actionCreator('appStart');

// Create an action
// action.type === 'appStart'
// action.payload === undefined
const action = appStart();

// Check action is 'appStart' and do something
if (appStart.match('appStart')) {
	// Do something
}

// Trigger an action
appStart.dispatch();

////////////////////////////////////////////////////

// Create an action with payload
// The type of payload is
// {
//    username: string,
//    password: string,
// }
const login = actionCreator<
{
	username: string,
    password: string,
}>('login');

// Create an action data
// action.type === 'login'
// action.payload.username === 'zhangsan'
// action.payload.password === 'admin@123'
const action = login({
	username: 'zhangsan',
    password: 'admin@123',
});

// Trigger an action
login.dispatch({
	username: 'zhangsan',
    password: 'admin@123',
});

actionCreator.async(type)

Create an async action object. An async action object has three sub action objects: started, done and failed. The payload of done is:

{
	// The param of async action
	params: startPayload,
    // The result of async action
    result: doneResult,
}

Example:

// Create an async action with started payload and done payload
// The payload type of started action is
// {
//    username: string,
//    password: string,
// }
//
// The payload type of done action is
// {
//     name: string,
//     age: number,
// }
const login = actionCreator<
{
	username: string,
    password: string,
},
{
	name: string,
    age: number,
}>('login');

// Trigger an started action
login.started.dispatch({
	username: 'zhangsan',
    password: 'admin@123',
});

// Trigger an done action
login.done.dispatch({
	params: payload,
    result: result,
});

sagaCreator(action, handle)

Create an saga, the saga will be actived while action trigged. The action is an action object created by actionCreator, the handle is a generaor.

The defination of handle is:

function*(payload, getState, action){}
  • payload: The data of triggered action
  • getState: State getter
  • action: The triggered action

There are some default saga helpers from redux-saga.

  • latest(action, handle):Wrapped takeLatest
  • every(action, handle):Wrapped takeEvenry
  • throttle(action, time, handle):Wrapped throttle
const sagaFromLatest = sagaCreator(action, handle);
const sagaFromEvery = sagaCreator.evenry(action, handle);
const sagaFromThrottle = sagaCreator.throttle(action, 1000, handle);

The result of sagaCreator (or helpers) has the property as bellow:

  • saga: The actual saga
  • handle: The raw generator from arguments

Example:

// Create an action
const appStart = actionCreator<string>('appStart');
// Create saga handler of action
const sagaAppStart = sagaCreator(appStart, function*(payload, getState) {
	// Do the async task
	const result0 = yield ...;
    // Do the async task
    const result1 = yield ...;
    // Do something else
    ...
});

// Or an async action
const login = actionCreator<
{
	username: string,
    password: string,
},
{
	name: string,
    age: number,
}>('login');

const sagaLogin = sagaCreator(login.started, function*(payload, getState) {
	// loginAPI will use username and password
    // and return a promise
	const result = yield loginAPI(payload);

    // Trigger the done event
    login.done.dispatch({
    	params: payload,
        result: result,
    });
})

reducerCreator(initState, action, reducer)

Create a reducer. The arguments as bellow:

  • initState: Initial state of this reducer
  • action: The related action object
  • reducer: Reducer handle, has the defination(state, payload, action) => state
    • state: The old state
    • payload: Data with the triggered action
    • action: The triggered action

Example:

// Create a reducer will be called when login.done triggered.
// The reducer just return the payload of this action.
const userInfo = reducerCreator({ name: '', age: 0}, login.done, (state, payload, action) => {
	return payload.result;
});

reducersCreator(initState)

Create a reducer who can handle mutiple action types. The result can use case(action, handle) to declare action handle branch.

Example:

// Create a reducer will be called when login.done or login.started triggered.
const userInfo = reducersCreator({ name: '', age: 0})
.case(login.started, (state, payload, action) => {
	// Reset state when started action
	return {
    	name: '',
        age: 0,
    };
})
.case(login.done, (state, payload, action) => {
	// Record the data when done action
	return payload.result;
});

axr(action, handle, reducer)

Create a axr object. An axr object has these information:

  • action: A map, include the whole action objects
  • handler: An array, include the whole sagas
  • reducer: A map, include the whole reducers

The key of action map is what used to dispatch action.

axrObject.action.appStart()
// or
axrObject.action.appStart.dispatch();

The key of reducer map is the property name in global state of store.

Example:

export default axr(
{
	// Use axr.action.appStart and axr.action.login
	appStart,
    login,
},
[
	sagaAppStart,
    sagaLogin,
],
{
	// Use state.userInfo to get the data
	userInfo,
}
);

axrCombine(axr,[axr...])

Combine mutiple axr objects as a big axr object. If there is name conflict in action or reducer, will throw an error.

axrCombine is the method to modulize our AXR source code.

// The directories
// The AXR in root will combine the sub directories's AXR (a and b)
root
	AXR
    	export axrCombine(aAXR, bAXR...)
    a
    	AXR
        	export axr()
    b
    	AXR
        	export axr()
	...

Example:

export default axrCombine(
	commonAXR,
    loginAXR,
    ...
);

axrSetOptions(options)

Setup AXR, the options must provide:

  • dispatch: Action dispatch function, the same as redux dispatch(action) => action
  • getState: State getter function, the same as redux getState() => state

Example:

axrSetOptions({
    getState: () => {
        return app().axrState();
    },
    dispatch: (action) => {
        return app().axrDispatch(action);
    }
});

Readme

Keywords

none

Package Sidebar

Install

npm i axr

Weekly Downloads

1

Version

1.0.13

License

MIT

Unpacked Size

101 kB

Total Files

25

Last publish

Collaborators

  • builditnow