1.0.5 • Published 7 years ago

redux-decor v1.0.5

Weekly downloads
1
License
MIT
Repository
gitlab
Last release
7 years ago

Redux Decorators

Requirements

Of course you can use only functions from this library, but I recommend to enable decorators support. See https://www.npmjs.com/package/babel-plugin-transform-decorators-legacy

Usage

// file 'MyModel.js'
import { Storage, Transient, AsyncAction, Action, selector } from 'redux-decor'
    
// Make reducer, inject it into redux store.
// Also mix into the class static actions and static 'getState()' - returns current redux state for that reducer.
// Add to the instance object methods 'getState()', 'dispatch()' - from redux store object.
// By default it uses class name as reducer name, but you can give alias like this '@Storage("TheirsModel")'
@Storage
export default class MyModel {
    
    // Provide properties for state and create initial state.
    forPerson = undefined;
    secretSauce = null;
    fromPerson = null;
    toPerson = null;
    error = null;
    loading = false;
    // Not sure if it really needed, but you can mark property as transient - it shall not pass to redux store
    @Transient
    transientField = 'should be ignored';
    
    // Mark class method as async action.
    // Any changes to 'this' will be ignored, only 'Promise.resolve' result will be used to update redux state.
    @AsyncAction({ // override default callbacks
        request: { loading: true }, // as plain object, just set 'this.loading = true'
        ok: function() { this.loading = false }, // as function, 'this' will be bound to redux state
        error: selector('fetchSecretSauceError') // use 'selector' helper, target method of class ( see below )
    })
    makeASandwichWithSecretSauce(forPerson) {
        var self = this;

        return this.fetchSecretSauce().then(
            sauce => self.makeASandwich(forPerson, sauce),
            error => {
                self.apologize('The Sandwich Shop', forPerson, error);
                throw error; //continue promise chain
            }
        );
    }
    
    // Used as error callback from 'makeASandwichWithSecretSauce' action
    fetchSecretSauceError(error) {
        this.loading = false;
        this.error = error;
    }
    
    // Mark class method as plain action.
    // You don't need to return anything, but changes to 'this' will be used to update redux state
    @Action
    makeASandwich(forPerson, secretSauce) {
        this.forPerson = forPerson;
        this.secretSauce = secretSauce;
        return {
            forPerson,
            secretSauce
        };
    }
    
    @Action
    apologize(fromPerson, toPerson, error) {
        this.fromPerson = fromPerson;
        this.toPerson = toPerson;
        this.error = error;
    }
    
    // Just method
    fetchSecretSauce() {
        return fetch('https://www.google/search?q=secret+sauce').then(r => r.status);
    }
}
    
    
const logger = createLogger({
    collapsed: true,
    duration: true,
    diff: true
});
    
setDefaultOptions({
    asyncAction: {
        request: function () {
            this.error = null;
            this.isLoading = true;
        },
        ok: function (payload) {
            Object.assign(this, payload);
            this.isLoading = false;
        },
        error: function (error) {
            this.error = error;
            this.isLoading = false;
        }
    }
});
    
    
    
// file init-store.js
import { applyMiddleware, combineReducers } from 'redux';
import { createLogger } from 'redux-logger';
import { createStore, setDefaultOptions } from 'redux-decor';
import MyModel from './MyModel';
    
// override default callbacks
setDefaultOptions({
    asyncAction: {
        request: function () {
            this.error = null;
            this.isLoading = true;
        },
        ok: function (payload) {
            Object.assign(this, payload);
            this.isLoading = false;
        },
        error: function (error) {
            this.error = error;
            this.isLoading = false;
        }
    }
});
    
const logger = createLogger({
    collapsed: true,
    duration: true,
    diff: true
});
    
const navReducer = (state = initialState, action) => {
    const nextState = ...
    // Simply return the original `state` if `nextState` is null or undefined.
    return nextState || state;
};
    
const store = createStore(
    combineReducers({Navigation: navReducer}), // provide custom reducer
    {Navigation: initialState}, // and custom initial state
    applyMiddleware(logger) // middlewares
);
    
    
 console.log("call action makeASandwich = ", MyModel.makeASandwich('for me', 'no sauce'));
 console.log("actual state for MyModel = ", MyModel.getState());
 console.log("also call action as instance method = ", new MyModel().makeASandwichWithSecretSauce('for you'));
1.0.5

7 years ago

1.0.4

7 years ago

1.0.3

7 years ago

1.0.2

7 years ago

1.0.1

7 years ago

1.0.0

7 years ago