137
177

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 #2Advent Calendar 2020

Day 9

[初心者向け]Reactの基礎を徹底解説してみた

Last updated at Posted at 2020-12-08

#はじめに
今回はReactの使い方についてまとめていきます。

環境構築については、以下の記事を参考にしてください。

WindowsでReactの環境構築をしてみる

#コンポーネントについて
Reactはコンポーネント(部品)という単位で実装していきます。

Webサイトやアプリは、ボタンやタブなどのコンポーネントの集まりと考えることができます。

例えば、このQiitaだと以下のようなコンポーネントが存在すると考えることができます(適当です)。

  • ボタンコンポーネント

image.png

  • ナビゲーションコンポーネント

image.png

つまり、コンポーネントとは見た目機能を組み合わせたものだと考えることができます。

このように、コンポーネントという単位でプログラムを管理すると、再利用することができたり、変更してもバグが起きにくいという利点がありますよね。

それでは実際にコンポーネントの種類を見ていきましょう。

今回は、npx create-react-appというコマンドを使ってReactアプリを作成し、そのアプリに各々のコードを記述して動きを見ていきます。

##Functional コンポーネントについて
Functionalコンポーネントについて見ていきましょう。

create-react-appを行うと、以下のようなファイル構成になります。

image.png

この中のApp.jsxに以下のようにコードを記述してください。

App.jsx
import React from 'react'

const App = (props) => {
  return (
    <div>
      <h1>Hello World</h1>
    </div>
  )
}
export default App

このように、Javascriptの関数のようにReactのコンポーネントを作成して、外部にエクスポートしています。

Functionalコンポーネントは、アロー関数またはfunction()で定義した関数のどちらを用いて記述します。

関数内のreturnの後に、JSXと呼ばれるHTMLのようなものを記述します。

ここでは使用していませんが、引数で渡しているpropsに、親コンポーネントから呼び出す際に変数を格納されることができます。

ちなみに、このエクスポートされたApp関数はindex.jsで呼び出されます。

index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

serviceWorker.unregister();

上記のように、index.jsApp.jsxファイルからエクスポートされたAppコンポーネントを読み込み、それをReactDOMに渡すことでrender(描画)しています。

yarn startを行い、実行結果を見てみましょう。

image.png

このように、Reactアプリを起動させるとindex.jsファイルが実行され、ReactDOMがrender(描画)されていることが分かります。

##クラスコンポーネントについて
クラスコンポーネントは以下のように作成します。

App.jsx
import React from 'react';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      open: 'pocomaru'
    }
  }
  render() {
    return (
      <div>
        <h1>Hello World</h1>
        <h1>{this.state.id}</h1>
      </div>
    );
  }
}
export default App

Javascriptのクラスを作成する際に、React.Componentというクラスを継承しています。

その後に、constructorにより、初期値のstateをセットします。コンストラクタとは、オブジェクト作成時に実行されるメソッドのことでしたね。

引数に渡しているpropsは、エクスポートしたAppコンポーネントを呼び出すときに渡した値が代入される箱のようなものです。

super(props)とすることで、親クラスを継承しています。

その後に、this.stateにオブジェクトを代入します。このthisは、このクラス自身のことです。今、Appクラスのopen stateがtrueに設定されています。

このstateに設定されている値を用いる場合、this.state.idとすればアクセスできます。

return以降はJSXと呼ばれる部分になります。この部分では、通常の書き方ではJavascriptコードを使用することができません。

そのため、this.state.idの値にアクセスするためには、中括弧{}で囲う必要があります。

この状態でReactアプリを起動すると以下のようになります。

image.png

#Functionalコンポーネントとクラスコンポーネントの違い
最初にFunctionalコンポーネントの特徴から解説します。以下の特徴を持ちます。

  • stateを持たない
  • propsを引数に持つ

順番に解説します。

###stateとは
stateとは、その名の通り状態のことです。

例えば、扉コンポーネントというものを考えたとき、扉が開いているのか閉じているのかというコンポーネントの状態を示すのがstateです。

ボタンコンポーネントでは、押されたことがあるのか押されたことがないのかというのもstateで管理できますし、何回押されたのかなどもstateで管理できます。

Functionalコンポーネントはクラスコンポーネントと違って、このstateを持つことができません。

React-hooksなどを用いればstateを持たせることは可能ですが、ここでは割愛させて頂きます。

