かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

TypeScriptのコンソールアプリでReduxを触ってみた

FluxとかReduxとか色々あるみたいですね。

Reduxは、以下のサイトにまとまってます。

rackt.org

(state, action) -> newStateというreducerというのを組み合わせたのを使うっぽい。とりあえず習うより慣れろなのでカウンターアプリのコンソールアプリを作ってみた。Redux自体はReactに依存したものじゃないので、こういう風にさくっと試せるのは有り難いですね。

まず、アプリで扱うデータのCounterクラスを定義します。

class Counter {
    constructor(public count: number) {
    }
}

次に、アプリケーションのActionを定義します。 JavaScriptの例では、Actionの識別子に文字列を使ってましたがTypeScriptではenumにしてみました。

enum ActionTypes {
    Increment,
    Decrement
}

interface Action<T> {
    type: ActionTypes;
    param: T;
}

function increment(value: number) {
    return {
        type: ActionTypes.Increment,
        param: value
    } as Action<number>;
}

function decrement(value: number) {
    return {
        type: ActionTypes.Decrement,
        param: value
    } as Action<number>;
}

次にreducerです。CounterとActionを受け取って新しいCounterを返します。このとき返すCounterは新しいインスタンスじゃないといけないので、object-assignを使って新しいコピーを作って返しています。

function counter(state: Counter = new Counter(0), action: Action<any>): Counter {
    switch (action.type) {
        case ActionTypes.Increment:
            return objectAssign({}, state, {
                count: state.count + action.param as number
            } as Counter);
        case ActionTypes.Decrement:
            return objectAssign({}, state, {
                count: state.count - action.param as number
            } as Counter);
        default:
            return state;
    }
}

reducerの関数が1つしかないので必要ないっちゃないのですが普通は複数あるのでまとめます。

var counterApp = Redux.combineReducers({
    counter
});

このcombineReducersというのを使うと、アプリのステートの構造がこんな感じになります。

interface State {
    counter: Counter;
}

因みに、combineReducersは、これと同じみたいですね。

function counterApp(state: State, action: Action<any>) {
    return {
        counter: counter(state.counter, action)
    };
}

あとは、createStateでステートを作ってdispatchメソッドにActionを渡していく感じです。

var store = Redux.createStore(counterApp);

console.log(JSON.stringify(store.getState()));
store.dispatch(increment(10));
console.log(JSON.stringify(store.getState()));
store.dispatch(decrement(5));
console.log(JSON.stringify(store.getState()));

こうすると、結果がこうなります。

{"counter":{"count":0}}
{"counter":{"count":10}}
{"counter":{"count":5}}

storeからreducerに処理がいって新しいstateが出来る。これが基本の流れみたいです。これを踏まえて次は、Reactと連携させてみようかな。