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の第二引数
componentDidMount
でajaxしたり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では新規事業に携わりたい方を様々な職種で募集しているので、ご興味ある方はぜひオフィスに遊びに来てください!