28
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Reactの基礎を理解しよう

Last updated at Posted at 2020-05-16

#目次

#概要
この記事はReact初心者である私がReactの基礎についてまとめたもので、私のようにReactをこれから学習しようとしている人向けの内容となっています。
Reactとは何か、Reactの開発環境の構築方法については別の記事にまとめてありますのでそちらを参考にしてみてください。
また私の記事は、より詳しい方が書いた記事等を参考にまとめていますので、さらに詳細に知りたい方は参考資料を見ることをおすすめします。

#Reactの基本文法

  • ReactはJavaScriptのライブラリ
  • 基本的な文法はJavaScriptベース
  • JSXと呼ばれるJavaScriptの中に直接HTMLを記述できる技術がある
  • アロー関数やclass構文などES6から実装された文法を取り入れている

React基本的な文法はこの辺りだと思います。

#JSX
JSXとは「Reactの基本文法」でも述べたように、JavaScriptのコード内で<div>...</div>というHTMLのような記述方法で記述できる技術です。

では実際の記述方法を見てみましょう。
最も簡単なJSXの例としては下記のような記述となります。

src/App.js
const element = <h1 className="greeting">Hello, world.</h1>;

elementに入っているタグ構文は文字列でもHTML要素でもなく、これがJSXです。

このように1つのファイル内でJavascriptとHTMLの記述方法を併用できるのか疑問に思う人もいるはずです。コンピュータ(ここではブラウザ)は賢いようでそうではないので本来であればJavaScript内に記述されたHTML構文を解釈することができません。

そこで登場するのがJavaScriptトランスパイラであるBabelです。このBabelによってReact.createElement()の形式つまりJavaScript形式に変換されます。Babelは他にもES2015などに対応していないブラウザに対して、対応できる形式に変換してくれる機能もあります。

以下がBabelによって変換された後の内容です。

src/App.js
import React from 'react';

const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world.'
);

Babelに頼らずReact.createElement()を使って直接記述することもできますが、JSXの方がわかりやすいし書きやすいですよね。

他にもJSXの記述方法にはいくつかのルールのようなものがあります。その中でも利用頻度の高いものは次の項目だと思います。

  • 返す要素は1つにまとまった要素として記述する必要がある
  • JSX内でJavaScriptを記載するときは{ }で囲む
  • 関数の呼び出しもできる
  • HTMLのclassはJSXではclassNameにする
src/App.js
import React from 'react';

const name = '太郎';
const age = '10';
add(x, y){ return x + y; }

render() {
  return (
    <div>
      <h1 className="greeting">こんにちは</h1>
      <p>僕の名前は{name}です。{age}歳です。</p>
      <p>1 + 2 = {this.add(1, 2)}</p>
    </div>
  );
}

このような感じになります。
returnで返している要素は<div>タグの中にまとまっていますので1つの要素と見ることができます。

1つの要素としてまとめる際に<div>タグを用いることで余計なDOM操作をすることになるので<React.Fragment>というものを利用した方がいいです。

src/App.js
import React from 'react';

const name = '太郎';
const age = '10';
add(x, y){ return x + y; }

render() {
  return (
    <React.Fragment>
      <h1 className="greeting">こんにちは</h1>
      <p>僕の名前は{name}です。{age}歳です。</p>
      <p>1 + 2 = {this.add(1, 2)}</p>
    </React.Fragment>
  );
}

#Component
Component(コンポーネント)とは、Reactの最終的な出力であるJSXを構成するUI部品のことで、一度作成すれば何度でも再利用することができます。

例えばJSXで、

src/App.js
import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(
  <React.Fragment>
    <div>
      <h1>Hello,World.</h1>
      <h2>Hi, everyone.</h2>
    </div>
    <div>
      <h1>Hello,World.</h1>
      <h2>Hi, everyone.</h2>
    </div>
  </React.Fragment>,
  document.getElementByID('root');
);

という<div>...</div>の中身が同じものが2つあったとき、何度も同じ構文を記述することはめんどくさいし効率が悪いですよね。
(ReactDOMなどまだ紹介していないところもありますが今は気にしないでください。後ほど説明します。)

そんなときに登場するのがコンポーネントです。言葉で説明してもイメージがつきにくいと思うので実際に先ほどの例を書き換えてみましょう。

