概要
- 前回記事の続き。
- 実際にReduxでReactのstateを管理する。
- Reactのインストールは出来ている前提とする。
- ReactとReactDOMはwebpackでグローバル変数かしている事とする。
Components
ReactでComponentsを作成していく。
まずは、メインとなるComponent。
(CSSフレームワークはMaterialize.cssを利用している。)
import FormApp from './Form/FormApp.jsx';
export default class App extends React.Component {
render() {
return (
<div className="container">
<FormApp
handleClick={this.props.onClick}
value={this.props.value}
/>
</div>
);
}
}
App.propTypes = {
onClick: React.PropTypes.func,
value: React.PropTypes.string
};
次に、Form全体を括るComponent。
import FormInput from './FormInput';
import FormDisplay from './FormDisplay';
export default class FormApp extends React.Component {
render() {
return (
<div>
<div className="row">
<div className="row">
<h1>Redux + React</h1>
</div>
<div className="row">
<div className="col s12 m4 l4">
<FormInput
className="input-text"
handleClick={this.props.handleClick}
/>
</div>
</div>
<div className="row">
<FormDisplay
value={this.props.value}
/>
</div>
</div>
</div>
);
}
}
FormApp.propTypes = {
handleClick: React.PropTypes.func,
value: React.PropTypes.string,
};
次は、Input部分のComponent。
export default class FormInput extends React.Component {
constructor(props) {
super(props);
this.send = this.send.bind(this);
}
send(e) {
e.preventDefault();
this.props.handleClick(this.refs.inputText.value);
this.refs.inputText.value = '';
return;
}
render() {
return (
<form>
<input
type="text"
defaultValue=""
ref="inputText"
/>
<button
className="btn"
onClick={this.send}
>
Send
</button>
</form>
);
}
}
FormInput.propTypes = {
handleClick: React.PropTypes.func
};
最後に表示部分のComponent。
export default class FormDisplay extends React.Component {
render() {
return (
<div>{this.props.value}</div>
);
}
}
FormDisplay.propTypes = {
value: React.PropTypes.string
};
Container
ReduxでReactを扱う時に、最初にはまるのはContainerの作成だと思います。
Reduxを使う上では、ReactのComponentは2種類に分けられます。
Container Components
機能に関するコンポーネント。いわゆるFluxでいうContainerです。
主に直接Reduxと連携するコンポーネントで、ReduxのStoreの状態(state)を監視し、またReduxのActionをDispatchする役割を持ち、データを所得したり、stateの更新を行ったりします。
主に親コンポーネントがこの役割を担います。
Presentational Components
見た目に関するコンポーネント。
Container componentsからpropsを通してデータを受け取り、Viewを構築します。
また同様にpropsから受け取ったコールバックを実行します。
前述した、Componentはこちらにあたる。
Container Componentsを実装していきます。
import { connect } from 'react-redux';
import App from './../components/AppComponents';
import FormActions from './../actions/FormActions';
let mapStateToProps = (state) => {
return {
value: state.value
};
};
let mapDispatchToProps = (dispatch) => {
return {
onClick(value) {
console.log(value);
dispatch(FormActions.send(value));
}
};
};
const AppContainer = connect(
mapStateToProps,
mapDispatchToProps
)(App);
export default AppContainer;
状態管理の部分はContainerComponentsで行います。
最後のconnectの部分で、PresentationalComponentsを引数にとり、ReuxとReactを連携します。
エントリーポイント
最後にエントリーポイントを実装します。
/*::::::::::::::::::::::::::::::::::
Components
:::::::::::::::::::::::::::::::::::*/
import App from './containers/App';
import { createStore } from 'redux';
import Reducer from './reducers/App';
import { Provider } from 'react-redux';
/*::::::::::::::::::::::::::::::::::
InitialState
:::::::::::::::::::::::::::::::::::*/
const initialState = {
value: ''
};
/*::::::::::::::::::::::::::::::::::
InitialStore
:::::::::::::::::::::::::::::::::::*/
const store = createStore(Reducer, initialState);
/*::::::::::::::::::::::::::::::::::
InitialDOM
:::::::::::::::::::::::::::::::::::*/
let mountNode = document.getElementById('mountNode');
/*::::::::::::::::::::::::::::::::::
Rendering
:::::::::::::::::::::::::::::::::::*/
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
, mountNode);
InitialStateでstateを初期化し、
InitialStoreで引数にReducerとstateの初期値を渡します。
これによりStoreが作成されます。
最後にContainerComponentsをrenderするのですが、この際にreact-reduxが提供する[Provider]コンポーネントを親としてrenderします。
Providerコンポーネントはパラメータとして、storeをとり、ここに作成したstoreを与える事で、PresentationalComponentsのpropsの値としてstateが使えるという仕組みです。
終わり
Redux自体は簡単なものの、ReactとReduxの連携の部分が少しデリケートで戸惑いましたが、
簡単アプリの作成に成功しました。
データがAction->(Dispatch)->Reducer->Storeと一方向になる事で、大・中規模のシステムでも対応しやすくなるのではないかと思います。
次はFluxをもう少し掘り下げての勉強と、Reduxでの非同期通信(Actionに記載?)周りを調査したいと思います。