はじめに
JavaScriptの基礎知識がだいたいわかったので、スキマ時間(4時間くらい)で簡単なブログのフロントエンドをReact+Reduxで構築した。
といっても、Modern React with Reduxというコースのセクション9を見ながら手を動かしただけ。JavaScript初心者だが、セクション9から見始めても特に問題なかった。
ソースコード
実装時のメモも含めて、以下に保存してある。
github.com/tomoyamachi/react-blog-sample
できるようになったこと
- SPAだが、URLごとで表示するDOMを分ける
- 非同期でAPI通信を行う
- 非同期処理が完了してから、表示処理を実行する
- 送信フォームの管理(バリデーション含む)
- ESの言語仕様がざっくりわかる
- 一人である程度のプロジェクトをつくる
今後
実践でそのまま利用できそうなことが詰まっていた。作成後1時間くらいはできたコードをいじって、各コードの役割を理解した。
次は、テストやコード品質の担保をしたいので、Advanced React and Reduxを見ようと思っている。
もし、React+Reduxを利用した中規模以上プロジェクトのソースコードが公開されてれば、かなりレベル上げができそう。
軽く探しているが見当たらないので、もしあれば知りたい。
以下、パッケージなどのメモ
SPAだが、URLごとで表示内容を出し分けたい
react-router-dom を利用。Switch
を使わない場合、パスの正規表現に引っかかったものすべてのコンポーネントが表示される。
なお、parameterを取得したいときは、Componentの this.props.match.params.{name}
の形で取得できる。
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import reducers from './reducers';
import promise from 'redux-promise';
import PostsIndex from './components/posts_index';
import PostsNew from './components/posts_new';
import PostsShow from './components/posts_show';
const createStoreWithMiddleware = applyMiddleware(promise)(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<BrowserRouter>
<div>
<Switch>
<Route path="/posts/new" component={PostsNew} />
<Route path="/posts/:id" component={PostsShow} />
<Route path="/" component={PostsIndex} />
</Switch>
</div>
</BrowserRouter>
</Provider>
, document.querySelector('.container'));
API通信がしたい
axiosを利用。
レスポンスが返ってきてからの処理を入れる場合は、axios.{HTTPmethod}().then()
でつなげる。エラー時の挙動は.catch()
で管理
export function createPost(values, callback) {
const request = axios.post(`${ROOT_URL}/posts${API_KEY}`, values)
.then(() => callback())
.catch((e) => console.log(e));
return {
type: CREATE_POSTS,
payload: request
};
}
非同期処理を管理したい
redux-promiseを利用する。ミドルウェアに入れるだけで、利用できるようになる。非同期処理が完了してから、処理を行えるようになる。 ※細かなことは分かってない
const createStoreWithMiddleware = applyMiddleware(promise)(createStore);
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
...(略)
フォームの管理がしたい
redux-form を利用。
バリデーションはreduxFormの引数にvalidate
を指定すればいい。
フォーム操作後にエラーを表示したい場合は、meta.touched
で判定。
import React, {Component} from 'react';
import {Field, reduxForm} from 'redux-form';
import { connect } from 'react-redux';
import { Field, reduxForm } from 'redux-form';
class PostsNew extends Component {
renderField(field) {
const {meta: { touched, error }} = field;
const className = `form-group ${touched && error ? 'has-danger' : ''}`;
return (
<div className={className}>
<label>{field.label}</label>
<input
className="form-control"
type="text"
{...field.input}
/>
<div className="text-help">
{field.meta.touched ? field.meta.error : ''}
</div>
</div>
);
}
onSubmit(values) {
this.props.createPost(values, () => {
this.props.history.push('/');
});
}
render() {
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
<Field
label="Title"
name="title"
component={this.renderField}
/>
<button type="submit" className="btn btn-primary">Submit</button>
</form>
);
}
}
function validate(values) {
const errors = {};
if(!values.title) {
errors.title = "enter a title!";
}
return errors;
}
export default reduxForm({
validate,
form: 'PostsNewForm'
})(
connect(null,{ createPost })(PostsNew)
);