src/App.js
import React, { Component } from 'react';

class Greeting extends Component {
  render() {
    return(
      <div>
        <h1>Hello, world.</h1>
        <h2>Hi, everyone.</h2>
      </div>
    );
  }
}

// ここ!!
ReactDOM.render(
  <React.Fragment>
    <Greeting />
    <Greeting />
  </React.Fragment>,
  document.getElementById('root')
);

このように記述できます。
今回はコンポーネントの中身が少なかったので全体の記述量はほとんど同じですが、コンポーネントとしてまとめられる量が多かったり、何度も同じJSXを記述する場合ほどその効果は大きくなります。見た目もなんだかすっきりしていますよね。
複雑な処理になればなるほどコンポーネントの真価が発揮されるでしょう。

またコンポーネントにはクラスコンポーネント関数コンポーネントの2種類あります。それぞれ特徴をみていきましょう。

###クラスコンポーネント
クラスコンポーネントはclass定義で作成されるコンポーネントです。クラスコンポーネントを作成する場合には、React.Component()を継承することで作成できます。前述した例のGreetingもクラスコンポーネントです。
クラスコンポーネントではJSXをreturnするために必ずrender()メソッドを定義する必要があります。メソッド以外にもクラスですのでconstructor(コンストラクタ)も定義することができます。

src/App.js
import React, { Component } from 'react';

class Greeting extends Component {  // React.Componentを継承
  constructor() {
    .
    .  // ここでは省略します
    .
  }

  render() {  // JSXを返すrenderメソッド
    return(
      <h1>Hello, world.</h1>
    );
  }
}

###関数コンポーネント
関数コンポーネントは、コンポーネントを関数で定義することができます。定義の仕方はfunctionでも書けますが、アロー関数で書くほうが記述量的にベターな気がします。

src/App.js
import React from 'react';

const Greeting = () => {
  return(
    <h1>Hello, world.</h1>
  );
}

このようになります。
関数コンポーネントの中身は基本的にrender()メソッドとなるので、クラスコンポーネントで記述していたrender()は省略できます。

以前は、後述する状態(state)やライフサイクルを関数コンポーネントでは持つことができなかったので、その場合にはクラスコンポーネントを作成するといった区別がありました。
しかしReact 16.8で実装されたHooksを用いることで関数コンポーネントでもクラスコンポーネントと同等の機能を持つことができるようになったので、今は基本的にコンポーネントはHooksを用いて記述されることが多いようです。
Hooksに関する記事はまた別に出します。

#props
propsとは、コンポーネントに引数として渡せるプロパティ(オブジェクト)です。

propsがどんな役割を担うのか例で見てみましょう。

src/App.js
const App = () => {
  return(
    <React.Fragment>
      <h1>I am taro, 10 years old.</h1>
      <h1>I am hanako, 8 years old.</h1>
      <h1>I am yuta, 11 years old.</h1>
    </React.Fragment>
  );
}

このようなJSXがあったとき、<h1>タグの中身は似たような内容ではありますが、全く同じではありません。でも共通する箇所が多いのでなんとかコンポーネントとしてまとめたいですよね。
そんなときに登場するのがpropsです。

ではpropsを用いて上記のコードを書き換えてみます。

src/App.js
const Greeting = props => {
  return(
    <h1>I am {props.name}, {props.age} years old.</h1>
  );
}

const App = () => {
  return(
    <React.Fragment>
      <Greeting name="taro" age="10" />
      <Greeting name="hanako" age="8" />
      <Greeting name="yuta" age="11" />
    </React.Fragment>
  );
}

書き換え前に比べすっきりしました。
ここで親コンポーネントAppが子コンポーネントGreetingコンポーネントに渡しているname="..." age=...propsです。

このようにコンポーネントを利用するうえで欠かすことのできない機能なのでしっかり抑えておきましょう。
propsを用いる場合には次のような注意点があります。

  • propsの受け渡しは親コンポーネント→子コンポーネントのみ
  • 子コンポーネント側からpropsの値を直接変更することはできない
  • 子コンポーネントではprops.データ名でデータを参照する

