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));
      }
  • 相关阅读:
    北京燃气IC卡充值笔记
    随机分析、随机控制等科目在量化投资、计算金融方向有哪些应用?
    量化交易平台大全
    Doctor of Philosophy in Computational and Mathematical Engineering
    Institute for Computational and Mathematical Engineering
    Requirements for the Master of Science in Computational and Mathematical Engineering
    MSc in Mathematical and Computational Finance
    万字长文:详解多智能体强化学习的基础和应用
    数据处理思想和程序架构: 使用Mbedtls包中的SSL,和服务器进行网络加密通信
    31-STM32+W5500+AIR202/302基本控制篇-功能优化-W5500移植mbedtls库以SSL方式连接MQTT服务器(单向忽略认证)
  • 原文地址:https://www.cnblogs.com/Answer1215/p/6044626.html
Copyright © 2011-2022 走看看