LoginSignup
10
10

More than 5 years have passed since last update.

まだ自分用のメモ書きレベルです…

公式サイトに乗っているQuickStartで作ったプロジェクトを前提に書きます。まだの人は、次のコマンドを打ってください。Windowsの方は後述のTipsに有るスクリプトを定義しないと動かないです。

npm i -g yo generator-fluxible
yo fluxible
npm run dev

なお、yoのテンプレートの依存パッケージが古くてうまく動かないことがあるので、最低babelくらいはアップデートしておきましょう。

ディレクトリ構成

  • actions
    • アクションの定義 (yo fluxibleでは入らないものの作ると便利)
  • components
    • Viewの定義
  • stores
    • ストアの定義
  • build
    • webpackの出力ディレクトリ(IDEなど使う場合は除外する)
  • configs
    • ルーティングなどの定義

使用されている(学ぶべき)技術

  • Babel (ECMA Script6)
  • ReactJS
  • Webpack
  • ES Lint

Tips

windowsで'npm run dev'を動かす

標準が&使ったワンライナーなので、Linux系でしか動かない。
package.jsonに以下のスクリプトを定義して、npm run dev-winを叩く。
Grup使ってもOK!

{
  "scripts": {
    "dev-win": "start node webpack-dev-server.js & SET PORT=3001 & nodemon start.js -e js,jsx"
  }
}

ウザいブラウザのログの消し方

ブラウザのコンソールから

localStorage.debug = "" // OFF
localStorage.debug = "*" // ON

npm debugを使用しているので、その他のオプションはここから探せる気がする。
https://www.npmjs.com/package/debug

前に書いた記事: http://qiita.com/kamijin_fanta/items/55795bd3936cc3a7fc5a

クライアントだけで描写したい

server.jsから編集。

  • executeAction(navigateAction…とかは見ての通り、URLでのナビゲーションを行っているだけなのでサーバ側には不要。
  • stateをdehydrateして取得する必要も渡す必要もない無い。
  • markupもコンポーネントをブラウザに書かせればいいので不要。
// server.js
server.use((req, res, next) => {
    let context = app.createContext();

    debug('Rendering Application component into html');
    const html = React.renderToStaticMarkup(htmlComponent({
        clientFile: env === 'production' ? 'main.min.js' : 'main.js',
        context: context.getComponentContext(),
        // state: exposed,
        // markup: React.renderToString(createElementWithContext(context))
    }));

    debug('Sending markup');
    res.type('html');
    res.write('<!DOCTYPE html>' + html);
    res.end();
});

server.jsでやっていたnavigateActionをブラウザでやるだけ。urlにはlocation.pathname + location.searchを指定することによってルーティングできる。

// client.js

import {navigateAction} from 'fluxible-router';
let context = app.createContext();
context.getActionContext().executeAction(navigateAction, {
    url: location.pathname + location.search
}, (err) => {
    if (err) {
        if (err.statusCode && err.statusCode === 404) {
            next();
        } else {
            next(err);
        }
        return;
    }

    window.context = context;
    const mountNode = document.getElementById('app');

    debugClient('React Rendering');
    React.render(
        createElementWithContext(context),
        mountNode,
        () => debugClient('React Rendered')
    );
});

RouteとNavLink

あってもなくても良いURLパラメータの指定

// routes.js
home: {
    path: '/:id?/',
},
<NavLink routeName="home" navParams={{id: null}}>Home</NavLink>
<NavLink routeName="home" navParams={{id: 123}}>Home 123</NavLink>

最後の/が無いとパラメータ無指定時に落ちる。ちなみに、routes.jsを編集した時はサーバごと再起動させたほうが良い。

パスのコンパイルの詳しい挙動は https://github.com/pillarjs/path-to-regexp/ のテストを見たら分かった。

URLパラメータを取得する

ルーティングの設定の任意のpathにパラメータの名前を指定する。

// routes.js
path: '/member/:user?/'

ComponentconnectToStoreに追記する。重要箇所に☆マークつけた。

// components/ComponentName.js
export default connectToStores(
    ComponentName,
    [ApplicationStore, "RouteStore"], // ☆
    function (context, props) {
        var appStore = context.getStore(ApplicationStore);
        var routeStore = context.getStore("RouteStore"); // ☆
        var params = routeStore.getCurrentRoute().get("params").toObject(); // ☆

        return {
            params: params, // ☆
            user: params.user
        };
    }
);

コンポーネントからthis.props.paramsで取得できるようになる。

クエリを含んだURLをNavLinkで生成する

結論から言うと、用意されていない。

Case1 makePath

コンポーネント上でthis.props.context.makePath(route, parm)を使用することによってURLを取得できる。それに+"?key=value"のような感じでクエリ付きのURLを生成し、JSXによりaタグを生成する。

Case2 Extend NavLink

fluxible-routercreateNavLinkComponentは、引数にオブジェクトを渡して呼び出すと拡張できる。1行目でクエリ文字を生成し、最後の行で結合させる。

// library/QueryNavLink.js
import { createNavLinkComponent } from 'fluxible-router';
import querystring from 'querystring';

export default createNavLinkComponent({
    _getHrefFromProps: function (props) {
        var query = props.query==undefined?"":"?" + querystring.stringify(props.query);

        var href = props.href;
        var routeName = props.routeName;
        var routeStore = this.context.getStore("RouteStore");
        if (!href && routeName) {
            href = routeStore.makePath(routeName, props.navParams);
        }
        if (!href) {
            throw new Error('NavLink created without href or unresolvable routeName \'' + routeName + '\'');
        }
        return href + query;
    }
});

あとは普通に使うときにqueryパラメータをつけるだけ。

// components/ComponentName.js
import NavLink from '../library/QueryNavLink';
<NavLink routeName="mail" query={{page: 1}}>テキスト</NavLink>

アクセスは、Route Dataのqueryを見るだけ。一応公式ドキュメントにも記述の通り、複数の値が見つかった場合は、配列として格納される点を注意。

export default connectToStores(
    Foo,
    ["RouteStore"],
    function (context, props) {
        var routeStore = context.getStore("RouteStore");
        var query = routeStore.getCurrentRoute().get("query").toObject()

        return {
            query: query
        };
    }
);

トラブルシューティング

すこし「ん?」って思ったところを挙げます。

this.context.executeAction is not a function

使用すると明示的に指定したComponentでしかexecuteActionは使えない。

// components/ComponentName.js
ComponentName.contextTypes = {
    executeAction: React.PropTypes.func.isRequired
}

Store undefined was not registered.

app.jsでStoreを登録しないと使えない。

// app.js
app.registerStore(TestStore);

Cannot read property 'storeName' of undefined

app.jsのRouteStoreの読み込み位置を変える。Webpackの都合なのか、数回ハマった。

// app.js
import RouteStore from './stores/RouteStore'; // Application,ApplicationStoreより上に持っていくる
import Application from './components/Application';
import ApplicationStore from './stores/ApplicationStore';

第二引数のストアは、名前でも渡せるのでそっちのほうが良いかも。文字列で渡すと表題のエラーは起こらない。特にRouteStore関係でエラーが出るのでその辺は注意が必要。

export default connectToStores(
    Application,
    ["ApplicationStore"],
    function (context, props) {
        // code
    }
);
10
10
0

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
10
10