ALLSPICE

スパイスファクトリー株式会社のメンバーが運営するWeb開発メディア

React初心者の方に向けた、React Hooksの基本説明とソースコード例

React初心者の方に向けた、React Hooksの基本説明とソースコード例

Posted by w_tu | |システム開発

DXエージェンシースパイスファクトリー株式会社、エンジニアのワンです。
スパイスファクトリーのシステム開発に関するページはこちら。

この記事では、React 初心者の方に向けて、react hooks についての基本説明と、いくつかの hook の紹介をしていきます。

hookとは

そもそも、 hook とは何でしょうか。
React 公式サイトでは、hooks について以下のように説明してあります。

フック (hook) は React 16.8 で追加された新機能です。state などの React の機能を、クラスを書かずに使えるようになります。

要は、hook は Reactの state やライフサイクルの機能などを、関数コンポーネント内に使用できるようにするための関数です。

hookを使用する理由

React 公式ドキュメントでは、クラスコンポーネントより hook を用いる関数コンポーネントの方がおすすめだとされています。

なぜクラスコンポーネントではなく関数コンポーネントを使用した方が良いのでしょうか。

実際に両者のソースコードを比較していきましょう。

クラスを使った場合

クラスは this を使用しています。 例えば this.setState などの特殊な状態処理メソッドを指します。
しかし、this は JavaScript の特別なキーワードであり、状況によって異なるものを参照するため、分かり辛い場合があります。

  • メソッドの中では、クラスオブジェクトを指す
  • イベントハンドラーでは、イベントを受け取った要素を指す

それに加えて、コードが多くなると更に複雑になります。
以下はクラスコンポーネントの簡単な例です。


import React from 'react';
class HelloComponent extends React.Component {
  constructor(props) {
      super(props);
      this.state = { name: '' };
      this.handleChange = this.handleChange.bind(this);
  };
  
  handleChange(event) {
      this.setState({ name: event.target.value });
  };
  
  render() {
      const { name } = this.state
      return (
            <div>
                <input value={name} onChange={this.handleChange} />
                <p>Hello {name}</p>
            </div>
      );
  };
};

 

hook を使って関数コンポーネントとして定義した場合

次のコードは、上と同じコンポーネントを関数コンポーネントとして書いたものです。


import React, { useState } from 'react';
const HelloComponent: React.FC = () => {
    const [name, setName] = useState('');
    
    const handleChange = (event) => {
        setName(event.target.value)
    };

    return (
        <div>
            <input value={name} onChange={handleChange} />
            <p>Hello {name}</p>
        </div>
    );
};

 

こちらは this を使用せず、 useState という hook を使って name の値を管理しています。
クラスコンポーネントと比べてコードの量が少なく、読みやすい印象です。

hook でロジックをカプセル化できるので、UIとロジックの分離が容易になります。
また、一度定義した hook は、関数コンポーネント内と他の hook 内でも使いまわせます。

把握しておくべきhookのルール

hook には2つのルールがあります。
hook の使用にあたって、まずこれらを理解しておく必要があります。

  • 関数コンポーネントでのみ使用でき、クラスコンポーネントでは使用できない
  • hookの呼び出しの順番は、毎回のレンダリングで同じである必要がある

尚、呼び出しの順番に関しては、if 条件やループ、ネストした関数の中に hook を入れることもできませんのでその点もご注意ください。

Reactの公式hook紹介

続いて、React が公式で出している hook について紹介します。
ここでは最もよく使われるという理由から useState と useEffect をピックアップしてご説明します。

useState と useEffect 以外にも、useContext、useRef、useCallback などの hook があるので、詳しく知りたい方はこちらの記事を参照してください。
https://ja.reactjs.org/docs/react-api.html#hooks

useState


import { useState } from 'react';
const [state, setState] = useState(initialState);
 

 

useState は state の値とその値を更新するためにセッター関数 setState を返します。
ステート管理のため、クラスコンポーネントのthis.stateとthis.setState()の代わりに使えます。

useEffect


import { useEffect } from 'react';
useEffect(() => {
    // 実行処理
}, []));

 

