43. Learn React.js in 5 minutes
【所要時間】
4時間47分(2018年8月27日)
【概要】
Reactの基本をおさらい
【要約・学んだこと】
- componentとはReactのbuilding blockのこと。
- componentはHTML, CSS, JSや、componentに指定した内部データを集めたものと考えることができる。
- componentは純粋なJavaScriptか、JSXで定義することができる。
- JSXを使う方が一般的。
- JSXを使う場合は、JSXをJavaScriptに変換するcompile stageが必要。
- User Interfaceを構築するのに Reactが便利なのは、componentの親 componentからデータを受け取ることができ、component自体にデータを含むことができることだ。
- Twitterのプロフィール画面だ。このページをReactで作ると、異なるセクションを異なるcomponents(色線で囲われた部分)に分解する。
- componentはcomponentの内部に存在することもできる。
- 左側のピンクを UserInfo componentと名付ける。UserInfo componentの中には、オレンジのUserImages componentがある。
- この親子関係が動作するには、親componentであるUserInfo componentが、自身と子componentであるUserImages component両方のデータの”state”が存在する場所になる必要がある。
- 子componentに、親componentのデータの一部を使いたい場合、attributeとして子componentにデータをわたす。
この場合、ユーザーが持つ全ての画像(現在Userinfo componentにある)を、UserImages componentに渡す。 - この親子階層は、データの管理を比較的シンプルにする。なぜならデータがどこに存在するか正確に知っているからで、そのデータを他の場所で操作をするべきではない。
下記の内容がReactの基礎的な側面だ。これらとその目的を理解する。
JSX — Allows us to write HTML like syntax which gets
transformed to lightweightJavaScript objects.Virtual DOM — A JavaScript representation of the actual
DOM.React.Component — The way in which you create a new component.render (method) — Describes what the UI will look like for
the particular component.ReactDOM.render — Renders a React component to a DOM node.state — The internal data store (object) of a component.constructor (this.state) - The way in which you establish
the initial state of a component.setState — A helper method used for updating the state of a
component and re-rendering the UIprops — The data which is passed to the child component
from the parent component.propTypes — Allows you to control the presence, or types of
certain props passed to the child component.defaultProps — Allows you to set default props for your component.Component LifeCycle
- componentDidMount — Fired after the component mounted
- componentWillUnmount — Fired before the component will unmount
- getDerivedStateFromProps - Fired when the component mounts and
whenever the props change. Used to update the state of a
component when its props changeEvents
- onClick
- onSubmit
- onChange
Creating your First Component (JSX, Virtual DOM, render, ReactDOM.render)
- React componentを作るには、ES6 classを使う必要がある。
import React from 'react'
import ReactDOM from 'react-dom'class HelloWorld extends React.Component {
render() {
return (
<div>Hello World!</div>
)
}
}ReactDOM.render(<HelloWorld />, document.getElementById('root'));
- classの中にあるメソッドはrenderだけだ。
- 全てのcomponentはrenderメッソドを持たなければならない。なぜならrenderはcomponentのUser Interfaceを記述しているからだ。
- この例では、このcomponentがrenderされる画面に、Hello World!が表示される。
- ReactDOM.renderは、2つのargumentを持つ。最初のargumentはrenderしたいcomponent, 2つ目のargumentはcomponentをrenderするDOM nodeだ。
- ここではReact.render ではなく、ReactDom.renderを使っている。これはReact.14によって、Reactをよりモジュラー化するために作られた変更だ。ReactがただのDOM elementを使うより、多くのことがrenderできると考えれば良い。
- 上記の例では、ReactにHello World componentを取得し、rootのIDのelementにrenderするように指示している。Reactの親子関係は、通常アプリ内で一度だけReactDOM.renderを使わなければならない。なぜなら、大抵の親componentをrenderすることで、全ての子componentもまたrenderされるからだ。
- HTMLをJSに投げるのが奇妙に感じ、そのことについて詳しく知りたいなら this link を参照。
- JSXはHTMLのようなsyntaxを軽量なJSに変換してくれるもの。ReactはこれらのJS objectを取得し、そこからvirtual DOM, actual DOM のJS表現を形成することができる。
class HelloWorld extends React.Component {
render() {
return React.createElement("div", null, "Hello World");
}
}
- JSXからJS変換フェーズを省略して、上記のようなReact componentを書くことができる。しかし、いくらかトリッキーだ。
- Reactは現在のvirtual DOM(いくらかのデータ変更が計算された後)と、以前のvirtual DOM(データ変更が計算される前)の違いを追い続ける。
- Reactは古いvirtualDOM新しいvirtual DOMの変更を隔離し、actual DOMで必要な変更のみを更新する。
- また、actual DOMの操作は遅い。Reactはvirtual DOMを追い続け、必要な時だけactual DOMの更新をするので、actual DOMの操作を最小化できる。
- 通常、UIはstateの管理を難しくするstateをたくさん持つ。virtual DOMをrenderするたびに、stateの変更も起こる。Reactを使うとアプリのstateを簡単に考えることができる。
- 例えば、
アプリのstateを変更するイベント
→re-render virtual DOM
→以前のvirtual DOMと新しいvirtual DOMが異なる
→必要なreal DOMだけ更新する。 - Part2では、このJSXからJSへの変換をするWebpackとBabelを紹介する。
✅ JSX — Allows us to write HTML like syntax which gets
transformed to lightweightJavaScript objects.✅ Virtual DOM — A JavaScript representation of the actual
DOM.✅ React.Component — The way in which you create a new component.✅ render (method) — Describes what the UI will look like for
the particular component.✅ ReactDOM.render — Renders a React component to a DOM node.state — The internal data store (object) of a component.constructor (this.state) - The way in which you establish
the initial state of a component.setState — A helper method used for updating the state of a
component and re-rendering the UIprops — The data which is passed to the child component
from the parent component.propTypes — Allows you to control the presence, or types of
certain props passed to the child component.defaultProps — Allows you to set default props for your component.Component LifeCycle
- componentDidMount — Fired after the component mounted
- componentWillUnmount — Fired before the component will unmount
- getDerivedStateFromProps - Fired when the component mounts and
whenever the props change. Used to update the state of a
component when its props changeEvents
- onClick
- onSubmit
- onChange
Adding State to your Component (state)
- stateについて。それぞれのcomponentは自身のstateを管理し、必要であれば子componentに渡す能力を持つ。
- Twitterの例に戻ると、ピンクのUserInfo componentはユーザーのインフォメーションのstateを管理する責任がある。
もし他のcomponentがこのstateやデータを必要としているが、そのstateがUserInfo componentの直接の子供でなければ、UserInfoと他のcomponentの直接の親となる別のcomponent(もしくはstateを求めるcomponent)を作る。 - つまり、multi-component階層をもつなら、一般的に共通の親componentがstateを管理し、それをprop経由で子componentに渡す。
自身の内部stateを持つcomponentを見てみよう。take a look
class HelloUser extends React.Component {
constructor(props) {
super(props)this.state = {
username: 'tylermcginnis'
}
}
render() {
return (
<div>
Hello {this.state.username}
</div>
)
}
}
- constructorメソッドとは”componentのstateをセットする方法”だ。つまり、constructor内部にあるthis.stateに置いたデータは、componentのstateの一部となる。
- 上記のコードではusernameの記録を追うようにcomponentに伝えている。usernameは{this.state.username}によって、componentの内部で使うことができる。
これはrenderメソッドと全く同じだ。 - componentには内部stateを修正する能力が必要だ。setStateによってそれができる。
Signal to notify our app some data has changed
→ Re-render virtual DOM
→Diff previous virtual DOM with new virtual DOM
→Only update real DOM with necessary changes.
この “signal to notify our app some data has changed” は実際はただのsetStateだ。setStateがコールされた時はいつでもvirtual DOMをre-renderし、異なるアルゴリズムを実行し、必要なreal DOMを更新する。
- 下記のコードのsetStateではいくつかのeventを導入している。
- input boxを持ち、そこに誰かがタイプすると、自動でstateを更新し、usernameを変える。
class HelloUser extends React.Component {
constructor(props) {
super(props)this.state = {
username: 'tylermcginnis'
}this.handleChange = this.handleChange.bind(this)
}
handleChange (e) {
this.setState({
username: e.target.value
})
}
render() {
return (
<div>
Hello {this.state.username} <br />
Change Name:
<input
type="text"
value={this.state.username}
onChange={this.handleChange}
/>
</div>
)
}
}
- handleChangeメソッドは、input boxにユーザーがタイプするたびにコールを受け取る。handleChangeがコールされると、setStateにinput boxにタイプされた内容をusernameに再定義するようコールする。
- setStateがコールされると、Reactは新しいvirtual DOMを作り、diffを実行し、 DOMを更新する。
- renderメソッドを見てみると、input fieldが追加された。
input fieldのタイプは明らかにtextになる。
valueは当初getInitialStateメソッドとして定義されたusername valueとなり、handleChange メソッドで更新される。 - onChangeはinput boxのvalueが変わるたびに指定するメソッドを呼ぶ。
この場合、handleChangeメソッドを指定した。 - 上記のコードは下記のようなプロセスで動作する。
userがinput boxにタイプする
→ handleChangeが呼び出される
→ componentのstateが新しいvalueにセットされる
→ Reactがvirtual DOMをre-renderする。
→ React Diffが変わる
→ Real DOMが更新される
✅ JSX — Allows us to write HTML like syntax which gets
transformed to lightweightJavaScript objects.✅ Virtual DOM — A JavaScript representation of the actual
DOM.✅ React.Component — The way in which you create a new component.✅ render (method) — Describes what the UI will look like for
the particular component.✅ ReactDOM.render — Renders a React component to a DOM node.✅ state — The internal data store (object) of a component.✅ constructor (this.state) - The way in which you establish
the initial state of a component.✅ setState — A helper method used for updating the state of a
component and re-rendering the UIprops — The data which is passed to the child component
from the parent component.propTypes — Allows you to control the presence, or types of
certain props passed to the child component.defaultProps — Allows you to set default props for your component.Component LifeCycle
- componentDidMount — Fired after the component mounted
- componentWillUnmount — Fired before the component will unmount
- getDerivedStateFromProps - Fired when the component mounts and
whenever the props change. Used to update the state of a
component when its props changeEvents
- onClick
- onSubmit
- onChange
Receiving State from Parent Component (props, propTypes, getDefaultProps)
- propsとは、親componentから子componentに渡されたデータのこと。
- 特定のデータを使う必要がある最上部の親componentのstateを扱う。
- もしデータを必要とする子componentを持っていたら、propsでデータを下ろす。
Here’s a very basic example of using props.
class HelloUser extends React.Component {
render() {
return (
<div> Hello, {this.props.name}</div>
)
}
}ReactDOM.render(
<HelloUser name="Tyler"/>,
document.getElementById('root')
);
- 9行目に”Tyler”と呼ばれる属性がある。componentは、{this.props.name} が”Tyler”を取得するのに使うことができる。
もう一歩進んだ下記の例では、2つのcomponentがある。1つは親、もう1つが子である。親はstateを置い続け、stateの一部をpropsとして子に下ろす。
Parent Component:
class FriendsContainer extends React.Component {
constructor(props) {
super(props)this.state = {
name: 'Tyler McGinnis',
friends: [
'Jake Lingwall',
'Sarah Drasner',
'Merrick Christensen'
]
}
}
render() {
return (
<div>
<h3> Name: {this.state.name} </h3>
<ShowList names={this.state.friends} />
</div>
)
}
}
- これはinitial stateを持つ。initial stateの一部を他のcomponentに渡す。
- 大部分の新しいコードはこれの子componentからくる。
Child Component:
class ShowList extends React.Component {
render() {
return (
<div>
<h3> Friends </h3>
<ul>
{this.props.names.map((friend) => <li>{friend}</li>)}
</ul>
</div>
)
}
}
- renderメソッドからretrunを受け取ったコードが、real DOMの外観を表現している。
- mapは新しいarrayを作り、array内の各項目に対してコールバックfunctionを呼び出し、各項目のコールバックfunctionを呼び出した結果を新しいarrayに埋める。
For example,
const friends = [
'Jake Lingwall',
'Sarah Drasner',
'Merrick Christensen'
];const listItems = friends.map((friend) => {
return "<li> " + friend + "</li>";
});console.log(listItems);
- The console.log は
["<li> Jake Lingwall</li>", "<li> Murphy Randall</li>", "<li> Merrick Christensen</li>"]
をreturnする。 - 新しいarrayを作り、<li> </li>をオリジナルのarrayの各項目に加えた。
- 上記の子componentは、名前をマッピングし、<li>タグのペアでそれぞれの名前を囲み、listItems variableに保存した。
- renderメソッドは全てのfriendsと順序をつけられていないlistを返す。
別のサンプルを見てみよう。
- データがどこにあっても、操作したいデータの場所が正確であることを理解することが重要。
- これによって、データを簡単に予想することができる。
- 特定のデータの全てのgetter/setterメソッドは、そのデータが定義された同じコンポーネント内に常に存在する。
- もしdataが存在する場所以外で操作する必要があるなら、getter/setterメソッドでpropsとしてそのcomponentに渡す必要がある。下記がその例だ。
class FriendsContainer extends React.Component {
constructor(props) {
super(props)this.state = {
name: 'Tyler McGinnis',
friends: [
'Jake Lingwall',
'Sarah Drasner',
'Merrick Christensen'
],
}this.addFriend = this.addFriend.bind(this)
}
addFriend(friend) {
this.setState((state) => ({
friends: state.friends.concat([friend])
}))
}
render() {
return (
<div>
<h3> Name: {this.state.name} </h3>
<AddFriend addNew={this.addFriend} />
<ShowList names={this.state.friends} />
</div>
)
}
}
- setStateを呼び出す方法に、addFriendメソッドがある。
- objectにそれを渡す代わりに、stateを渡されたfunctionを渡している。
- 以前のstate(friends arrayでやったこと)にあるcomponentの新しいstateをセットするたびに、setStateを現在のstateを持つfunctionに渡す。そして新しいstateにデータを結合しreturnする。Check it out here.
class AddFriend extends React.Component {
constructor(props) {
super(props)this.state = {
newFriend: ''
}this.updateNewFriend = this.updateNewFriend.bind(this)
this.handleAddNew = this.handleAddNew.bind(this)
}
updateNewFriend(e) {
this.setState({
newFriend: e.target.value
})
}
handleAddNew() {
this.props.addNew(this.state.newFriend)
this.setState({
newFriend: ''
})
}
render() {
return (
<div>
<input
type="text"
value={this.state.newFriend}
onChange={this.updateNewFriend}
/>
<button onClick={this.handleAddNew}> Add Friend </button>
</div>
)
}
}class ShowList extends React.Component {
render() {
return (
<div>
<h3> Friends </h3>
<ul>
{this.props.names.map((friend) => {
return <li> {friend} </li>
})}
</ul>
</div>
)
}
}
- このコードはnameをfriends listに加える能力があることをのぞいて、先ほどの例とほぼ同じだ。加えようとしているnew frinedを管理する新しいAddFriend componentをどうやって作ったかに着目する。
- その理由は、親component(FriendContainer)が加えているnew friendを気にしないからだ。全体として全てのfriends(friends array)を気にしているだけだ。
しかし、それを気にするcomponentからだけがデータを操作できるルールに固執しているので、propとしてAddFriend componentに、addFriendメソッドを渡し、handleAddNewメソッドがコールされると、それをnew friendと呼ぶ。 - propsに関する他のReactの機能として、propTypesとdefaultPropsがある。
- prop-typesは子componentに渡す特定のpropsの存在、またはtypeを管理する。
- propTypesを使えば、特定のpropsが必要とされるか、特定のpropsが特定のtypeであるかを指定できる。
- React15以降、propTypesはReact packageに含まれない。npm install prop-types でインストールする必要がある。
- defaultPropsは、特定のpropsがcomponentに渡されない場合に、default(もしくはbackup) valueを指定することができる。
- 先ほどのcomponentsを、propTypesを使い、addFriendがfunctionで、AddFriend componentに渡されることを要求した。
- また、defaultPropsを使い、もしfriendsのarrayがなければ、ShowList componentが与えられるように指定し、それがempty arrayのdefaultになるようなる。
import React from 'react'
import PropTypes from 'prop-types'class AddFriend extends React.Component {
constructor(props) {
super(props)this.state = {
newFriend: ''
}
}
updateNewFriend(e) {
this.setState({
newFriend: e.target.value
})
}
handleAddNew() {
this.props.addNew(this.state.newFriend)
this.setState({
newFriend: ''
})
}
render() {
return (
<div>
<input
type="text"
value={this.state.newFriend}
onChange={this.updateNewFriend}
/>
<button onClick={this.handleAddNew}> Add Friend </button>
</div>
)
}
}AddFriend.propTypes: {
addNew: PropTypes.func.isRequired
}class ShowList extends React.Component {
render() {
return (
<div>
<h3> Friends </h3>
<ul>
{this.props.names.map((friend) => {
return <li> {friend} </li>
})}
</ul>
</div>
)
}
}ShowList.defaultProps = {
names: []
}✅ JSX — Allows us to write HTML like syntax which gets
transformed to lightweight JavaScript objects.✅ Virtual DOM — A JavaScript representation of the actual
DOM.✅ React.Component — The way in which you create a new component.✅ render (method) — Describes what the UI will look like for
the particular component.✅ ReactDOM.render — Renders a React component to a DOM node.✅ state — The internal data store (object) of a component.✅ constructor (this.state) - The way in which you establish
the initial state of a component.✅ setState — A helper method used for updating the state of a
component and re-rendering the UI✅ props — The data which is passed to the child component
from the parent component.✅ propTypes — Allows you to control the presence, or types of
certain props passed to the child component.✅ defaultProps — Allows you to set default props for your component.Component LifeCycle
- componentDidMount — Fired after the component mounted
- componentWillUnmount — Fired before the component will unmount
- getDerivedStateFromProps - Fired when the component mounts and
whenever the props change. Used to update the state of a
component when its props change✅ Events
- onClick
- onSubmit
- onChange
Component LifeCycle
- それぞれのcomponentは様々な点で使い勝手のある、lifecycle eventを持つ。
例えば、initial renderのajax requestを作る場合、どこでそれをすればいいのだろうか。もしくは、propsが変わるたびに何かのlogicを実行したい場合、どうすればいいのか。異なるdifferent lifecycle eventはそれら両方の答えになる。
class App extends React.Component {
constructor(props) {
super(props)this.state = {
name: 'Tyler McGinnis'
}
}
componentDidMount(){
// Invoked once the component is mounted to the DOM
// Good for making AJAX requests
}
static getDerivedStateFromProps(nextProps, prevState) {
// The object you return from this function will
// be merged with the current state.
}
componentWillUnmount(){
// Called IMMEDIATELY before a component is unmounted
// Good for cleaning up listeners
}
render() {
return (
<div>
Hello, {this.state.name}
</div>
)
}
}
- componentDidMount
initial renderの後に1度呼び出す。このメソッドが呼び出される時、componentはすでに呼び出されているため、必要であればコールによってvirtual DOMへのアクセスする。 - this.getDOMNode()
これはAJAXを作った場所にあるlifecycle eventで、データで取得する。 - componentWillUnmount
このlife cycleはcomponentがDOMからマウント解除される直前に呼び出される。ここで必要なクリーンアップができる。 - getDerivedStateFromProps
渡されているpropsに基づいてcomponentのstateを更新する必要があることもある。これがここで行うlifecycleメソッドだ。それがpropsとstateを渡され、returnするobjectが現在のstateに結合される。
さらに深くReactを学びたいならばhttps://tylermcginnis.com/courses/react-fundamentals/ を参照。
【わからなかったこと】
Component LifeCycle の項目がどういう場面で必要になるのかよくわからないが、のちに必要な場面出てくると思われるのでその時に学んだ方がいいと思いました。
【感想】
ページをcomponentで細かく分割し、必要なデータを親子関係で受け渡す。また、変更の必要がある箇所のみ更新するというイメージ。