LoginSignup
0
0

Hook(useState, useEffect) [5日間でReactの基礎を習得したい 3/5日目]

Posted at

はじめに

5日間でReactの基礎を習得する試みの3日目です。3日目は、フックについて学びます。

私はC#やPythonを仕事で使っているため、オブジェクト指向の言語的な考え方や、Pythonでの例えを使って理解を進めます。同じような境遇の方の理解の助けになれば幸いです。

フック(hook)

クラスコンポーネントでは出来るが、関数コンポーネントでは出来ないような実装があります。
例えば、クラスコンポーネントはメンバ変数に値を保持しておくことができます。しかし、当然ながら関数コンポーネントではstateなどのメンバ変数を保持することができません。

そこでフックを使う

メンバ変数等が必要でクラスコンポーネントでしかできなかった実装を、関数コンポーネントできるようにしてくれるのがフックです。

ここでは特にメジャーなuseStateとuseEffectを扱います。

useState

useStateは関数コンポーネントで、stateを使うためのフックです。(stateは2日目に扱いました。)

使ってみる

1日目に作ったプロジェクトのsrc/app/page.jsには、Homeコンポーネントが定義されています。
この中身を全部消して、以下のように編集しましょう。

page.js
"use client";

import React, { useState } from 'react';

// ボタンをクリックすると、表示される値がインクリメントされるコンポーネント
export default function Home() {
  // useStateを使用してカウンターの状態を初期化
  const [clickedCount, setClickedCount] = useState(0);

  // カウンターをインクリメントする関数
  const incrementCount = () => {
    setClickedCount(clickedCount + 1);
  };

  return (
    <div>
      <h1>Welcome to Next.js!</h1>
      <p>クリック数のカウント: {clickedCount}</p>
      <button onClick={incrementCount}>Increment Counter</button>
    </div>
  );
}

npm run devで起動すると、画面が表示されます。
"Increment Counter"ボタンを4回クリックすると次のような画面になります。
image.png

解説

useStateは const [stateを格納する変数名, stateを更新する関数名] = useState(stateの初期値);で宣言します。

const [clickedCount, setClickedCount] = useState(0);  // clickedCountの初期値は0になる

ボタンをクリックしたときのイベントにincrementCount関数を設定しています。この関数内でsetClickedCount(clickedCountの値を更新する関数)を実行しています。

// カウンターをインクリメントする関数
const incrementCount = () => {
    setClickedCount(clickedCount + 1);
};

incrementCountが実行されると、clickedCountの値が変更されるため、再描画されて"クリック数のカウント: "の数値が更新されます。

// clickedCountの値が変わると、画面が再描画されて値が更新される
<p>クリック数のカウント: {clickedCount}</p>  

useEffect

useEffectは、関数コンポーネントでコンポーネントが描画された後に副作用を実行するためのフックです。

副作用とは、コンポーネントのUIを変えるような処理・外部に対して操作する処理のことを指します。具体的な内容はこちら の記事が参考になります。

useEffectのクラスコンポーネントからの理解 副作用は、コンポーネントがすべて表示(マウント)されたあとに実行します。 クラスコンポーネントを使えば、コンポーネントが描画されたときの初期処理、コンポーネントが更新された後の処理などに、任意の処理を実行させられます。これは、各処理に相当するメソッドがクラスコンポーネントが継承しているReact.Copmponentに実装されており、それをoverrideすれば実装できます。
// これは模擬的な React.Component クラス。この感じのものをクラスコンポーネントは継承している。
class React.Component {
  constructor(props) {
    this.props = props;
  }

  componentDidMount() {
    // コンポーネントマウント後の初期処理
  }

  shouldComponentUpdate(nextProps, nextState) {
    // プロップス/ステート変更時の再レンダリング判断
    return true;
  }

  componentDidUpdate(prevProps, prevState) {
    // コンポーネント更新後の処理
  }

  componentWillUnmount() {
    // コンポーネントアンマウント前のクリーンアップ
  }

  render() {
    // UIレンダリングのロジックを実装必須
    throw new Error("Render method must be implemented");
  }
}

しかし、関数コンポーネントでは、このようなoverrideはできません。そこで、useEffectフックを使います。

使ってみる

Homeコンポーネントを以下のように編集しましょう。

page.js
"use client";

import React, { useEffect } from 'react';

// マウント(画面表示)完了後にコンソールにログが出力されるコンポーネント
export default function Home() {
  // コンポーネントがマウントされた後の副作用
  useEffect(() => {
    console.log('Component is mounted.');
  }, []);

  return (
    <div>
      <h1>Welcome to Next.js!</h1>
      <p>コンソールをチェックしてください</p>
    </div>
  );
}

npm run devで起動したあと、ブラウザで表示してF12の開発者ツールにてコンソールを確認してください。
image.png

https://qiita.com/kim_t0814/items/ce95b6b92e7994d4fdac#react18%E3%81%AE%E6%8C%99%E5%8B%95 この記事によると、開発モードで実行すると、2回マウントされるようなので、コンソールにも2回分のログが出ています。

解説

useEffectは、useEffect(実行する関数, 監視する値のリスト[省略可])で宣言します。
2引数目の"監視する値のリスト"ですが、このリストに値を入れておくと、その値が変わるたびに、関数が実行されます。何も書かない場合([]とする場合)、コンポーネントがマウントされる時だけコードが実行されます。

useEffect(() => {
    console.log('Component is mounted.');
}, []); // 今回はマウント時だけ実行されることになる

最後に

フックは他にも沢山ありますし、自作もできるようです。ただし、大事なことは"クラスコンポーネントでしかできなかった実装を関数コンポーネントでもできるようにする"という基本を覚えておくことだと感じました。
複雑な場合は、クラスコンポーネントだったらどう実装するのか、という観点から理解するのがよさそうです。

次回は既存のリポジトリを編集し、実践的に学びます。

何か間違いがあれば、是非コメントを頂けると助かります!

0
0
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
0
0