ReactでuseRefを使うとき、関心があるのは「React useRef 使い方 非推奨」というキーワードです。このキーワードで検索する人は、useRefの基本的な使い方だけでなく、「どのような使い方が避けるべきか」「代替の適切な方法は何か」を知りたいはずです。この記事では、現場で使える具体例とともに、非推奨パターンから学び、安全で効率的な利用方法を体系的に解説します。
React useRef 使い方 非推奨な場面とその背景
ReactのuseRefには、正しい使い方がありますが、誤った使い方はバグや予期せぬ挙動の原因となります。まずはどのような状況が「使い方非推奨」とされるのかを理解しましょう。背景には、useStateとの違いやReactのレンダリングモデルへの理解不足があります。このセクションでは、具体的な非推奨パターンとその理由を整理します。
UI表示に影響する値をuseRefで管理する
useRefで状態を管理しているように見えるコードはよくありますが、refの更新はレンダリングを引き起こしません。そのため、画面に表示すべき値をrefで扱うと、見た目の更新が行われず、ユーザーは変化がないと感じることがあります。UIに直接関係する値は、必ずstateで管理することが望ましいです。
レンダリング中にref.currentを読み書きする
レンダリング中にref.currentを読み書きするのはReactの純粋性を壊すような行為です。初回レンダリングではref.currentがnullであることが多く、値が未定のままで処理されることがあります。また、後続のレンダリングで値が変わったとしてもそれをReactが検知しないため、ロジック全体が不安定になります。
stateとrefを重複して使うアンチパターン
stateとrefを同じ目的で重複させて管理するコードも見られます。例えばある値をrefで保存しつつ、その値の変化時にstateを更新して強制的に再レンダリングさせるようなケースです。これは設計として曖昧であり、可読性・メンテナンス性を低下させます。
React useRef を使うべき場面と正しい設計原則
非推奨なパターンを避けるには、useRefを使うべき場面を正しく把握する必要があります。useRefはレンダーに関係しない値を保持するためのものです。例えば、DOM参照、タイマーID、前回のpropsやstateの値などです。このセクションではどんな設計原則が使い分けの基準になるかを整理します。
レンダリングに影響しない内部ロジック用の値
レンダリングの外で使われ、UI更新を伴わない値の管理にuseRefは最適です。例えばタイマーのID、外部APIから取得したデータのキャッシュ、あるいは変数の前回値などです。こうした用途では、stateを使うと不必要な再レンダリングを引き起こすため、refが効率的です。
DOMノードに対する操作が必要なとき
フォーカスをセットする、スクロール位置を取得する、要素のサイズや位置を測る、あるいは外部ライブラリで要素を直接操作する必要があるような場面では、useRefでDOMノードにアクセスすることが適切です。この目的でrefを使うことはReactでも認められており、安全な使い方とされています。
レンダリング性能の最適化としての役割
頻繁な状態更新でパフォーマンスに悪影響が出るようなケースでは、stateではなくuseRefを使って更新頻度を制御することが有効です。例えば入力文字列の一時保存、継続する処理で前回の値と比較する用途などでは、レンダリングを抑える工夫として使われます。
React useRef の具体的な安全実装テクニック
使い方を誤ると非推奨となるrefですが、適切に使えば強力なツールです。このセクションでは実際のコード例を交えて、安全性を高め、保守性を確保するテクニックを紹介します。これらを使うことで「使い方非推奨」にならない実装ができます。
初期化を条件付きで行うパターン
refの初期値に重い処理を直接渡すと、レンダリングの際に毎回その処理が実行されて無駄になります。初期値をnullにして、最初の必要なタイミングで初めて値を設定するように設計するとパフォーマンスを向上できます。これはレンダーコストを削減するための最新の常識です。
effectフックやハンドラ内でのみref.currentを触る
レンダリング中にref.currentを操作すると予測不能な動きになるため、読み書きはuseEffectやイベントハンドラ内で行います。これによりReactのレンダリングモデルに沿った、安定した動作が得られます。特にStrict Modeでの再レンダリングに耐える設計が可能です。
stateとrefを使い分けるチェックリスト
どちらを使うべきか迷ったら以下の基準で判断すると良いです。UIに影響する値かどうか。レンダー回数を減らす必要があるか。外部APIやブラウザAPIとのやりとりかどうか。値があるタイミングでnullになる可能性があるかどうか。これらを順に考えて選択することで、非推奨なパターンを未然に防げます。
非推奨な使い方を避けるための比較表
使い方非推奨なパターンと推奨される代替方法を比較することで、設計判断がしやすくなります。代表的な例を表にして整理します。
| 誤ったパターン | 推奨される代替 |
|---|---|
| UI表示に関わる値をrefで管理し画面が更新されない | stateを使って値の変化をReactにレンダリングさせる |
| レンダー中にref.currentを書き換える/読む | useEffectやイベントハンドラ内で扱う |
| stateとrefで同じ値を二重管理する | 目的を明確にして一方に統一する |
| DOMを直接操作してReact外で要素を削除・改変する | ReactのレンダリングとDOM構造を尊重する設計にする |
最新情報に基づくReactのバージョンアップでのuseRefへの変更点
Reactは継続的に改良されており、useRefも例外ではありません。最新バージョンではrefにまつわる型制約の更新や、文字列refの非推奨化などが行われています。これらの変更を知っておくことが、安全な実装と将来の互換性を高めるポイントです。
文字列refの廃止とrefコールバックの推奨
以前はclassコンポーネントで文字列refを使うことがありましたが、現在では非推奨です。代わりに関数形式のrefコールバックを使うことが標準とされており、型安全性と予測可能性の面で優れています。文字列refの動作は将来のバージョンで削除されているため、早めの移行が望ましいです。
useRefの初期引数の必須化と型関連の改善
最新リリースではuseRefを呼び出す際に引数が必須となり、型システムとの整合性が強化されています。初期値を渡さない書き方は型チェックで警告の対象になることがあります。nullやundefinedを明示的に渡して初期化するスタイルが、安全かつ将来的な変更に対応しやすい方式とされています。
eslintプラグインによるrefsの利用ルール強化
React公式のlintルールで、レンダー中のref.currentの読み書き禁止や、UIに使われるべきstateと非表示値(ref)の使い分けを強制するルールが追加されています。これによりコードレビュー時に非推奨なパターンが検出されやすくなり、開発者のミスを防ぐ設計が促進されます。
実際のコード例:非推奨パターンと改善パターン
理論だけでは理解しきれない部分があります。ここでは実際に誤った使い方と、その改善例を示しながら、どのような点が問題でどのように直せばよいかを具体的に見ていきます。これによってコードの読み手・保守者もより理解しやすくなります。
非推奨例:UI更新が反映されないカウンター
非推奨な例として、ボタンをクリックしたときにカウンターが増えるが、画面の数字が変わらないというコードがあります。これはrefで値を管理しており、ref.currentをイベントハンドラで変更しているためです。Reactはこれを検知せずレンダリングを起こさないので、画面が変わりません。
改善例:stateを使った正しいカウンター
同じ機能をstateで管理することで、値の変化に応じて自動的に再レンダリングされ、UIが最新状態を反映します。stateの初期化、更新関数の呼び出し、JSX内での値参照という基本的な形式を守ることが重要です。
非推奨例:レンダー中にref.currentを操作してしまうケース
レンダー関数の中でref.currentを書き換えるコードがあります。これは純粋関数であるReactコンポーネントの性質に反しており、再レンダリングの際に不整合が起きたり、Strict Modeで二度描画されたときに予期しない状態になります。
改善例:useEffectでのref.current操作
useEffectフックを使って、レンダリング後にref.currentを操作する方法が推奨されます。これによりDOMが確実に生成された後でref.currentが安全に参照可能となり、不具合のリスクが低くなります。またイベントハンドラ内部でも同様の方法で扱います。
まとめ
useRefはReactコンポーネントでレンダーに影響しない値を保持するための強力なツールですが、「React useRef 使い方 非推奨」とされるパターンを避けることが重要です。UI表示に関する値をrefで扱うこと、レンダリング中にref.currentを読んだり書いたりすること、stateとrefの重複管理などは特に注意が必要です。
推奨される設計原則としては、表示に影響する値は必ずstateで管理すること、DOMノード操作やタイマーIDなど非表示の情報はrefに任せることが適切です。最新のReactバージョンでは、文字列refの廃止や初期引数の必須化、lintルールの強化などが進んでおり、安全実装のベストプラクティスは進化しています。
今回紹介した比較表とコード例を参考に、自分のプロジェクトで現在使われているuseRefのパターンを見直してみてください。正しい設計を意識することで保守性・可読性が向上し、予期せぬエラーを未然に防げるようになります。
コメント