読者です 読者をやめる 読者になる 読者になる

かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

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

TypeScript

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と連携させてみようかな。