TaikiTkwkbysh
@TaikiTkwkbysh (WAKA Engineer)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

【React】useRefのcurrentに参照が渡されるタイミングについて

解決したいこと

React学習初学者の者です。
React HooksのuseRefを学習中で、ご教示頂きたことがあり投稿いたしました。

useRefのrefについて、参考書及びReactの公式ドキュメントには以下のように記載がありました。

【環境】
sandboxで作成。
reactバージョンは以下の通りです。
スクリーンショット 2022-11-21 23.09.11.png


◆ React公式ドキュメント


  • DOM 要素への Ref の追加 -

コンポーネントがマウントされると React は current プロパティに DOM 要素を割り当て、マウントが解除されると null に戻します。



◆ Typescript&React&Next.jsで作る実践Webアプリケーション開発

refをコンポーネントに渡すと、この要素がマウントされた時、ref.currentにDOMの参照がセットされ、DOMの関数などを呼び出すことができます。



この説明の上で下記の処理を実行したときの挙動が気になりました。
以下は、p要素をクリックしたときにファイルアップロードの選択ダイアログが表示されるソースです。

import React, { useState, useRef } from "react";


export const Sample = () => {

  const InputImageRef = useRef<HTMLInputElement | null>(null);

  const fileRef = useRef<File | null>(null);

  // refの状態確認用メソッド
  const refCheck = (): void => {
    if (InputImageRef.current == null) {
      console.log("nullです");
    } else {
      console.log("current → " + InputImageRef.current);
    }
  };

  // pクリック時のメソッド
  const onClickText = () => {
    refCheck();
    if (InputImageRef.current !== null) {
      InputImageRef.current.click();
    }
  };

  // fileの参照
  const onChangeImage = (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = e.target.files;
    if (files !== null && files.length > 0) {
      fileRef.current = files[0];
    }
  };


  return (
    <div>
      {refCheck()}
      <p style={{ textDecoration: "underline" }} onClick={onClickText}>
        画像をアップロード
      </p>
      <input
        ref={InputImageRef}
        type="file"
        accept="image/*"
        onChange={onChangeImage}
        style={{ visibility: "hidden" }}
      />
    </div>
  );
};

スクリーンショット 2022-11-21 22.57.40.png

この時、

・ 一番最初に画面に表示した時 → refCheckメソッドの結果は "nullです"

・ p要素をクリックする → "current → [object HTMLInputElement] "

という結果になります。



この挙動について、refの説明では、

「要素がマウントされた時にcurrentプロパティにDOMの参照がセットされる」

となっていたにも関わらず、なぜ初期表示時はnullで、p要素をクリックするとinput要素のrefのcurrentプロパティの参照が入るのでしょうか。
今の自分の解釈では、
「初期表示の段階でマウントされているから、その時に既にcurrentに入るのではないのか」
と思ってしまいます。



少し気になったのは、
Sampleコンポーネントのreturn内を一部編集した時にもconsole出力され、その時には

"current → [object HTMLInputElement] "

が出力されました。なので、イベントハンドラを実行したことで再レンダリングされ、マウントされるタイミングでcurrentにDOMの参照が入ったのかとも思いましたが、正直あっている気がしないのでご教示いただけますと幸いです。

何卒、よろしくお願い致します。

0

2Answer

    <div>
      {refCheck()}

この段階(すなわち render時点)で関数refCheck即時に呼び出しているため,その時点でのInputImageRefを参照することになります.
以下の通りこの段階ではまだマウントは完了していませんし,Refの更新も行われていません.

マウント
コンポーネントのインスタンスが作成されて DOM に挿入されるときに、これらのメソッドが次の順序で呼び出されます。

constructor()
static getDerivedStateFromProps()
render()
componentDidMount()

ref の更新は componentDidMount または componentDidUpdate ライフサイクルメソッドの前に行われます。

DOM要素にアクセスしなければならない場合は,関数コンポーネントの場合useEffect等確実にRef更新後のタイミングで呼ばれることを確認してください.

0Like

@Verclene

この度はご対応頂き、誠にありがとうございます。

なるほど。
refにDOMの参照が入るのは、ライフサイクルメソッドcomponentDidMount()の直前、
つまりrenderの後ということですね。

自分がrender中にconsoleで出力しているからまだマウントされておらず、nullになっているとのことで、納得致しました。

自分もご教示いただいた後、再度色々確認してみました。
sandboxにreactのディベロッパーツールがあり、その中にrefの参照先が表示されている箇所があったので見てみたところ、リロードしたらすぐにrefの参照先にinputが入っていました。

スクリーンショット 2022-11-22 22.42.41.png

確認する場所が悪かったのですね...。

大変勉強になりました。
また機会がございましたら、是非ともご対応頂けますと幸いでございます。

以上、宜しくお願い致します。

0Like

Your answer might help someone💌