首页 > 代码库 > [AngularJS] Write a simple Redux store in AngularJS app

[AngularJS] Write a simple Redux store in AngularJS app

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));  }

 

[AngularJS] Write a simple Redux store in AngularJS app