您的位置:首页 > 移动开发

[AngularJS] Write a simple Redux store in AngularJS app

2016-11-09 17:25 495 查看
The first things we need to do is create a reducer:

/**
* CONSTANT
* @type {string}
*/
export const GET_CATEGORIES = "GET_CATEGORIES";

/**
* INIT VALUE
*/
export const initialCategories = [
{id: 0, name: 'Development'},
{id: 1, name: 'Design'},
{id: 2, name: 'Exercise'},
{id: 3, name: 'Humor'}
];

/**
* REDUCERS
* @type {string}
*/
export const categories = (state = initialCategories, {type, payload}) => {
switch(type) {
case GET_CATEGORIES:
return payload || state;
default:
return state;
}
};


It has some default initialize data. What it does is just simply return the state.

Then let's create a gloable store for the app, which has two methods, getState, dispatch. Two props: reducer, state.

class Store {
constructor(reducer, initialState) {
this.reducer = reducer;
this.state=  initialState;
}

getState() {
return this.state
}

dispatch() {
this.state = this.reducer(this.state, action);
}

}


Once we got that, we are going to init our store:

import {categories, initialCategories} from './components/categories/category.state';
import Store from './app.store';
const store = new Store(categories, initialCategories);


We passed in categoreis reudcer and the initialCategories state.

To make it available to Angular APP. we need to make it injectable:

let appModule = angular.module('app', [
CommonModule.name,
ComponentsModule.name
])
.value('store', store)


Then we can use it in our app:

class CategoriesController {
constructor(store) {
'ngInject';

angular.extend(this, {
store
});
}

$onInit() {
this.store.dispatch({type: GET_CATEGORIES});
this.categories = this.store.getState();
}
}


Now we are going to simply the code a little bit, we going to make a subscribe method so that we don't need to call getState() method everytime after we dispatch an action.

You can think that the subscribe method is a just callback function which each time we dispatch an action, it will be called. And inside the callback function, we will call this.store.getState() to get the value.

class Store {
constructor(reducer, initialState) {
this.reducer = reducer;
this.state = initialState;
this.listeners = [];
}

getState() {
return this.state;
}

dispatch(action) {
this.state = this.reducer(this.state, action);
this.listeners.forEach((l) => l());
}

subscribe(listener) {
this.listeners = [
...this.listeners,
listener
];

// return an unsubscribe function
return () => {
this.listeners = this.listeners.filter(l => l !== listener);
}
}
}

export default Store;


class CategoriesController {
constructor($timeout, store) {
'ngInject';

angular.extend(this, {
$timeout,
store
});
}

$onInit() {
this.unsubscribe = this.store.subscribe(() => {
this.categories = this.store.getState();
});

this.store.dispatch({type: GET_CATEGORIES});
}
}


Currently inside the dispatch() metod, we pass in an object with type and payload. It would be better if we can manage those action in a single place. There is where Action creator comes in to play.

/**
* ACTIONS CREATOR
*/
export const CategoriesActions = () => {
const getCategoreis = (categories) => {
return {type: GET_CATEGORIES, payload: categories}
};

const getCurrentCategory = (currentCategory) => {
return {type: GET_CURRENT_CATEGORY, payload: currentCategory}
};

return {
getCategoreis,
getCurrentCategory
};
};


To make it avaiable to Angular App, we can create a factory for this:

let appModule = angular.module('app', [
CommonModule.name,
ComponentsModule.name
])
.value('store', store)
.factory('CategoriesActions', CategoriesActions)
.component('app', AppComponent)


Then we can use it inside the controller:

constructor($timeout, store, CategoriesActions) {
'ngInject';

angular.extend(this, {
$timeout,
store,
CategoriesActions
});
}


$onInit() {
this.unsubscribe = this.store.subscribe(() => {
this.categories = this.store.getState();
});

this.store.dispatch(this.CategoriesActions.getCategoreis());
}


onCategorySelected(currentCategory) {
this.currentCategory = category(this.currentCategory, this.CategoriesActions.getCurrentCategory(currentCategory));
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: