RIT Tech Blog

株式会社RITのエンジニアが知見を共有する技術ブログです。

React Hooks使ってリファクタしてみた話

CTOの福田です

React 16.8 リリースされましたね

新機能のReact Hooksを使って自社サービスのコードをリファクタしてみたので、全体的な使用感とかハマったポイントを挙げていこうと思います。

前提

  • Reduxは使ってません
  • statefulなコンポーネントを多用してます
  • React + React RouterのSPA
  • TypeScript

ざっくり

  • 〇 Class ComponentがFunction Componentにできてネストが一段減って行数も微妙に削減されてうれしい
  • useState使うとsetState({hoge: 'fuga'})setHoge('fuga')みたいにできてうれしい
  • useEffectの第二引数が直感的じゃない?

詳しく

Class ComponentがFunction Componentにできる & setStateがシンプルに

何かすごいメリットがあるかって言われると微妙なんですが、単純にネストと行数が削減されるのでよいとおもいます

単純なカウンターの例を書いてみると

class HelloComponent extends React.Component<{}, {count: number}> {
    state = {
        count: 0;
    };

    render() {
        return (
            <button onClick={() => this.setState({count: this.state.count + 1})}>{this.state.count}</button>
        );
    }
}

function HelloComponent() {
    const [ count, setCount ] = useState(0);
    return (
        <button onClick={() => setCount(count + 1)}>{count}</button>
    );
}

になります

useEffectの第二引数

componentDidMountajaxしたりcomponentDidUpdateでrefからdomを操作したい場合はuseEffectの第一引数にコールバック関数渡してその中で処理するんですが、asyncなコールバックが渡せなかったり何も考えずにasyncな関数呼び出してその中でsetStateしてると無限ループしちゃうのでちゃんとドキュメント読みましょう

メッセージ一覧を取得して表示する画面で最初書いてたコード(サンプル用に改変済み

import React, { useState, useEffect } from 'react';
import { Message } from '../entities';
import { MessageRepository } from '../repositories';

export default function Messenger() {
    const [ messages, setMessages ] = useState(new Array<Message>());

    const fetchMessages = async () => {
        setMessages(await MessageRepository.getAll());
    };

    useEffect(() => {
        fetchMessages();
    });

    return (
        <ul>
            {messages.map(m => <li key={m.id}>{m.text}</li>)}
        </ul>
    );
}

useEffectはstateやpropsが変更される度に呼び出されるので、この例ではsetMessagesを呼び出すたびにfetchMessagesが呼び出されて無限ループしてしまいますが、 useEffectの第二引数を使うことによって特定の値が変更された場合のみコールバックを実行するように制御できます

なので、ここに空の配列を渡してやることで初回だけ実行されるコールバックが実現できます

useEffect(() => {
    fetchMessages();
}, []);

これで初回だけ実行されるので、componentDidMount相当になります

最後に

ハマりポイント何個か書こうと思ったんですがほとんどハマらなかったので書くことがありませんでした

現状複雑な状態や副作用を持ってるコンポーネントだと大幅な改修が必要になっちゃうんですが基本的にコード量は減るので、新しいコンポーネント書くときには積極的に使うといいんじゃないでしょうか

RITでは新規事業に携わりたい方を様々な職種で募集しているので、ご興味ある方はぜひオフィスに遊びに来てください!

https://rit-inc.co.jp