Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Not an issue, just sharing a great base class for Redux and Immutable.js #1407

Closed
born2net opened this issue Feb 15, 2016 · 2 comments
Closed

Comments

@born2net
Copy link

not an issue, more of a discussion...
so I was shopping around looking for the best way to support Immutable.js with redux.
I ended up coming up with a solution which works really nice, it gives you the full support of Typescript's typing and it allows you to inject any class instance into redux so you have full typing support around your redux functions.

import {Map} from 'immutable';
import { UUID } from 'angular2-uuid';


/**
 * StoreModel is a thin wrapper of Immutable data around for a Class
 * uses the internal immutable map to hold all values.
 * This allows us a base class on which we can extend and inject
 * into any Redux store as we follow Immutability
 *
 * Also ships with a helper static method to create unique IDs
 **/
export class StoreModel {

    static UniqueId(){
        return UUID.UUID();
    }

    constructor(data:any = {}) {
        this._data = Map<string, any>(data);
    }

    _data:Map<string, any>;

    public setKey<T>(ClassName:any, key:string, value:any):T {
        return this.setData(ClassName, this._data.set(key, value)) as T;
    }

    public getKey(key:string) {
        return this._data.get(key);
    }

    public setData<T>(ClassName, data:any):T {
        function ClassFactory(className:{new(data): T;}, data:any):T {
            var created:T = new className(Map<string, any>(data));
            return created;
        }

        return ClassFactory(ClassName, data);
    }

    public getData():Map<string, any> {
        return this._data;
    }

}

and so you can simply extend the base such as a Todo:

export class TodoModel extends StoreModel {

    constructor(data:any = {}) {
        super(data);
    }

    invalidateTodoId(i_id = -1) {
        return this.setKey<TodoModel>(TodoModel, 'modelId', i_id);
    }

}

and insert that todo into redux with all the goodness of typing support

export function todos(state:List<TodoModel> = List<TodoModel>(), action:ITodoAction):List<TodoModel> {

    function indexOf(id:string) {
        return state.findIndex((i:TodoModel) => i.getKey('modelId') === id);
    }

    switch (action.type) {
        case TodoAction.ADD_TODO:
            return state.push(action.todoModel);
        case TodoAction.REMOVE_TODO:
            return List<TodoModel>(state.filter((i:TodoModel) => i.getKey('modelId') !== action.modelId));
        case TodoAction.CLEAR_TODOS:
            return List<TodoModel>();
        case TodoAction.EDIT_TODO:
            return state.update(indexOf(action.modelId), (todoModel:TodoModel) => {
                return todoModel.setKey<TodoModel>(TodoModel, action.key, action.value)
            });
        default:
            return state;
    }
}

and you also get the same typing support on the subscription side:

appStore.subscribe((businesses:List<BusinessModel>)=> {

            function indexOf(businessId:string) {
                return businesses.findIndex((i:BusinessModel) => i.getKey('businessId') === businessId);
            }


            var b:BusinessModel = businesses.get(3);
            var id = b.getKey('businessId');
            var idx:string = indexOf(id);
            console.log(idx);

            // console.log(value);
        }, 'business');

 ...

full source @: https://github.com/born2net/ng2Boilerplate
works GREAT...

Sean

@gaearon
Copy link
Contributor

gaearon commented Feb 15, 2016

Hi, thank you for sharing. In general we recommend that both actions and the state are plain objects (or something like Immutable Maps) so they are easy to serialize, record and replay, hydrate and dehydrate.

@gaearon gaearon closed this as completed Feb 15, 2016
@born2net
Copy link
Author

tx, yes I am using a for my store, but internally using classes.
regards

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants