以下のuseImperativeHandle
、useLayoutEffect
、useDebugValue
フックが必要な理由がわかりません。ドキュメントの例ではなく、これらを使用できる例を挙げていただけますか。
ベストアンサー1
この回答の冒頭で、これらのフックはほとんど使用されないことを述べさせてください。99% の場合、これらは必要ありません。これらは、まれなコーナーケースのシナリオをカバーすることのみを目的としています。
useImperativeHandle
通常、 を使用すると、useRef
がアタッチされているコンポーネントのインスタンス値が与えられますref
。これにより、DOM 要素を直接操作できるようになります。
useImperativeHandle
非常に似ていますが、次の 2 つのことが可能になります。
- これにより、返される値を制御できます。インスタンス要素を返す代わりに、戻り値が何であるかを明示的に指定します (以下のスニペットを参照)。
blur
ネイティブ関数 ( 、など) を独自の関数に置き換えることができるfocus
ため、通常の動作に副作用が生じたり、まったく異なる動作が発生したりする可能性があります。ただし、関数は好きなように呼び出すことができます。
上記のいずれかを実行したい理由は多数考えられます。ネイティブ プロパティを親に公開したくない場合や、ネイティブ関数の動作を変更したい場合などです。理由は多数考えられます。ただし、はuseImperativeHandle
ほとんど使用されません。
useImperativeHandle
使用時に親コンポーネントに公開されるインスタンス値をカスタマイズします。ref
例
この例では、 から取得する値には、で宣言したref
関数のみが含まれます。他のプロパティは含まれません (blur
useImperativeHandle
これを実証するために値を記録しています)。関数自体も、通常予想される動作とは異なる動作をするように「カスタマイズ」されています。ここでは、 が呼び出された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
場合によっては、特定の値やプロパティをデバッグしたいことがありますが、そのためにはコストのかかる操作が必要になり、パフォーマンスに影響する可能性があります。
useDebugValue
React DevTools が開かれ、関連するフックが検査されるときにのみ呼び出され、パフォーマンスへの影響を防ぎます。
useDebugValue
React DevTools でカスタムフックのラベルを表示するために使用できます。
ただし、私は個人的にこのフックを使用したことはありません。コメントで誰かが良い例を挙げて洞察を与えてくれるかもしれません。