command-pack

1.1.4 • Public • Published

Command-Pack for redux

CQS implementation for redux https://martinfowler.com/bliki/CommandQuerySeparation.html

Installation

npm i -S command-pack

Counter Sample

Sample for Counter

First I need to explain what is command and handler. Basically a command is just a data dictionary that carries required parameters for the handler. To create a command it is needed to make a new brand class that extends command-pack Command.

Commands:

For our counter sample, we need two commands: First, IncreaseCounter to increase total and DecreaseCounter.

- IncreaseCounter.js

import {Command} from "command-pack";
 
export default class IncreaseCounter extends Command {
 
    amount;
 
    constructor(amount) {
        super();
        this.amount = amount;
    }
 
    handle(state) {
        return {
            ...state,
            total: state.total + this.amount
        };
    }
}

- DecreaseCounter.js

import {Command} from "command-pack";
 
export default class IncreaseCounter extends Command {
 
    amount;
 
    constructor(amount) {
        super();
        this.amount = amount;
    }
 
    handle(state) {
        return {
            ...state,
            total: state.total - this.amount
        };
    }
}

Now we have commands... and they know how to handle this data parameters with handle method by given state.

Command Registration

import { CommandContainer } from "command-pack";
 
const container = new CommandContainer("counterStore") // Store name
    .setDefaultState({total: 0}) // Store default state
    .register(IncreaseCounter) // our commands
    .register(DecreaseCounter);

CommandExecutor

import { CommandContainer, CommandExecutor} from "command-pack";
 
CommandExecutor.add(new CommandContainer("counterStore")
    .setDefaultState({total: 0})
    .register(IncreaseCounter)
    .register(DecreaseCounter)
);

CommandExecutor.createStore() for Redux-Provider

import React from 'react';
import ReactDOM from 'react-dom';
import Provider from "react-redux/src/components/Provider";
 
import { CommandContainer, CommandExecutor} from "command-pack";
 
import IncreaseCounter from "./components/counter/IncreaseCounter";
import DecreaseCounter from "./components/counter/DecreaseCounter";
import Counter from './components/counter/Counter';
 
CommandExecutor.add(new CommandContainer("counterStore")
    .setDefaultState({total: 0})
    .register(IncreaseCounter)
    .register(DecreaseCounter)
);
 
ReactDOM
    .render(
        <Provider store={CommandExecutor.createStore()}>
            <div>
                <h2>COUNTER Sample</h2>
                <Counter/>
            </div>
        </Provider>
        , document.getElementById('root'));
 
registerServiceWorker();
 

Counter React Component

import React from 'react'
import {connect} from "react-redux";
import {CommandExecutor} from "command-pack";
import DecreaseCounter from "./DecreaseCounter";
import IncreaseCounter from "./IncreaseCounter";
 
class Counter extends React.Component {
 
    inc() {
        CommandExecutor.execute(new IncreaseCounter(1));
    }
 
    dec() {
        CommandExecutor.execute(new DecreaseCounter(1));
    }
 
    render() {
        const total = this.props.counterStore.total;
 
        return (<div>Counter : {total}
            <button onClick={this.dec.bind(this)}>decrease</button>
            <button onClick={this.inc.bind(this)}>increase</button>
        </div>)
    }
}
 
export default connect(x => {
    return {counterStore: x.counterStore}
})(Counter);

ASYNC example

To solve that problem, I tried with middlewares thunk and etc... But it just increases complexity. With command-pack it is really easy to implement an async flow.

Basically you need two commands:

  • StartDownload to start flow
  • DownloadCompleted to get the results

- StartDownload.js

import {Command, CommandExecutor} from "command-pack";
 
export default class StartDownload extends Command {
 
    url;
 
    constructor(url) {
        super();
        this.url = url;
    }
 
    handle(state) {
        fetch (this.url).then (content=>{
            CommandExecutor.execute (new DownloadCompleted (content));
        });
        return {
            ...state,
            downloading : true
        };
    }
}

- DownloadCompleted.js

import {Command} from "command-pack";
 
export default class DownloadCompleted extends Command {
 
    content;
 
    constructor(content) {
        super();
        this.content = content;
    }
 
    handle(state) {
        return {
            ...state,
            downloading : false,
            content : this.content
        };
    }
}

Readme

Keywords

Package Sidebar

Install

npm i command-pack

Homepage

fcelik.us

Weekly Downloads

1

Version

1.1.4

License

ISC

Last publish

Collaborators

  • fcelik