#state
stateとは、コンポーネント内部の状態を表す値です。
propsとは違い、そのコンポーネント内でしか扱うことができず、かつsetState()を使うことでコンポーネント内で変更可能なのが特徴です。

クラスコンポーネントでstateを使う場合は、基本的にコンポーネント作成時のコンストラクタ内で初期化します。this.stateオブジェクトに値を指定することで、同コンポーネント内のメソッドで取得することができます。

src/Counter.js
import React, { Component } from 'react';

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = {  // this.stateの初期化
      count: 0,
    };
  }

  render() {
    return(
      <div>count: {this.state.count}</div>
    );
  }
}

このような記述になります。constructor(props)super(props)はおまじないみたいなものと覚えて大丈夫です。

this.stateの初期値設定ができたので、値をsetState()で変更してみましょう。

src/Counter.js
import React, { Component } from 'react';

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = {  // this.stateの初期化
      count: 0,
    };
  }

  // this.state.countを+1するメソッド
  handleCountButton = () => {
    this.setState({count: this.state.count + 1});  // this.stateの更新
  }

  render() {
    //Countボタンをクリックしたらcountが+1されるJSX
    return(
      <React.Fragment>
        <div>count: {this.state.count}</div>
        <button onClick={this.handleCountButton}>Count</button>
      </React.Fragment>
    );
  }
}

ここではCountというボタンを押すことで、this.state.countが+1されるというメソッドhandleCountButton()を用いて更新をしてみました。目で追うと若干複雑に見えますが、1つずつ理解していけばそこまで難しくないと思います。

statepropsと同様にコンポーネントを扱ううえで必要な機能なのでここでしっかり理解しておきましょう。最も重要な注意点は、this.state直接変更することができないことです。必ずsetState()で変更しましょう。

###現在のReact
以前まではクラスコンポーネントでしかstateを利用することができませんでしたが、React Hooksで追加された機能のuseStateを使うことで関数コンポーネントでもstateを利用することができるようになりました。これにより最近のReactコンポーネントの主流は関数コンポーネントになっています。useStateなどReact Hooksについては前述したように別の記事にまとめたいと思います。

#2種類のrender()
今までのコードにrender()が何回も登場していますが、このrender()にも2種類あります。

  • React.Componentのrender()
  • ReactDOMのrender()

それぞれについて見てみましょう。

###React.Componentのrender()
Componentでも述べましたが、コンポーネント内で必ず定義する必要のあるメソッドがrender()です。(ただし関数コンポーネントでは省略されることもあります。)

class App extends Component {
  render() {
    return( /*返す要素*/ );
  }
}

コンポーネントに用いるrender()は呼び出されると、this.propsthis.stateを調べReact要素などを返します。(詳細はこちら

###ReactDOMのrender()
ReactDOM.render()のイメージとしては最終的にブラウザへレンダリングするためのメソッドです。

ReactDOM.render(element, container[, callback])

よくReactの特徴として「仮想DOM」というワードを見かけると思いますが、それに起因するのがReactDOM.render()です。
ReactDOM.render()メソッドが飛び出されると指定されたcontainerにReact要素をレンダリングします。このとき描画された結果のDOMを表したデータ構造が仮想DOMです。
再度ReactDOM.render()が呼び出されると、変更前後の仮想DOMの差分を計算し、最低限の操作をブラウザ上の実際のDOMに対して行います。

これら2種類のrender()の役割をまとまると、

  • 各Componentのrender()がそれぞれのパーツを作る
  • ReactDOMのrender()がパーツを集めて1つにまとめてブラウザへ描画する

といったイメージかと思います。

#まとめ
Reactの基礎についてまとめてみました。とは言ってもまだ基礎の基礎くらいで、本当はまだまだこんなものではありません。とりあえず今回の記事のまとめです。

  • ReactではJSXが書ける
  • ComponentはJSXを構成するUI部品
  • propsは親コンポーネントから子コンポーネントへ渡せる引数オブジェクト(子では変更不可)
  • stateはコンポーネント内部の状態を表す値(変更可)
  • **render()**メソッドには2種類ある

今回は自身の知識の土台を固めるつもりでこのような記事を書きましたが、今後も必要に応じて色々とまとめてみたいと思います。

#参考資料

28
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?