almin+react-routing-resolver
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();
余談として
おお、書いてある > almin@0.16.0ではContextのdispatcherがオプショナルになりました。 https://t.co/3kn3Ak98YG
— JK (@kinjou__j) 2018年6月11日
だとのこと
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
終わり!