useImperativeHandle、useLayoutEffect、useDebugValue を使用する場合 質問する

useImperativeHandle、useLayoutEffect、useDebugValue を使用する場合 質問する

以下のuseImperativeHandleuseLayoutEffectuseDebugValueフックが必要な理由がわかりません。ドキュメントの例ではなく、これらを使用できる例を挙げていただけますか。

ベストアンサー1

この回答の冒頭で、これらのフックはほとんど使用されないことを述べさせてください。99% の場合、これらは必要ありません。これらは、まれなコーナーケースのシナリオをカバーすることのみを目的としています。


useImperativeHandle

通常、 を使用すると、useRefがアタッチされているコンポーネントのインスタンス値が与えられますref。これにより、DOM 要素を直接操作できるようになります。

useImperativeHandle非常に似ていますが、次の 2 つのことが可能になります。

  1. これにより、返される値を制御できます。インスタンス要素を返す代わりに、戻り値が何であるかを明示的に指定します (以下のスニペットを参照)。
  2. blurネイティブ関数 ( 、など) を独自の関数に置き換えることができるfocusため、通常の動作に副作用が生じたり、まったく異なる動作が発生したりする可能性があります。ただし、関数は好きなように呼び出すことができます。

上記のいずれかを実行したい理由は多数考えられます。ネイティブ プロパティを親に公開したくない場合や、ネイティブ関数の動作を変更したい場合などです。理由は多数考えられます。ただし、はuseImperativeHandleほとんど使用されません。

useImperativeHandle使用時に親コンポーネントに公開されるインスタンス値をカスタマイズします。ref

この例では、 から取得する値には、で宣言したref関数のみが含まれます。他のプロパティは含まれません (bluruseImperativeHandleこれを実証するために値を記録しています)。関数自体も、通常予想される動作とは異なる動作をするように「カスタマイズ」されています。ここでは、 が呼び出されたdocument.titleときに入力を設定してぼかしますblur

const MyInput = React.forwardRef((props, ref) => {
  const [val, setVal] = React.useState('');
  const inputRef = React.useRef();

  React.useImperativeHandle(ref, () => ({
    blur: () => {
      document.title = val;
      inputRef.current.blur();
    }
  }));

  return (
    <input
      ref={inputRef}
      val={val}
      onChange={e => setVal(e.target.value)}
      {...props}
    />
  );
});

const App = () => {
  const ref = React.useRef(null);
  const onBlur = () => {
    console.log(ref.current); // Only contains one property!
    ref.current.blur();
  };

  return <MyInput ref={ref} onBlur={onBlur} />;
};

ReactDOM.render(<App />, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>


useLayoutEffect

とある程度似ていますがuseEffect()、React が DOM に更新をコミットした後に実行されるという点で異なります。更新後に要素間の距離を計算したり、更新後のその他の計算や副作用を実行したりする必要があるまれなケースで使用されます。

シグネチャは と同じですuseEffectが、すべてのDOM変更後に同期的に実行されます。これを使用して、DOMからレイアウトを読み取り、同期的に再レン​​ダリングします。内部でスケジュールされた更新はuseLayoutEffect同期的にフラッシュされます。ブラウザが描画する前に

高さが変化する可能性がある絶対配置の要素があり、その下に別の要素を配置したいとします。 を使用して親の高さと上部のプロパティを計算し、それを子の上部のプロパティに適用することdivができます。getBoundingClientRect()

useLayoutEffectここでは、ではなくを使用しますuseEffect。以下の例でその理由を確認してください。

: useEffect(びくびくした行動に注意してください)

const Message = ({boxRef, children}) => {
  const msgRef = React.useRef(null);
  React.useEffect(() => {
    const rect = boxRef.current.getBoundingClientRect();
    msgRef.current.style.top = `${rect.height + rect.top}px`;
  }, []);

  return <span ref={msgRef} className="msg">{children}</span>;
};

const App = () => {
  const [show, setShow] = React.useState(false);
  const boxRef = React.useRef(null);

  return (
    <div>
      <div ref={boxRef} className="box" onClick={() => setShow(prev => !prev)}>Click me</div>
      {show && <Message boxRef={boxRef}>Foo bar baz</Message>}
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("app"));
.box {
  position: absolute;
  width: 100px;
  height: 100px;
  background: green;
  color: white;
}

.msg {
  position: relative;
  border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>

useLayoutEffect

const Message = ({boxRef, children}) => {
  const msgRef = React.useRef(null);
  React.useLayoutEffect(() => {
    const rect = boxRef.current.getBoundingClientRect();
    msgRef.current.style.top = `${rect.height + rect.top}px`;
  }, []);

  return <span ref={msgRef} className="msg">{children}</span>;
};

const App = () => {
  const [show, setShow] = React.useState(false);
  const boxRef = React.useRef(null);

  return (
    <div>
      <div ref={boxRef} className="box" onClick={() => setShow(prev => !prev)}>Click me</div>
      {show && <Message boxRef={boxRef}>Foo bar baz</Message>}
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("app"));
.box {
  position: absolute;
  width: 100px;
  height: 100px;
  background: green;
  color: white;
}

.msg {
  position: relative;
  border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>


useDebugValue

場合によっては、特定の値やプロパティをデバッグしたいことがありますが、そのためにはコストのかかる操作が必要になり、パフォーマンスに影響する可能性があります。

useDebugValueReact DevTools が開かれ、関連するフックが検査されるときにのみ呼び出され、パフォーマンスへの影響を防ぎます。

useDebugValueReact DevTools でカスタムフックのラベルを表示するために使用できます。

ただし、私は個人的にこのフックを使用したことはありません。コメントで誰かが良い例を挙げて洞察を与えてくれるかもしれません。

おすすめ記事