useEffect は、クラスコンポーネントの componentDidMount、componentDidUpdate、componentWillUnmount のメソッドの代わりに使えます。
1つ目の引数として定義した関数の実行が2つ目の引数の値によって変わります。イメージとしては以下です。

  1. 2つ目の引数の配列が指定されてない場合は、何かのステートが変わる度に実行されます。
  2. 2つ目の引数の配列が空だったら、componentDidMount と同じ動きになります。
  3. 2つ目の引数の配列に変数を指定すると、その変数に変化があったときに実行されます。

その他おすすめhook

その他にも便利な hook はたくさんあります。

react hook form

react hook form はフォームを検証するのに役立つライブラリです。
hook の形にしたメソッドで使用されます。
以下は react-hook-form を使った簡単な例です。


import { useForm } from 'react-hook-form';
const HelloFormComponent = () => {
    const { register, handleSubmit, formState: { errors } } = useForm();
    const onSubmit = (data) => console.log('Hello: ' + data.name);
    return (
        <form onSubmit={handleSubmit(onSubmit)}>
            <input defaultValue="" {...register("name")} placeholder="名前" />
                {errors.exampleRequired && <span>必須項目です</span>}
            <input type="submit" />
        </form>
    );
};
 

 

custom hooks

また、独自の hook を定義することもできます。
こちらは custom hook が集まっているレポジトリです。
https://github.com/streamich/react-use

過去作成したhook紹介

これまで私自身が作成した hook についても1つピックアップしてご紹介します。

useIsScrollAtEnd

この hook は isScrollAtTop と isScrollAtBottom を返します。scroll の位置が一番上もしくは一番下にあるかどうかを教えてくれます。


import { useCallback, useEffect, useState } from 'react';
import throttle from 'lodash/throttle';
const fps = 12;
const useIsScrollAtTopBottom = (
    targetDom: HTMLDivElement | (Window & typeof globalThis) = window,
    scrollTopThreshold = 0
) => {
    const [isScrollAtTop, setIsScrollAtTop] = useState(false);
    const [isScrollAtBottom, setIsScrollAtBottom] = useState(false);
    const target = targetDom;

    const handleScroll = useCallback(() => {
        const scrollPosition =
            'pageYOffset' in target ? target.pageYOffset : target.scrollTop;
        const scrollHeight =
            'document' in target
                ? target.document.documentElement.scrollHeight
                : target.scrollHeight;
        const containerHeight =
            'innerHeight' in target ? target.innerHeight : target.clientHeight;
    
        const maxScrollTop = scrollHeight - containerHeight;

        if (scrollPosition = maxScrollTop) {
            setIsScrollAtBottom(true);
        } else {
            setIsScrollAtTop(false);
            setIsScrollAtBottom(false);
        }
    }, [target, scrollTopThreshold]);

    const throttledScroll = throttle(handleScroll, 1000 / fps);

    useEffect(() => {
        targetDom.addEventListener('scroll', throttledScroll);
        return () => targetDom.removeEventListener('scroll', throttledScroll);
    }, [handleScroll]);

    return { isScrollAtTop, isScrollAtBottom };
};

 

以下は実際の使い方です。
isScrollAtBottom の値が true になったら、loadNextPage() で次のページを取得する処理を実行します。
そうすると、無限スクロールを実現することができます。


const { isScrollAtBottom } = useIsScrollAtTopBottom();
useEffect(() => {
    if (isScrollAtBottom) {
        loadNextPage();
    }
}, [isScrollAtBottom]);

 

 

useIsScrollAtEnd のフックを実装することで、無限スクロールを簡単に実現できるようになりました。

hookは、シンプルで利便性の高い機能

関数コンポーネント + hook はクラスコンポーネントの代わりに使用できます。
クラスよりもシンプルで、コードがとても読みやすくなります。
また、hook は関数コンポーネント内のどこでも再利用できるので、そういった観点からもとても便利です。
是非、皆さまも活用してみてください。

また、弊社では開発からサービスの運用まで、幅広くご支援させていただいております。
是非一度お気軽にお問い合わせください。

また、詳しいサービス内容に関しては、当社ホームページのアジャイルシステム開発に関するページをご参照ください。

CONTACT

無料相談はこちらから
 

このエントリーをはてなブックマークに追加
アバター画像
About The Author

w_tu

何かお困りのことはありませんか?無料でご相談を承っております!