Reactで状態を扱う場面では、useState
やuseEffect
の他に、再描画を伴わずに値を保持したいケースがあります。そのようなときに使われるのが、useRef
です。
今回は、あるシステムで見られた「constで定義したuseRef
に対して値を代入してもエラーにならないのはなぜか?」という疑問を出発点に、useRef
の正しい使い方と注意点を整理します。
constで定義した変数に代入?エラーにならない理由とは
以下のようなコードを見たとき、不思議に思った方もいるかもしれません。
const endDtExtendedDays = useRef(0); endDtExtendedDays.current = coupon.end_dt_min_interval_days;
一見すると、const
で定義された変数に代入しているように見えますが、実はこれは参照先のプロパティを書き換えているだけであり、endDtExtendedDays
自体の参照は変更されていないため、エラーにはなりません。
つまり、useRef
の戻り値は以下のような構造を持っています。
{ current: 任意の値 }
このcurrent
プロパティは自由に読み書きでき、再描画のきっかけとはならないのが特徴です。
useRef
が有効な場面とは
useRef
は、以下のような目的でよく使われます。
- 状態の保持(ただしUI更新の必要がないもの)
- 処理中フラグの管理
- 以前の値の保持
- タイマーIDや外部インスタンスの参照
たとえば、ボタン連打による処理の重複を防止する際には、以下のような使い方が有効です。
const processing = useRef(false); const handleClick = () => { if (processing.current) return; processing.current = true; // 処理を実行 setTimeout(() => { processing.current = false; }, 1000); };
useEffectと連携する際の注意点
useRef
の値は変更しても再描画が発生しないため、useEffect
などの副作用フック内で値を使う場合には注意が必要です。
以下のような実装例がありました。
useEffect(() => { if (startDt) { const now = new Date(); const daysDiff = Math.abs(differenceInDays(now, startDt)); const min = daysDiff <= 30 ? addDays(now, endDtExtendedDays.current) : startDt; setMinDate(min); } }, [startDt]);
このコードでは、endDtExtendedDays.current
の変更は依存配列に含まれていないため、変更後も再評価されません。
解決策
再描画に反映させたい場合は、useState
と組み合わせて以下のようにすると確実です。
const [endDtExtendedDays, setEndDtExtendedDays] = useState(0); useEffect(() => { if (startDt) { const now = new Date(); const isWithinRange = Math.abs(differenceInDays(now, startDt)) <= 30; const min = isWithinRange ? addDays(now, endDtExtendedDays) : startDt; setMinDate(min); } }, [startDt, endDtExtendedDays]); useEffect(() => { const load = async () => { const data = await fetchCoupon(couponId); setEndDtExtendedDays(data.end_dt_min_interval_days); }; load(); }, []);
このようにすると、endDtExtendedDays
が変わった時点で再評価が行われるようになります。
よくある誤解とアンチパターン
useRefを使えば便利だからといって、全ての状態をこれで管理するのはおすすめできません。
特に次のような場合は避けるべきです。
- UIに直接関係する値の保持 →
useState
を使うべきです。 - 副作用に関係する値をuseRefだけで扱う →
useEffect
との組み合わせに注意が必要です。
まとめ
ReactにおけるuseRefの特徴を理解すれば、再描画の無駄を避けつつ、状態を効率よく保持することができます。
- constで定義しても、
useRef
のcurrentは変更可能 - currentの変更は再描画されない
useEffect
との併用時は依存配列に注意- UIと連動する値にはuseStateを使うべき
今回のようなシステム内の不具合や疑問点は、同じようにReactを利用している多くのエンジニアにとっても身近な問題です。
Reactの特性を正しく理解しておくことで、より信頼性の高いフロントエンド実装が可能になります。
- Original:https://minory.org/react-useref.html
- Source:minory
- Author:管理者
Amazonベストセラー
Now loading...