はじめに
前回の続きです。
公式チュートリアルのComponents and Props
からやっていきます。
業務時間中にちまちま書いているんですが、なんとかモチベーションを落とさずに継続できています・・・!
やってみる
Components and Props
Vue.js
でもやるコンポーネント分割と、コンポーネント間のデータの受け渡しのあたりの話ですね。
Part1でも若干触れましたが、基本的にclass
で定義するようです。babel
を使わない場合はfuntion
で定義してもいいそうですが、class
の方が色々と都合が良いとのこと。
こんな感じで使うんですね。コンポーネントを埋め込む際は<Welcome>
のように先頭を大文字にするのがお作法のようです。
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
class App extends extends React.Component {
render() {
return (
<div>
<Welcome name="Tanaka" />
<Welcome name="Sato" />
</div>
)
}
}
ReactDOM.render(
<App/>,
document.getElementById('root)
)
他には1コンポーネントが複雑化した際の分割方法が書かれてありましたが、Vue
と同じような感じですね。
また、受け渡されるprops
はreadonlyだとのことです。これもVue.js
では親のコンポーネントの値を変更するのは推奨されていませんでしたし、一緒ですね。
State and Lifecycle
これまではReactDOM.render()
によって描画を更新する方法しか知りませんでしたが、この章ではそれ以外の方法を教えてくれるそうです。
時計のコンポーネントを作るとしたら、これまでの知見だけでは
function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('root')
);
}
setInterval(tick, 1000);
こんな感じになりますが、これだと毎回ReactDOM.render()
でアプリ全体の描画を更新することになってしまいます。
本当はClock
の内部で時刻を勝手に更新していくような作りにしたい・・・。
そこで、state
をコンポーネントに定義しましょう。Vue
で言うところのdata
ですね。
state
を使うとこんな感じにかけるそうです。
DOMの定義部分ではthis.state
でコンポーネントのstate
内の値を見にいって、constructor
内で渡されたprops
をstate
に保存するような動作にしています。
Vue
で言い換えるとconstructor()
がcreated()
でstate
がdata
のイメージですね。
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
続いて、時刻を更新する処理を作ります。Vue
だとmounted
でsetInterval
を入れてbeforeDestroy
でclearInterval
するイメージですかね。
こんな感じにかけるそうです。想像通りですね。一度constructor
でstate
を定義すれば、クラスにプロパティを足したりするのは自由らしいです。以下の例ではtimerID
を後から追加していますね。
state
の更新はsetState
を使う必要があるそうです。。Vue
だとmethods
の中にコンポーネント内関数を定義していましたが、react
だとtick()
を定義しているようにクラス内に自由に定義して良さそうですね。もちろんReact.Component
の関数をオーバーライドしないように注意しなければいけ無さそうですが。
処理が呼ばれる順番はコメントに書きました。
class Clock extends React.Component {
// 2
constructor(props) {
super(props);
this.state = {date: new Date()};
}
// 4
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
// 6
componentWillUnmount() {
clearInterval(this.timerID);
}
// 5
tick() {
this.setState({
date: new Date()
});
}
// 3
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
// 1
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
state
を変更する際はsetState()
を使う必要がありますが、state
やprops
は非同期で更新されるので以下のように書く必要があると。
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
setState
はシャローマージ?なので、既存のプロパティを壊さず一部を置換したりできると。
こんな感じに書いても、this.setState({comments})
でstate.posts
が消えることは無いと説明しています。
constructor(props) {
super(props);
this.state = {
posts: [],
comments: []
};
},
componentDidMount() {
fetchPosts().then(response => {
this.setState({
posts: response.posts
});
});
fetchComments().then(response => {
this.setState({
comments: response.comments
});
});
}
残りの部分は、state
がコンポーネント内にカプセル化していて、props
は常に子コンポーネントに流れる単方向データフローであると説明しています。この辺りもVue
と同じですね。
終わりに
今回はコンポーネントとライフサイクルを学びましたが、なんとなくReact
でアプリを作る道筋が見えてきました。基本的な概念はVue
と変わらないですし、意外とすんなり受け入れられそうですね。次回はHandling Events
からやっていきます。