Reactの肝であるコンポーネントの基本についてまとめたいと思います。
React+TypeScriptの環境構築については前回の記事を参照。
React: v15.6.1
コンポーネント
Reactはコンポーネント指向に基づいたライブラリです。
コンポーネントと呼ばれるUI部品を定義し、それらを組み合わせることでアプリケーションを構築します。
まずは細かいところは置いておいてごく簡単なコンポーネントを定義してみます。
コンポーネントのファイルを置くディレクトリを作成。
1 | $ mkdir ./src/components |
コンポーネントMyComponentを定義し、MyComponentをルートコンポーネントのApp内に配置します。
1 2 3 4 5 6 7 8 9 10 11 12 13 | import * as React from 'react' ; class MyComponent extends React.Component { render() { return ( <div> Hello </div> ); } } export default MyComponent; |
1 2 3 4 5 6 7 8 9 10 11 12 13 | import * as React from 'react' ; import './App.css' ; import MyComponent from './components/MyComponent' ; class App extends React.Component { render() { return ( <MyComponent /> ); } } export default App; |
React.Componentを継承し、renderメソッドの戻り値としてコンポーネントの要素をUIを定義します。
TypeScriptコード中にHTMLタグっぽいものが書けるのが少々気持ち悪いですが、
これはJSXと呼ばれる構文で、JSXを用いることでコンポーネントの定義が簡潔に書けます。
なおJSXを含むファイルは拡張子が.jsx(今回はTypeScriptなので.tsx)になります。
定義したコンポーネントは、親コンポーネントの中に入れ子してHTMLタグのように配置することができます。
props,state
Reactのコンポーネントにはporpsとstateという概念があります。
props
propsは親コンポーネントからそのコンポーネント渡されるパラメータです。
propsはイミュータブルなobjectであり、変更はできません。
MyComponent.tsxとApp.tsxを次のように修正してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import * as React from 'react' ; interface MyComponentProps { greeting: string; } class MyComponent extends React.Component<MyComponentProps, {}> { render() { return ( <div> { this .props.greeting} </div> ); } } export default MyComponent; |
1 2 3 4 5 6 7 8 9 10 11 12 | import * as React from 'react' ; import MyComponent from './components/MyComponent' ; class App extends React.Component { render() { return ( <MyComponent greeting= "Hello!!" /> ); } } export default App; |
propsの値は親コンポーネントで属性値のようにして指定します。
またTypeScriptを使っている場合はpropsに対してinterfaceで型を定義することで、
親コンポーネントでpropsの値をちゃんと指定しているか静的にチェックすることができます。
Functional Components(Stateless Components)
後述するstateを持たないコンポーネントは上記のclass構文とは別に、
propsのみを引数にもつ純関数として定義することも可能です。
上記のMyComponentをFunctional Componentとして定義すると次のようになります。
1 2 3 4 5 6 7 | function MyComponent(props: MyComponentProps) { return ( <div> {props.greeting} </div> ); } |
またアロー関数を使えば次のようにも書けます。
1 2 3 4 5 | const MyComponent = (props: MyComponentProps) => ( <div> {props.greeting} </div> ); |
stateが必要ないコンポーネントはパフォーマンスの観点からFunctional Componentsを用いることが推奨されます。
state
コンポーネントが持つ状態を表すのがstateです。
stateはミュータブルなobjectであり、変更が可能です。
MyComponentを次のように変更してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | ... class MyComponent extends React.Component<MyComponentProps, MyComponentState> { constructor(props: MyComponentProps) { super (props); this .state = { count: 1 }; setInterval( () => this .countUp(), 1000 ); } countUp() { this .setState({ count: this .state.count + 1 }); } render() { return ( <div> { this .props.greeting} <div> count: { this .state.count} </div> </div> ); } } ... |
constructorでstateの初期値を設定し、その後1秒ごとに更新しています。
stateの更新にはsetStateメソッドを用います。
classを用いた定義とFunctionalの定義の使い分けですが、
コンテナとして機能する上位のコンポーネントにのみclass構文を用いてstateを持たせ、
その他の子コンポーネントはFunctionalに定義しstateを持たせない、と捉えればひとまず十分だと思います。
WEBアプリケーション関連 人気連載リンク
基礎からPHPWEBアプリ解発を学ぶなら・・
PHP基礎 連載
より実践的なWEBアプリ開発講座!Bootstrap活用を学ぶなら・・
魁!小野の塾 連載