はじめに
本記事は初めてreactを触る人向けに書いています。
reactってなんだ?どう書いたらいいの?という初歩的な内容をまとめています。
※ライフサイクルの説明は長くなるので割愛させていただきました。
以下の記事が秀逸なのでこちらを紹介させていただきます。
https://qiita.com/Julia0709/items/3c3fc8d29fd2e56ed7a9
Reactとは
FaceBookによって開発されたフロントエンドフレームワークで、Reactはリアクティブ・プログラミングで、値がどのように伝わっていくかを重視しています。
従来のjsとの違いとして、表示を更新するとき予め用意した値を設定しておけば元の値を変更すると表示も自動的に更新されます。
また、Reactは直接DOM操作するのではなく、プログラム的に仮のDOMを構築してそれを操作します。
これを仮想DOMといいます。この仮想DOMは通常のDOMに比べて軽くて高速です。
React開発に必要なもの
- Node.js: JavaScriptの実行環境(必須)
- Create React App: Node.jsに組み込まれたnpxを使ってターミナルで
npx create-react-appフォルダ名
を入力して実行(スターターキットのようなもの。自分で環境構築ができる場合は不要) - React Developer Tools: デバッグ用ツール。Reactを使った開発をするならあった方が良い。(ブラウザの拡張ツール)
※トランスパイラ等はCreate React Appで用意されているのでここでは省略します。
JSX
Reactでは、HTMLのタグを直接JavaScriptのスクリプトに記述する仕組みを持っています。これをJSXといいます。JSXを使用することでようやくReactを使うメリットを実感できると思います。
JSXを使った記述と使わない記述の違いを見ていきます。
ブラウザに表示されているここに表示されます。をHello Worldに表示を変更させます。
<div id="root">ここに表示させます。</div>
JSXなし
import React from 'react'; //インストールしたreactを使うためにインポートしています。(今回はcreate-react-appで必要な物をまとめてインストールしているので、新しくインストールする必要はありません。)
const rootId = document.querySelector('#root');
const element = React.createElement (
'p', {}, 'Hello World'
);
ReactDOM.render(element, rootId);
JSX
import React from 'react';
ReactDOM.render(<p>Hello World</p>,document.getElementById('root'));
JSXを使用した方が記述量が減り、可読性が上がるのが分かりますね。
JSXを使わない場合以下のReact.createElementという箇所で仮想DOMのエレメントを作成しています。
const element = React.createElement (
'p', {}, 'Hello World'
);
React.createElementの第一引数にはタグ名、第二引数にはそのエレメントに用意される属性オブジェクト(必要ない場合はからのオブジェクトを指定)、第三引数には作成するエレメントの内部に組み込まれるものを用意します。
まとめると以下のようになります。
React.createElement(タグ名、属性、中に組み込む物);
作成した仮想DOMエレメントをReactDOMオブジェクトのrenderメソッドを使いレンダリングします。
JSXを使う場合はシンプルに
pタグ
で表示したいHello Worldを囲い、renderメソッドを使いレンダリングしています。
そして、ブラウザにアクセスすると差分を検知し、divタグ
で囲われたここに表示されます。がHello Worldに書き換わっていると思います。
デバッグツールで確認すると以下のように変更されていることが確認できます。これはJSXで記述した方でも同じように表示されるはずです。
<div id="root"><p>Hello World</p></div>
どちらの書き方が良いかは一目瞭然ですね。
JSXを使わないと表示するタグをcreateElementで1つずつ作成していかなければなりません。その煩雑さを解消するためにJSXを使うという訳です。
しかし、JSXはbabelによってトランスパイルされることで初めて成り立っています。どのようにbabelが変換しているかを頭でイメージできるかできないかでは習熟度が全然違ってきます。
コンポーネント
Reactではコンポーネント毎に管理する分割統治の概念があります。
ここでは基本的なコンポーネントの書き方を書いていきます。
//index.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import App from '.Components/app'; //Appコンポーネントがある階層を指定してインポートする。
ReactDOM.render(<App />,document.getElementById('root'));
//app.js
class App extends React.Component {
render() {
return <p>Hello World</p>
}
}
export default App;//Appコンポーネントを他ファイルでインポートできるようにエクスポートする。
上記ではReact.Componentを継承したAppクラスを作って、**render()メソッドでJSXをreturnしています。これによりReactDOM.render()**から呼び出した際にJSXで出力されます。
このようにコンポーネント化することにより以下のメリットがあります。
- 再利用性が高い
- 保守性が高い
- 管理がしやすい
- アトミックデザインと相性が良い(パーツ・コンポーネント単位で定義していくUIのデザイン手法)
コンポーネントはスクリプト内に複数のコンポーネントを書いて、組み合わせて表示を作成することができます。
また、上記の例では敢えてファイルを複数に分ける想定で書いていますが、これはコンポーネントが複数存在する想定での書き方で、今回のようにテキストを表示させるだけの場合は1ファイルで完結させた方がシンプルで良いでしょう。
状態管理
Reactでは保管した状態を操作するために以下のようなモノが用意されています。
- props
親コンポーネントから渡されたプロパティです。propsはimmutableなデータで、変更ができません。 - state
コンポーネントが持っている状態です。stateはmutableなデータで変更することができます。
stateの初期値を受け取るにはthis.stateで値を取り出します。
簡単に説明すると、親コンポーネントで保持しているstateの値を子コンポーネント側でpropsで受け取ります。stateを更新することでコンポーネントの表示を変えたりしています。
以下のようにapp.jsを書き換えます。
//app.js
import React, { Component } from 'react';
class App extends Component {
constructor(props){
super(props);
this.state = {
clickCount: 0
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState((state) => ({
clickCount: state.clickCount + 1
}));
}
render(){
return(
<div>
<button onClick={this.handleClick}>ButtonCount</button>
<h1>{this.state.clickCount}</h1>
</div>
);
}
}
export default App;
クリックしたら値が更新され数字が1つずつ増えていきます。
最初に画面に表示されている0の数字はconstructorで設定しており、ステートの値はオブジェクトリテラルとして記述します。
これでthis.stateの中から設定した値を取り出して利用することができるようになりました。
初期状態として表示される0はconstructorで設定した0が表示されているということです。
そしてButtonCountボタンを押下すると、<h1>
タグで挟んでいる**{this.state.clickCount}
の値が更新**されます。
今回はapp.jsで完結させていますが、clickCountの値を子コンポーネントに渡して、
子コンポーネントで値を表示するという実装だったとすると以下のようになります。
//app.js
import React, { Component } from 'react';
import Child from '.Component/child.js';
class App extends Component {
constructor(props){
super(props);
this.state = {
clickCount: 0
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState((state) => ({
clickCount: state.clickCount + 1
}));
}
render(){
return(
<div>
<button onClick={this.handleClick}>ButtonCount</button>
<Child clickCount={this.state.clickCount} />
</div>
);
}
}
export default App;
//child.js
import React, {Component} from 'react';
class Child extends Component {
render() {
console.log(this.props);
return <h1>{this.props.clickCount}</h1>
}
}
export default Child;
親コンポーネントの**<Child clickCount={this.state.clickCount} />
箇所で子コンポーネントに値を渡し、子コンポーネントの{this.props.clickCount}
**箇所で親コンポーネントから渡された値を受け取り表示しています。
**console.log
**で実際受け取っている値が見ることができます。
おわりに
今回のように小規模開発であれば問題ないのですが、大規模開発になるとコンポーネントも増えて、propsのバケツリレーになってしまいます。
このバケツリレーを避けるためにReduxというReactが扱う状態を管理するフレームワークなどを使うと良いでしょう。
[Redux公式]
(https://redux.js.org/introduction/getting-started)
[Redux超入門]
(https://qiita.com/YU01BLC/private/b294344c71b85aecfe5a) ←さらっと理解したい人向けに書いたので良かったら覗いてみてください。