almin+react-routing-resolver

2018-06-22T00:00:00+00:00 JavaScript almin

hatebupwaを読んでる時に気になったreact-routing-resolverを使ってみた

※almin自体にはあまり触れないのでドキュメント参照

package.json

{
  "name": "sample",
  "version": "1.0.0",
  "scripts": {
    "build": "webpack",
    "lint": "eslint src"
  },
  "dependencies": {
    "almin": "^0.16.0",
    "core-decorators": "^0.20.0",
    "history": "^4.7.2",
    "office-ui-fabric-react": "^5.100.0",
    "react": "^16.3.1",
    "react-dom": "^16.3.1",
    "react-routing-resolver": "^3.0.0"
  },
  "devDependencies": {
    "babel-core": "^6.26.3",
    "babel-eslint": "^8.2.3",
    "babel-loader": "^7.1.4",
    "babel-plugin-transform-decorators-legacy": "^1.3.4",
    "babel-preset-env": "^1.6.1",
    "babel-preset-react": "^6.24.1",
    "eslint": "^4.19.1",
    "eslint-plugin-react": "^7.9.1",
    "webpack": "^3.8.1"
  }
}

まぁ普通にインストール周りをやるだけなんだけど、ES7 Decorators関連をちょっと使うのでbabel-plugin-transform-decorators-legacyを入れておく

※eslint関連は省略

.babelrc

{
  "presets": ["react", "env"],
  "plugins": [
    "transform-decorators-legacy"
  ]
}

store/AppStore.js

import { Store } from "almin";

export default class AppStore extends Store {

  constructor() {
    super();
    this.state = {};
  }

  getState() {
    return this.state;
  }

}

Context.js

import { Context, StoreGroup } from "almin";
import createHistory from "history/createHashHistory";
import AppStore from "./store/AppStore";

const storeGroup = new StoreGroup({
  sample: new AppStore()
});

export const context = new Context({
  store: storeGroup
});

export const browserHistory = new createHistory();

余談として

だとのこと

components/User.js

import * as React from "react";
import { context } from "../Context";

export default class User extends React.PureComponent {

  constructor({ name }) {
    super();
    this.name = name;
  }

  render() {
    return (
      <div>
        <h1>Hello, {this.name}</h1>
      </div>
    );
  }
}

一応、Storeによる状態管理を使ってデータをやりとりすることも出来るのですが今回省略(簡略化したため)

components/App.js

import React from "react";
import { autobind } from "core-decorators";
import { Route, Router } from "react-routing-resolver";
import { context, browserHistory } from "../Context";
import User from "./User";
import HomeDispatcherUseCase from "../use-case/HomeDispatcherUseCase";
import { DefaultButton, TextField } from "office-ui-fabric-react";

export default class App extends React.PureComponent {

  constructor() {
    super();
    this.nameTextRef = React.createRef();
  }

  componentWillMount() {
    const onChangeHandler = () => {
      this.setState(context.getState());
    };
    onChangeHandler();
    this.unSubscribe = context.onChange(onChangeHandler);
  }

  render() {
    return (
      <React.Fragment>
        <nav className="navbar navbar-inverse" style={{ borderRadius: "0" }}>
          <nav className="navbar-collapse">
            <ul className="nav navbar-nav pull-right">
              <li><a href="#">{this.state.sample.name}</a></li>
            </ul>
          </nav>
        </nav>
        <div className="container-fluid">
          <Router history={browserHistory}>
            <Route pattern="/user/:name" onMatch={this.onMatchUser} render={this.onRenderUser} />
            <Route pattern="/home" onMatch={this.onMatchHome} render={this.onRenderHome} />
            <Route pattern={"*"} onMatch={this.onMatchOther} />
          </Router>
        </div>
      </React.Fragment>
    );
  }

  @autobind
  onMatchHome() {
    this.setState({ sample: { name: "guest" }});
  }

  @autobind
  onMatchUser({ name }) {
    this.setState({ sample: { name }});
  }

  onMatchOther() {
    context.useCase(new HomeDispatcherUseCase()).execute();
  }

  @autobind
  onRenderHome() {
    return (
      <div>
        <form onSubmit={this.onClick} className="form-inline">
          <div className="form-group">
            <TextField className="form-control" ref={this.nameTextRef} />
          </div>
          <DefaultButton
            primary
            text="click"
            onClick={this.onClick}
            className="btn btn-default"
            style={{ marginLeft: "10px" }} />
        </form>
      </div>
    );
  }

  onRenderUser({ name }) {
    return (
      <User name={name} />
    );
  }

  @autobind
  onClick(event) {
    event.preventDefault();
    const value = this.nameTextRef.current.value || "";
    browserHistory.push(`/user/${value}`);
  }
}

use-case/HomeDispatcherUseCase.js

import { UseCase } from "almin";
import { browserHistory } from "../Context";

export default class HomeDispatcherUseCase extends UseCase {
  execute() {
    browserHistory.push("/home");
  }
}

index.js

"use strict";

import React from "react";
import ReactDOM from "react-dom";
import App from "./component/App.js";

ReactDOM.render(<App />, document.querySelector("#app"));

実際に動かしてみる

まず/にアクセスした場合にはonMatchOtherでHomeDispatcherUseCaseにより/homeへpushされて移動される。でそのpush先の/homeではonMatchHomeが先に処理されてonRenderHomeで返されたビューがレンダリングされるようになる

でなんか入れてclickを押すとonClickによって#/user/{name}に飛ばされるようになる

というようにonMatchUserでデータをセットされてonRenderUserによってビューがレンダリングされる

まぁとりあえず使ってドキュメント読めばいいだけなので(ry

終わり!

graphql.jsを使ってみた webpackでTypeScriptプロジェクトをビルド