React + Unduxでみんなを幸せにする

##ほんとにめっちゃ使いやすいので早く使ってください
~~いつまでReduxでヒイヒイ言ってるんですか？~~

## Unduxって？
Reactの状態管理をするため(バケツリレーとかしたくない)のライブラリ
公式：[undux](https://undux.org/)
###特徴
 - ただ使うだけならgetとsetしか存在しない優しい世界
 - ただし、rxjsを利用すれば複雑なこともできる
 - (僕は)基本的にReactの各ComponentのStateで状態管理するという概念にあっている(と思う)

### とりあえずコードを見てくれ
今回つくるのは簡単なチャットアプリのモックだと思ってください

チャットアプリの全ソース：[socket_test](https://github.com/shoichi1023/socket_test)


まずunduxのインストールから

```
npm install --save rxjs undux
```

そして使い方は簡単
まずは保存したい値を入れるStoreを作る

```Store.js
import { createConnectedStore } from 'undux'

var store = createConnectedStore({
    comments: [],
    user: {
        name: null
    }
});

export default store;
```

次にStoreをpropに渡すためにルートのコンポーネントを囲う
（今回はルーターにreact-routerを使ってます）

```index.jsx
import React from "react";
import ReactDom from "react-dom";
import { BrowserRouter } from "react-router-dom";
import Store from "./Store";

//router
import App from "./App";

class Root extends React.Component {
    render() {
        return (
            <Store.Container>
                <BrowserRouter>
                    <App />
                </BrowserRouter>
            </Store.Container>
        );
    }
}

ReactDom.render(<Root />, document.getElementById("root"));
```

そしたらStoreを呼び出したいコンポーネントを```withStore```でラップ

```Chat.jsx
import React from "react";
import Store from "../Store";

class Chat extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            msg: "",
            comments: []
        }
    }

    componentDidMount() {

    }

    changeTxt(e) {
        this.setState({ msg: e.target.value });
    }

    render() {
        var messages = this.state.comments.map((comment, index) => {
            return <p key={index}>{comment.msg}</p>
        });
        return (
            <div>
                <input type="text" value={this.state.msg} onChange={(e) => {
                    this.changeTxt(e);
                }} />
                <button onClick={() => {
                    actions.sendMsg(this.props.store, this.state.msg);
                    this.setState({ msg: "" });
                }}>
                    投稿
                </button>
                <div>
                    {messages}
                </div>
            </div>
        );
    }

}

export default Store.withStore(Chat);
```

Storeの値は```this.props.store```から```.get("key")```すればとれますが、このまま使うと値の更新時にレンダリングしてくれなくなってしまうので```ComponentWillMount```内で監視して、値自体は```state```のものを使います。

```Chat.js
    componentDidMount() {
        var store = this.props.store;

        //stateにstoreの値をbind
        store.on("comments").subscribe((comments) => {
            this.setState({ comments: comments });
        });
    }
```

rxjs知らない人のために補足。
クリックイベントなどと同様に、onで値の変更を監視して、subscribeで変更があった時の挙動の制御をします。

後は各々好きなところで値を受け取ってセットすればいい。
僕は個人的にActionファイルは作りたい派なので下記のような構造になった。(Socketわからない人ごめんなさい、普通に```ComponentWillMount```内でAPIにデータ取りに行ってると思ってもらって構いません。)

```Chat.jsx
   componentDidMount() {
        var store = this.props.store;

        socket.on('entered', (data) => {
            var comments = store.get("comments");
            comments.push(data);
            store.set("comments")(comments);
        });

        socket.on('received', (data) => {
            var comments = store.get("comments");
            comments.push(data);
            store.set("comments")(comments);
        });

        socket.on('leaved', (data) => {
            var comments = store.get("comments");
            comments.push(data);
            store.set("comments")(comments);
        });

        //stateにstoreの値をbind
        store.on("comments").subscribe((comments) => {
            this.setState({ comments: comments });
        });
    }

```

```action/chat.jsx
import socket from "../socket";

export const entry = (store, name) => {
    var user = store.get("user");
    user.name = name;
    store.set("user")(user);
    const data = { name: name };
    socket.emit('connected', data);
}

export const sendMsg = (store, msg) => {
    const name = store.get("user").name;
    const data = {
        name: name,
        msg: msg
    };
    var comments = store.get("comments");
    comments.push({ msg: name + " : " + msg });
    store.set("comments")(comments);
    socket.emit('sendMsg', data);
}
```

ちなみにプロダクト作る際はもっと複雑にStore使うことになると思うのですが、その際はNamedStore使うと便利です。

```namedStore.js
import { createConnectedStoreAs } from "undux";

const initialA = {
  aHoge:null,
  aFuga:null
}

const initialB = {
  bHoge:null,
  bFuga:null
}

const store = createConnectedStoreAs({
  A: initialA,
  B: initialB
});

export default store;
```

こんな形で書いてあげれば、**```Store.withStores```**で囲ってあげればそれぞれ```this.props.A``` , ```this.props.B```といった形でそれぞれのstoreが下りてきます。
※公式のExampleには```withStore```って書いてあるので注意。PR送ったのでそのうち治るはず。


### よかったこと、悪かったこと
正直、とても使いやすくて、

 - 学習コストなんてない(rxjsの勉強はしたほうがいいかも)
 - 値の監視
 - state内でちゃんと管理できる
 - 使うのにミドルウェアいらない
 - onとsubscribe使えばvue.jsとかmobxみたいなComputedも実現できる(unduxではEffectって言う)
 - ライブラリ内部のコードが見やすい(大体定義にジャンプすれば解決する)

といったあたりがほんとに好きでした。

悪かったことは

 - 公式リファレンスがもう少し充実するといい
 - まだ出たばかりなので資料が少ない(それでも全然困らないレベルなのはほんとにシンプル目指してるだけあるすごい)
 - 値の監視の部分が少し冗長な感じはする

といったあたりでしょうか？

個人的にはstateの値を使ってきれいなReactが書けるので気に入っています。
Reduxとかだと自動でレンダリング走らせてくれたりするので、propsの値を直で使ったりしがちなのが今まではまりやすいポイントだったのかなと思ったので。
あとは、Storeには共通の値を入れといて各コンポーネントで加工して使うとかやりやすそう。

みんなもundux使ってハッピーになりましょう。