zoukankan      html  css  js  c++  java
  • [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));
      }
  • 相关阅读:
    linux 下查看文件个数及大小
    weblogic日志小结
    Excel数据通过plsql导入到Oracle
    Linux查看外网IP
    linux挂载/卸载优盘
    git版本回退
    linux修改文件所属用户、用户组
    retry.RetryInvocationHandler (RetryInvocationHandler.java:invoke(140))
    Hadoop切换namenode为active
    Netty使用LineBasedFrameDecoder解决TCP粘包/拆包
  • 原文地址:https://www.cnblogs.com/Answer1215/p/6044626.html
Copyright © 2011-2022 走看看