前回の記事でReactが使える環境は作ったので、
まずはStateとPropsをちゃんと使ってリストを作ってみる。
ListBaseにStateを持たせて、
ListにPropsとして渡して、
ListRecordを描写してみようかなと。
StateとPropsについて
State
- そのコンポーネントが持っている状態
- mutable data (可変のデータ)
- maintained by component (コンポーネントによって保持)
- should be considered private (プライベートであるべき)
this.setState({state1: "value1",state2: "value2"});
のようにコンポーネント作成後任意のタイミングで入れられる。
初期値は
this.state = {state1: "value1",state2: "value2"}
こんな感じで入れてもいい。
Props
- 親コンポーネントから渡されたプロパティ
- immutable data (不変のデータ)
- passed in from parent (親から渡される)
- can be defaulted & validated (デフォルト値の設定と検証が可能)
<Component props1="value1" props2="value2">
のようにコンポーネント作成時に入れられる。
作ってみた
構成は前回と同じ。
"dependencies": {
"react": "^15.4.2",
"react-dom": "^15.4.2"
},
"devDependencies": {
"babel-core": "^6.24.0",
"babel-loader": "^6.4.1",
"babel-preset-es2015": "^6.24.0",
"babel-preset-react": "^6.23.0",
"webpack": "^2.2.1"
}
こんな感じ。
最初の呼び出し元としてapp.jsxを作る。
前回はindex.html内でrenderを呼んでいたが、
app.jsx自体にやらせることにした。
app.jsx
import React from 'react';
import ReactDom from 'react-dom';
import ListBase from './listbase.jsx';
ReactDom.render(
<ListBase/>,
document.getElementById('listbase'));
なので、webpack.config.jsは、app.jsxをベースとしてapp.jsを作る様に
webpack.config.js
const path = require('path');
module.exports = {
entry: {
app: './src/app.jsx'
},
output: {
path: './public',
filename: '[name].js'
},
module: {
loaders: [
{
loader: 'babel-loader',
exclude: /node_modules/,
test: /\.js[x]?$/,
query: {
cacheDirectory: true,
presets: ['react', 'es2015']
}
}
]
}
};
なので、index.htmlはapp.jsを呼び出すだけ。
index.html
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="listbase"></div>
<script src="public/app.js"></script>
</body>
</html>
ここからはさくっと。
呼び出されるListBaseコンポーネントはStateデータをコンストラクターで持ち、
<List data={this.state.data}/>
として子コンポーネントに渡すだけ。
listbase.jsx
import React, {Component} from 'react'
import List from './list.jsx';
export default class ListBase extends Component {
constructor(props) {
super(props);
this.state = {
data: [
{
id: 1,
name: 'tanaka'
}, {
id: 2,
name: 'yoshida'
}
]
};
}
render() {
return (<List data={this.state.data}/>);
}
}
渡されたdataを、
Listコンポーネント内でループしてListRecordコンポーネントをdataの数だけ生成する。
listrecord.js
import React, {Component} from 'react'
import ListRecord from './listrecord.jsx';
export default class List extends Component {
render() {
var rows = this.props.data.map(function(row) {
return (<ListRecord data={row} key={row.id}/>);
});
return (
<ul>
{rows}
</ul>
);
}
}
で、最終的にListRecordがPropsを描写する。
listrecord.jsx
import React, {Component} from 'react'
export default class ListRecord extends Component {
render() {
return (
<li>
{this.props.data.id}:{this.props.data.name}
</li>
);
}
}
npm run webpack -pして、
index.htmlを表示してみる!
1:tanaka
2:yoshida
おお!表示された。
PropsはImmutableなので、値を変える時はListBase自体で
setStateし直すということか。
それで、
<ListRecord data={row} key={row.id}/>
keyを比較して変更のあったものを再描写してる感じかな。
(最初keyがなくて怒られた苦笑)
うん、なんとなくだけどわかってきた。
ES6で書くとfunction(){}とかなくてJSっぽくなくていい!
DebugしにくいからReactDevTool入れてちゃんとサーバー上で動かした方がいいな。
あとコンポーネントとして、
こうやってマイクロな感じで作ったコンポーネントを組み合わせて呼び出して、
全部JSじゃなくて必要なところだけコンポーネントを埋め込んでリッチにする方が、
DOM全部管理するより開発しやすいんじゃないかなーと思った。
ここまでやって、次はFluxとかでのデータフロー管理なわけかな。
ちょっとずつ進んでる感。