###propsを引数に持つとは
Functionalコンポーネントは、propsを引数に持つことができます。ちなみにクラスコンポーネントもコンストラクタにpropsを渡すので、Functionalコンポーネントだけの機能ではありませんが。

propsとは、親コンポーネントから渡す値を格納するのようなものです。

具体例で確認してみましょう。

App.jsxという親コンポーネントからName.jsxというコンポーネントを呼び出し、propsとしてnameを渡すことを考えてみましょう。以下のようになります。

App.jsx
import React from 'react';
import Name from './Name';

const App = (props) => {
  return(
    <div>
      <Name name='pocomaru'/>
    </div>
  )
}
export default App

このファイルでは、Name.jsxの中のName関数コンポーネントをインポートしています。

そのインポートした関数のname属性にpocomaruという値を渡しています。

この渡した値には、props.nameとすることでアクセスできます。Name.jsxの中身を確認してみましょう。

Name.jsx
import React from 'react';

const Name = (props) => {
    return (
        <h1>{props.name}</h1>
    )
}

export default Name

結果は以下のようになります。

image.png

それでは次にクラスコンポーネントについて見ていきましょう。

以下の特徴があります。

  • ライフサイクルをもつ
  • stateを持つ

それぞれについて解説していきます。

###ライフサイクルをもつ
クラスコンポーネントはライフサイクルを持ちます。

ライフサイクルとは、コンポーネントが生まれて、成長し、死ぬまでの循環のことです。

こんなことを言われても意味がわからないと思うので、具体的に説明します。

ボタンコンポーネントのライフサイクルについて考えてみましょう。

ある日、ボタンコンポーネントが誕生しました。マウントされるとも言いますね。

Reactにおいては、このボタンコンポーネントが誕生した瞬間constructorが走ります。stateに値を代入する処理などですね。

そのようにしてconstructorが走った後は、renderが走ります。これによりReactが描画され、画面で見ることができます。

