14
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

baobab-reactを使って軽量fluxを回す

Last updated at Posted at 2016-03-19

reactでfluxやってるとあのサイクルを回すのが面倒くさくなりませんか?僕はなりました。
そこでbaobab-reactです。

                                 ┌────────────────────┐
                   ┌──────────── │    Central State   │ ◀───────────┐
                   │             │    (Baobab tree)   │             │
                   │             └────────────────────┘             │
                Renders                                          Updates
                   │                                                │
                   │                                                │
                   ▼                                                │
        ┌────────────────────┐                           ┌────────────────────┐
        │        View        │                           │       Actions      │
        │ (React Components) │  ────────Triggers───────▶ │     (Functions)    │
        └────────────────────┘                           └────────────────────┘

1周がこんな感じで回っています。
1本のstate treeがあり、そこから一意に定まるviewがあり、viewがactionを発行し、actionはstate treeを更新する。
まさに求めていた軽量fluxって感じですごく良かったです。

例としてしょうもないカウンターを作ってみます

screenshot 2016-03-20 0.02.26.png

install

npm i -S baobab baobab-react@1.0.0

現在最新の2.0.0rcは上手くimportが出来ないため一個前のバージョンを指定しています。
2016-04-01追記
現在の安定版は1.0.1です。

state tree

アプリケーションの全状態を管理する1本のstate treeを作ります。

tree.js
import Baobab from "baobab";

export default new Baobab({
  counter: 0
});

こんな感じでstate treeとなるobjectを渡したbaobabのインスタンスをexportします。

root component

index.js
import React from "react";
import {render} from "react-dom";
import {root} from 'baobab-react/higher-order';
import tree from "./tree";
import App from "./app";

const RootedApp = root(App, tree);
render(
  <RootedApp />,
  document.getElementById("app")
);

こんな感じで、ルートとなるコンポーネントはbaobab-reactのroot関数でラップした物を使います。

2016-04-01追記
現在betaの2.0.0ではhigher/order関数のシグネチャが変更されて、Componentとcursorの引数が逆になるようです。
root(Component, tree)root(tree, Component)

branch component

全てのコンポーネントはbaobab-reactのbranchでラップしたものを使うようにします。

app.js
import React from "react";
import {branch} from "baobab-react/higher-order";

export default branch(class App extends React.Component {
  handleClickPlus() {
    this.props.actions.addCount(1);
  }

  handleClickMinus() {
    this.props.actions.addCount(-5);
  }

  render() {
    return (
      <div>
        <h1>count: {this.props.counts}</h1>
        <button onClick={() => this.handleClickPlus()}>plus 1</button>
        <button onClick={() => this.handleClickMinus()}>minus 5</button>
      </div>
    );
  }
}, {
  actions: {
    addCount: (tree, value) => {
      const counter = tree.get(["counter"]);
      tree.set(["counter"], counter + value);
    }
  },
  cursors: {
    counts: ["counter"]
  }
});

2016-04-01追記
こちらもroot関数と同じでComponentとcursorの引数が逆になっています。
branch(App, Component)root(cursors, Component)

branchはbranch(コンポーネントクラス, {actions: {}, cursors: {}})という感じで作成します。
第二引数のactionsにはそのコンポーネントで使うアクション関数を渡します。keyの名前でprops.actions以下にアクション関数が登録されます。ここでactionを登録しておくとaction関数の第一引数にtreeがインジェクションされるようになるので、好きなようにstate treeをいじることが出来るようになります。
第二引数のcursorstreeの参照を示していて配列でパスを渡すとtreeの該当する値をkeyの名前でpropsにおいてくれます。

あとはbrowserifyとかbabelifyとかしてhtmlで読み込んでやればokです。
今はactionを個別に作っていますがactions.jsみたいなところから読み込んでやったり、BaseComponentを作ってそこでactionsは定義してしまったりとお好きなようにいい感じにしてください。

以上。

14
13
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?