[解決済み] useImperativeHandle、useLayoutEffect、useDebugValueを使用する場合
質問
なぜ、以下のようになるのか理解できません。
useImperativeHandle
,
useLayoutEffect
および
useDebugValue
フックが必要なのですが、どのような場合に使用できるのか、例を挙げてください。
どのように解決するのですか?
前置きが長くなりましたが、これらのフックはすべて非常に稀にしか使われません。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()
を使用して、親の height および top プロパティを計算し、それらを子の top プロパティに適用するだけです。
ここでは
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のカスタムフックのラベルを表示するために使用することができます。
個人的にはこのフックを使ったことがないのですが。多分、コメント欄の誰かが良い例を挙げて、何かヒントを与えてくれるでしょう。
関連
-
[解決済み] Error: yarn start - エラー コマンド "start" が見つかりません。
-
[解決済み] Reactルータを使ったプログラムによるナビゲーション
-
[解決済み] React JSX内のループ
-
[解決済み] React-routerのURLを更新したり、手動で書き込んだりするとうまくいかない
-
[解決済み] React NativeとReactの違いは何ですか?
-
[解決済み] setStateを呼び出さずにReactコンポーネントを強制的に再レンダリングすることは可能ですか?
-
[解決済み] Reduxの非同期フローになぜミドルウェアが必要なのか?
-
[解決済み] Reactのstateとpropsの違いとは?
-
[解決済み] JSX.ElementとReactNodeとReactElementの使い分けは?
-
[解決済み】ReactJS - "setState "が呼ばれるたびにrenderが呼び出されるのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】Warning.Itが表示されるのはなぜですか?Functions are not valid as a React child?
-
[解決済み] Jestの `beforeEach` グローバルは何のためにあるのですか?
-
[解決済み] Next.jsでWebSocketを利用する
-
[解決済み] MUI Boxは何のためのコンポーネントですか?
-
[解決済み] リアクトです。<tr>は<td>の子として表示できません。コメント > td > tr を参照してください。
-
[解決済み] MUI Boxは何のためのコンポーネントですか?
-
[解決済み] React TypeScriptで作業しているときに、Jestが予期しないトークンに遭遇した
-
[解決済み] axios-mock-adapter onGet mock data not effective.
-
[解決済み] Reactプロジェクトに.envファイルを追加する
-
[解決済み] Reactでグローバル変数を宣言する方法とは?