この後に、componentDidMountという関数が走ります。このcomponentDidMount`に何か操作をかいておけば、コンポーネントがマウントされた後に一度だけ使うことができます。

ここまでが生まれたときの話です。次は、コンポーネントが成長していくときの話をしましょう。

コンポーネントが誕生した後は、度重なるrenderがユーザーの操作により発生します。

具体的にはrenderは、ユーザーの操作などによりstateが変更されるたびに呼び出されます。

これがライフサイクルの成長の過程であり、renderされる毎にcomponentDitUpdateという関数が実行されます。

最後に、コンポーネントが死ぬときの話をしましょう。

コンポーネントが死ぬ直前、つまりはアンマウントされる直前にcomponentWillUnmountという関数が実行されます。

このように、ライフサイクルに合わせてcomponentDidMountなどのメソッドを実行することができ、これらはクラスコンポーネントでしか使用することができません。React-hooksを使えば、Functionalコンポーネントでも用いることができますが。

それでは次に、ライフサイクルについて解説していきます。

#ライフサイクルの種類
ライフサイクルには、以下の三種類があります。

  • Mounting

  • Updating

  • UnMounting

各々について解説していきましょう

###Mountingとは
Mountingとは、コンポーネントが生まれるときの期間のことです。

このMountingのときに使われるライフサイクルメソッドは、マウントが行われる直前に実行されるcomponentWillMountとマウントが実装された直後に実行されるcomponentDidMountです。

ちなみにマウントが行われる直前に実行されるcomponentWillMountは非推奨なので使わないほうがよいです。

##Updatingとは
Updatingとは、コンポーネントが変更される期間のことです。

クラスコンポーネントはライフサイクルとstateを持つことができます。

つまり、コンポーネントが変更されるとはこのstateが変更されることを指します。

例えば、ボタンコンポーネントを実装するとします。このボタンコンポーネントの元々の色は赤色で、ボタンをクリックすると青色になるという機能をもたせたいとします。

どのように実装するかというと、このボタンコンポーネントにstateを持たせて管理することが考えられます(例えばcolorコンポーネントを持たせてクリックにより変更させるなど)。

Reactにおける重要な点の一つは、このstateが変更されたときにrenderが走るということです。つまり、stateが変更されるたびに画面の一部分を再描画していきます。

なぜこのような事になっているのかというと、stateの変更を画面に反映させるためです。例えば先ほどの例でボタンコンポーネントをクリックして、colorというstateを赤色から青色に変更させたとします。しかし、例えstateが変更されたとしても、render(描画)されなければ画面に反映されません。そのため、Reactではstateが変更されるたびにrenderが呼ばれるようになっています。

このstateが変更されてrenderされるという時がUpdatingの期間であり、その前後に対応したライフサイクルメソッドが走ります。Updatingにおけるライフサイクルメソッドは、以下の4つが考えられます。

  • componentWillReactiveProps  マウントされたコンポーネントが新しいpropsを受け取る前

  • shouldComponentUpdate    新しいpropsやstateを受け取った時

  • componentWillUpdate     新しいpropsやstateを受け取った後、レンダリングする直前

  • componentDidUpdate      更新が行われた直後

##Unmountingとは
コンポーネントが破棄される期間のことをUnMountingの期間といいます。

componentWillUnmountというライフサイクルメソッドが、コンポーネントが破棄される直前に呼び出されます。

それでは実際に、これらのライフサイクルメソッドを実装してみましょう。

#componentDidmountの実装
componentDidmountは、次の用途で用いられます。

  • Ajaxを使ったデータフェッチを行う(初回)
  • DOMに対する処理を行う(初回)
  • タイマーをリセットする
  • イベントリスナのセット

今回は、イベントリスナのセットを行っていきましょう。

LikeButtonコンポーネントを作成して、クリックするといいね数が増えていくという機能を実装します。

以下のように、App.jsxとLikeButton.jsxを実装しましょう。

App.jsx
import React from 'react';
import LikeButton from './LikeButton';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    }
  }

  componentDidMount() {
    document.getElementById("counter").addEventListener('click', () => this.setState({count: this.state.count + 1}))
  }
  render() {
    return (
      <div>
        <LikeButton count={this.state.count} />
      </div >
    )
  }
}
export default App
LikeButton.jsx
import React from 'react';

const LikeButton = (props) => {
    return (
        <div>
            <button id="counter">いいね数: {props.count}</button>
        </div>
    )
}
export default LikeButton

結果は以下のようになります。

temp1.gif

それではコードの解説をしていきます。

.jsx
constructor(props) {
  super(props);
  this.state = {
    count: 0
  }

この部分で、Appコンポーネントのstateとしてcountを持たせています。

このstateをLikeButtonコンポーネントに渡して、その中のButtonをクリックするたびに、このstateが更新されていけば良いわけですね。

今回は、componentDidMountを用いてイベントリスナーを設定しています。イベントリスナーとは、イベント(文字入力やボタンクリックなど)が行われたことを検知して発動する関数のことです。これにより、コンポーネントが誕生したときにイベントリスナーをコンポーネントに設定することができます。

今回は、クリックというイベントが発生したときに、() => this.setState({count: this.state.count + 1}という関数が実行されるようになりました。

クラスコンポーネントのstateを変更するときは、このようにsetStateメソッドを用いて、そのメソッド内で関数またはオブジェクトを指定することにより、stateを変更することができます。クラスコンポーネント内でstateにアクセスするときにはthis.state.***としてアクセスします。ちなみに、このsetStateメソッド内で関数を渡すかオブジェクトを渡すかの違いによって、挙動が異なります。詳しくは以下の記事を参考にしてください。

React の setState() の引数が関数の場合とオブジェクトの場合の違いについて整理する

また、以下のコードでLikeButtonコンポーネントを呼び出し、propsとしてthis.state.countを渡しています。

.jsx
<LikeButton count={this.state.count} />

このようにして渡したstateを、LikeButtonコンポーネントではprops.countという形で利用しています。

.jsx
<button id="counter">いいね数: {props.count}</button>

このbuttonタグのidにcounterを指定しています。このタグは、親コンポーネントであるApp.jsxからも指定して呼び出すことができます。

ここまでで、componentDidMountを用いてコンポーネントが誕生した直後にイベントリスナーを設定することができました。

###補足 別の方法で同じ機能を実装
また、今回の機能はApp.jsxからpropsとしてcountを更新する関数を渡し、それを子供のコンポーネントのボタンタグのonClickに指定することでも実装できます。

App.jsx
import React from 'react';
import LikeButton from './LikeButton';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    }
  }

  UpdateCounter = () => {
    this.setState({
      count: this.state.count + 1
    })
  }
  render() {
    return (
      <div>
        <LikeButton count={this.state.count} UpdateCounter={this.UpdateCounter} />
      </div >
    )
  }
}
export default App
LikeButton.jsx
import React from 'react';

const LikeButton = (props) => {
    return (
        <div>
            <button onClick={props.UpdateCounter}>いいね数: {props.count}</button>
        </div>
    )
}

export default LikeButton

#componentDidUpdateの実装
それでは次にstateが更新されてrenderが走った後に呼び出されるcomponentDidUpdateを実装していきましょう。

このライフサイクルメソッドは、stateがある閾値を超えたときに別の動作をするようにしたいときなどに実装すると便利ですね。

今回は、いいね数が5という閾値を超えた際に、いいね数を0にするという機能を実装していきます。

componentDidUpdateはstateが更新され、それによりrenderが走った後に呼び出されます

つまり、その更新されたstateに対して更新されるたびにif文やswich文で比較を行い、指定した値になったときに指定した関数を実行する、といった処理を実装していきます

今回はthis.state.countの値をcomponentDidUpdateの中で5と比較し、5以上になったときにthis.state.countの値をsetStateメソッドを用いて0にするという機能を実装していきます。

以下のコードです。

App.jsx
import React from 'react';
import LikeButton from './LikeButton';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    }
  }

  componentDidMount() {
    document.getElementById("counter").addEventListener('click', () => this.setState({count: this.state.count + 1}))
  }

  componentDidUpdate(){
    if (this.state.count >= 5) {
      this.setState({
        count: 0
      })
    }
  }
  render() {
    return (
      <div>
        <LikeButton count={this.state.count} />
      </div >
    )
  }
}
export default App
LikeButton.jsx
import React from 'react';

const LikeButton = (props) => {
    return (
        <div>
            <button id="counter">いいね数: {props.count}</button>
        </div>
    )
}
export default LikeButton

以前の状態から追記したコードは以下だけです。

.jsx
  componentDidUpdate(){
    if (this.state.count >= 5) {
      this.setState({
        count: 0
      })
    }
  }

このコードにより、stateの値が更新されるたびにthis.state.countが5以上かどうかを確認することになります。

実行結果は以下のようになります。

temp2.gif

#componentWillUnmountの実装
このメソッドは主に次の機能を実装したいときに使います。

  • タイマーを解除する
  • イベントリスナーを解除する
  • 非同期処理を中止する

今回は、イベントリスナーを解除してメモリを開放する機能を実装していきましょう。

以下のコードです。

App.jsx
import React from 'react';
import LikeButton from './LikeButton';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    }
  }

  componentDidMount() {
    document.getElementById("counter").addEventListener('click', () => this.setState({count: this.state.count + 1}))
  }

  componentDidUpdate(){
    if (this.state.count >= 5) {
      this.setState({
        count: 0
      })
    }
  }

  componentWillUnmount() {
    document.getElementById('counter').removeEventListener('click', () => this.setState({count: this.state.count + 1}))
  }
  render() {
    return (
      <div>
        <LikeButton count={this.state.count} />
      </div >
    )
  }
}
export default App
LikeButton.jsx
import React from 'react';

const LikeButton = (props) => {
    return (
        <div>
            <button id="counter">いいね数: {props.count}</button>
        </div>
    )
}
export default LikeButton

これでコンポーネントがアンマウントされたときにイベントリスナーを削除して、メモリを開放することができるようになりました。

追記したのは以下の部分です。

.jsx
  componentWillUnmount() {
    document.getElementById('counter').removeEventListener('click', () => this.setState({count: this.state.count + 1}))
  }

このコードにより、イベントリスナーを削除することができています。

それでは次に、ReactのHooksについてまとめていきます。

#Hookとは
Hookとは、端的に言えばクラスコンポーネントの機能をFunctionalコンポーネントでも使えるようにするためのものです。

具体的には、今まではクラスコンポーネントでしか持つことができなかったstateやライフサイクルをFunctionalコンポーネントで利用できるようになります。

今までReactの様々な機能にアクセスできるクラスコンポーネントと違い、一切のアクセスが許可されていなかったFunctionalコンポーネントをReactの機能へ接続(Hooks into)するという意味で、Hooksと呼ぶらしいです。
#なぜHookを使うのか
察しの良い皆さんならこう思ったはずです。

「stateやライフサイクルメソッドが使いたいならクラスメソッド使えば良くね?」

確かに一理あります。

しかし、クラスコンポーネントには以下で示すような問題がありました。

  • 処理が散らばりやすい
  • thisを使いたくない
  • 複数のライフサイクルメソッドに処理がまたがるのが嫌だ
  • そもそもクラスコンポーネントの構文が複雑
  • stateの扱い方が複雑

この中のいくつかの問題点を、さらに深く解説していきます。

##処理が散らばりやすい
Reactを書いたことがある皆さんなら共感頂けると思いますが、クラスコンポーネントはメソッドをいくつも実装できるが故に処理が散り散りになりやすいんですよね。

子供のコンポーネントで行われる処理を、親のクラスコンポーネントのライフサイクルに定義して使いたくなりますよね。

具体例で話すなら、例えば人間コンポーネントを定義して、それに子供としてハサミコンポーネントを渡したとします。

このハサミコンポーネントの前に紙が存在するときに、ハサミコンポーネントの切断という機能を実装したいとします。

人間コンポーネントをクラスコンポーネント、ハサミコンポーネントをFunctionalコンポーネントだとすると、はstateを持つ人間コンポーネントで管理することになりますし、紙の状態に応じた処理(ここでは切断する)もライフサイクルを持つ人間コンポーネントの中で書くことになりそうです。

子供のコンポーネントがハサミコンポーネントのみならまだしも、他の様々なコンポーネントのstateやライフサイクルも人間コンポーネントで管理することになると、非常に煩雑になりそうですよね。

そもそも、切断するという処理はハサミコンポーネントの中の処理であるので、当然の思考としてハサミコンポーネントの中で管理するのが良さそうです。

また、というstateも、紙の状態に応じたライフサイクルを用いた処理も、人間コンポーネントではなくハサミコンポーネントで管理するべきですよね。

ここでハサミコンポーネントをクラスコンポーネントにしてしまっても良いのですが、それだと根源的な解決になりません。

そもそも、ひとつの機能はひとつの場所にという原則を守って書くことを強制してしまった方が良さそうです。

そこで導入されたのがHookであり、Functionalコンポーネント自体にstateやライフサイクルを管理させるとうものです。

##thisを使いたくない
Javascriptにおけるthisは、他の言語におけるthisとは違う挙動をします。

詳しくは以下の記事を御覧ください。

JavaScriptの「this」は「4種類」??

JavaScript の this を理解する多分一番分かりやすい説明

つまり、簡単に書くとthisの使い方めっちゃむずいということです。

こんなものはトラブルの元です。

できるだけ使わないようにしようという動きも多く、そのためクラスコンポーネントはできるだけ使いたくないと思う人も多いようです。

複数のライフサイクルメソッドに処理がまたがるのが嫌だ

クラスコンポーネントのライフサイクルメソッドは、時間の流れで処理を分割します。

そうすると、同じような機能が複数のライフサイクルメソッドに跨ってしまうことがありますよね。

そのように記述するよりも、同じ機能は同じ場所と言う方が分かりやすいと考える人も多いようです。ちなみに私もそう思います。

#React-Hooksの実装
それでは実際にHooksを実装してみましょう。

##Hooksでstateの管理
まず、Hooksでstateの管理をしていきます。

HooksはFunctionalコンポーネントにおけるstateの管理やライフサイクルメソッドの実装に用いるんでしたね。

Hooksでstateを用いるときは、useStateというメソッドを使います。

実際にコードで確認してみましょう。

今回は、ScissorsコンポーネントというFunctionalコンポーネントを作成して、それを親コンポーネントであるAppコンポーネントから呼び出します。

そのScissorsコンポーネントにcuttingとうstateを持たせて、ボタンを押すことで変化させるという機能を実装します。

以下がコードです。

App.jsx
import React from 'react';
import Scissors from './Scissors'

const App = () => {

  return(
    <div>
      <Scissors />
    </div>
  )
}
export default App

これはシンプルにScissorsコンポーネントを呼び出しているだけですね。以下がそのScissorsコンポーネントです。

Scissors.jsx
import React, { useState } from 'react';

const Scissors = () => {
    const [cutting, changeCutting] = useState("NoCutting");
    return(
        <div>
            <h1>{cutting}</h1>
            <button onClick={() => changeCutting("YesCutting!")}>change </button>
        </div>
    )
}

export default Scissors

それではHooksの部分を解説していきます。

以下の部分でuseStateをインポートしています。

.jsx
import React, { useState } from 'react';

これでインポートすることができました。

次の部分が、useStateを使う上で肝となる部分です。以下のコードです。

.jsx
const [cutting, changeCutting] = useState("NoCutting");

それでは解説します。

cuttingがstateであり、changeCuttingがstateを変更させる関数です。ちなみに、このchangeCuttingに引数を渡して実行すれば、cuttingの値がその引数に渡した値に変化します。

つまり、このuseState関数は、statestateを変更させる関数を同時に定義していると考えることができますね。

クラスコンポーネントでは、constructorの部分でthis.state = {}という感じにstateを定義し、setStateを用いてそのstateを変更していたと思います。

それでは、useStateの引数の部分は何を意味するのでしょうか。

正解は、stateの初期値になります。

つまり、上のコードはcuttingというstateを作成し、その初期値にNoCuttingを渡し、それと同時にそのstateを変更させる関数であるchangeCuttingを作成したことになります。またこのchangeCuttingは、実行したときにcuttingの値を引数に指定した値に変更させる関数になります。

以下のコードで、ボタンをクリックしたときにこのchangeCuttingを実行しています。

.jsx
<button onClick={() => changeCutting("YesCutting!")}>change </button>

buttonタグのonClickにアロー関数としてchangeCuttingを実行したものを渡しています。

onClickはボタンをクリックしたときに引数として渡された関数を実行するという機能なので、このように関数そのものを渡します。

実際にこのReactアプリの挙動を見てみましょう。

temp3.gif

ここまでで、Hooksによるstate管理は終わりです。

##Hooksによるライフサイクルの管理
Hooksによるライフサイクルメソッドの代替として、useEffectメソッドがあります。

以下の三つのメソッドを代替することができます。

  • coponentDidMount()
  • componentDidUpdate()
  • componentWillUnmount()

軽く解説します。

###componentDidMountについて
componentDidMountはマウントが行われた直後に実行されるメソッドです。Ajaxを使ったデータフェッチ(初回)やイベントリスナのセットなどを行います。

###componentDidUpdateについて
componentDidUpdateはstateの更新が行われた直後に行われるメソッドです。具体的には、stateが更新され、その後にrenderが走った後に呼び出されます。

stateがある閾値を超えたときに別の動作をするようにしたいときなどに使うと便利ですね。

###componentWillUnmountについて
componentWillUnmountは、コンポーネントが破棄される直前に呼び出されます。

具体的には、イベントリスナーを解除してメモリを開放するときなどに利用されます。

それでは、実際にuseEffectメソッドを用いてこれらのライフサイクルメソッドを実装してみましょう。

#useEffectメソッドの実装
まず、最初にuseEffectメソッドの使い方解説を行います。

以下の記事を参考にしました。

【React】useEffectの第2引数って?

##第一引数のみ

第二引数を空っぽにすると、第一引数に指定したコールバック関数がrender毎に実行されます。

componentDidUpdateと同じタイミングで呼ばれることになりますね。

.jsx
useEffect(() => {
  console.log("render")
});

しかし、これは公式のリファレンスで推奨されていない書き方なので、使わないようにしましょう。

##第二引数を与える

###空の配列が渡されたとき

.jsx
useEffect(() => {
  console.log('mounting')
}, [])

第二引数に空の配列が渡された場合、マウント時のみ、第一引数に渡されたコールバック関数を実行します。

Reactはrenderが呼ばれるたびに第二引数の値がrender前とrender後に変化したかどうかを確認します。

その時、変化していた場合にのみ第一引数に設定したコールバック関数を実行します。

今回は、第二引数に空の配列を指定しているため、マウント時のみ第一引数のコールバック関数が走るようになります。

componentDidMountと同じタイミングになります。

###第二引数の配列に値が渡された場合
第二引数に値の配列が渡された場合、renderの前後で値が変化した場合に第一引数のコールバック関数が呼ばれます。

.jsx
const [boolean, changeBoolean] = useState(true)
useEffect(() => {
  console.log('changed')
}, [boolean])

この場合、第二引数に渡したbooleanの値が変更されるたびに第一引数に渡したコールバック関数が呼ばれるようになります。

###マウント時とアンマウント時のみ実行
useEffectメソッドにおいては、第一引数のコールバック関数内においてreturnを行うと、そのreturnの中の処理がアンマウント時に実行されるようになります。

以下のコードです。

.jsx
useEffect(() => {
  console.log("render")
  return () => {
    console.log("Unmounting!")
  }
}, []}

第二引数に空の配列を渡しているので、render毎に実行されることはありません。

つまり、console.log("render")の部分がマウント時のみ実行されるようになります。

また、return後の関数が、アンマウント時に実行されるようになります。

#終わりに
今回の記事はここまでになります。

お疲れさまでした。

#参考

日本一わかりやすいReact入門#8...React Hooksでstateを扱おう

React Hooks超入門

最近Reactを始めた人向けのReact Hooks入門

137
177
1

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
137
177

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?