useImperativeHandle
useImperativeHandle
์ ref๋ก ๋
ธ์ถ๋๋ ํธ๋ค์ ์ฌ์ฉ์๊ฐ ์ง์ ์ ์ํ ์ ์๊ฒ ํด์ฃผ๋ React ํ
์
๋๋ค.
useImperativeHandle(ref, createHandle, dependencies?)
๋ ํผ๋ฐ์ค
useImperativeHandle(ref, createHandle, dependencies?)
์ปดํฌ๋ํธ์ ์ต์์ ๋ ๋ฒจ์์ useImperativeHandle
์ ํธ์ถํ์ฌ ๋
ธ์ถํ ref ํธ๋ค์ ์ฌ์ฉ์๊ฐ ์ง์ ์ ์ํ ์ ์์ต๋๋ค.
import { forwardRef, useImperativeHandle } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
useImperativeHandle(ref, () => {
return {
// ... ๋ฉ์๋๋ฅผ ์ฌ๊ธฐ์ ์
๋ ฅํ์ธ์ ...
};
}, []);
// ...
์๋์์ ๋ ๋ง์ ์์๋ฅผ ํ์ธํ์ธ์.
๋งค๊ฐ๋ณ์
-
ref
:forwardRef
๋ ๋ ํจ์์์ ๋ ๋ฒ์งธ ์ธ์๋ก ๋ฐ์ ref์ ๋๋ค. -
createHandle
: ์ธ์๊ฐ ์๊ณ ๋ ธ์ถํ๋ ค๋ ref ํธ๋ค์ ๋ฐํํ๋ ํจ์์ ๋๋ค. ํด๋น ref ํธ๋ค์ ์ด๋ ํ ์ ํ์ด๋ ๋ ์ ์์ต๋๋ค. ์ผ๋ฐ์ ์ผ๋ก ๋ ธ์ถํ๋ ค๋ ๋ฉ์๋๊ฐ ์๋ ๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค. -
(์ ํ์ )
dependencies
:createHandle
์ฝ๋ ๋ด์์ ์ฐธ์กฐํ๋ ๋ชจ๋ ๋ฐ์ํ ๊ฐ์ ๋์ดํ ๋ชฉ๋ก์ ๋๋ค. ๋ฐ์ํ ๊ฐ์ props, state ๋ฐ ์ปดํฌ๋ํธ ๋ด์์ ์ง์ ์ ์ธํ ๋ชจ๋ ๋ณ์์ ํจ์๋ฅผ ํฌํจํฉ๋๋ค. React์ ๋ํ ๋ฆฐํฐ๋ฅผ ๊ตฌ์ฑํ ๊ฒฝ์ฐ ๋ชจ๋ ๋ฐ์ํ ๊ฐ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์์กด์ฑ์ผ๋ก ์ง์ ๋์๋์ง ํ์ธํฉ๋๋ค. ์์กด์ฑ ๋ชฉ๋ก์ ํญ์ ์ผ์ ํ ์์ ํญ๋ชฉ์ ๊ฐ์ง๊ณ[dep1, dep2, dep3]
์ ๊ฐ์ด ์ธ๋ผ์ธ์ผ๋ก ์์ฑ๋์ด์ผ ํฉ๋๋ค. React๋ ๊ฐ ์์กด์ฑ์Object.is
๋น๊ต๋ฅผ ์ฌ์ฉํ์ฌ ์ด์ ๊ฐ๊ณผ ๋น๊ตํฉ๋๋ค. ๋ฆฌ๋ ๋๋ง์ผ๋ก ์ธํด ์ผ๋ถ ์์กด์ฑ์ด ๋ณ๊ฒฝ๋๊ฑฐ๋ ์ด ์ธ์๋ฅผ ์๋ตํ ๊ฒฝ์ฐcreateHandle
ํจ์๊ฐ ๋ค์ ์คํ๋๊ณ ์๋ก ์์ฑ๋ ํธ๋ค์ด ref์ ํ ๋น๋ฉ๋๋ค.
๋ฐํ๊ฐ
useImperativeHandle
์ undefined
๋ฅผ ๋ฐํํฉ๋๋ค.
์ฌ์ฉ๋ฒ
๋ถ๋ชจ ์ปดํฌ๋ํธ์ ์ปค์คํ refํธ๋ค ๋ ธ์ถ
๊ธฐ๋ณธ์ ์ผ๋ก ์ปดํฌ๋ํธ๋ ์์ ์ปดํฌ๋ํธ์ DOM ๋
ธ๋๋ฅผ ๋ถ๋ชจ ์ปดํฌ๋ํธ์ ๋
ธ์ถํ์ง ์์ต๋๋ค. ์๋ฅผ ๋ค์ด MyInput
์ ๋ถ๋ชจ ์ปดํฌ๋ํธ๊ฐ <input>
DOM ๋
ธ๋์ ์ ๊ทผํ๋ ค๋ฉด forwardRef
๋ฅผ ์ฌ์ฉํ์ฌ ์ ํ์ ์ผ๋ก ์ฐธ์กฐ์ ํฌํจํด์ผ ํฉ๋๋ค.
import { forwardRef } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
return <input {...props} ref={ref} />;
});
์์ ์ฝ๋์์ MyInput
์ ๋ํ ref๋ <input>
DOM ๋
ธ๋๋ฅผ ๋ฐ๊ฒ ๋ฉ๋๋ค. ๊ทธ๋ฌ๋ ๋์ ์ฌ์ฉ์ ์ง์ ๊ฐ์ ๋
ธ์ถํ ์ ์์ต๋๋ค. ๋
ธ์ถ๋ ํธ๋ค์ ์ฌ์ฉ์ ์ ์ํ๋ ค๋ฉด ์ปดํฌ๋ํธ์ ์ต์์ ๋ ๋ฒจ์์ useImperativeHandle
์ ํธ์ถํ์ธ์.
import { forwardRef, useImperativeHandle } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
useImperativeHandle(ref, () => {
return {
// ... ๋ฉ์๋๋ฅผ ์ฌ๊ธฐ์ ์
๋ ฅํ์ธ์ ...
};
}, []);
return <input {...props} />;
});
์์ ์ฝ๋์์ <input>
์ ๋ํ ref
๋ ๋์ด์ ์ ๋ฌ๋์ง ์์ต๋๋ค.
์๋ฅผ ๋ค์ด ์ ์ฒด <input>
DOM ๋
ธ๋๋ฅผ ๋
ธ์ถํ์ง ์๊ณ focus
์ scrollIntoView
์ ๋ ๋ฉ์๋๋ง์ ๋
ธ์ถํ๊ณ ์ถ๋ค๊ณ ๊ฐ์ ํด ๋ด
์๋ค. ๊ทธ๋ฌ๊ธฐ ์ํด์๋ ์ค์ ๋ธ๋ผ์ฐ์ DOM์ ๋ณ๋์ ref์ ์ ์งํด์ผ ํฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ useImperativeHandle
์ ์ฌ์ฉํ์ฌ ๋ถ๋ชจ ์ปดํฌ๋ํธ์์ ํธ์ถํ ๋ฉ์๋๋ง ์๋ ํธ๋ค์ ๋
ธ์ถํฉ๋๋ค.
import { forwardRef, useRef, useImperativeHandle } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
const inputRef = useRef(null);
useImperativeHandle(ref, () => {
return {
focus() {
inputRef.current.focus();
},
scrollIntoView() {
inputRef.current.scrollIntoView();
},
};
}, []);
return <input {...props} ref={inputRef} />;
});
์ด์ ๋ถ๋ชจ ์ปดํฌ๋ํธ๊ฐ MyInput
์ ๋ํ ref๋ฅผ ๊ฐ์ ธ์ค๋ฉด focus
๋ฐ scrollIntoView
๋ฉ์๋๋ฅผ ํธ์ถํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ๊ธฐ๋ณธ <input>
DOM ๋
ธ๋์ ์ ์ฒด ์์ธ์ค ๊ถํ์ ์์ต๋๋ค.
import { useRef } from 'react'; import MyInput from './MyInput.js'; export default function Form() { const ref = useRef(null); function handleClick() { ref.current.focus(); // ์ด ์์ ์ DOM ๋ ธ๋๊ฐ ๋ ธ์ถ๋์ง ์์ผ๋ฏ๋ก ์๋ํ์ง ์์ต๋๋ค. // ref.current.style.opacity = 0.5; } return ( <form> <MyInput label="Enter your name:" ref={ref} /> <button type="button" onClick={handleClick}> Edit </button> </form> ); }
์ฌ์ฉ์ ์ ์ imperative ๋ฉ์๋ ๋ ธ์ถ
imperative handle์ ํตํด ๋
ธ์ถํ๋ ๋ฉ์๋๋ DOM ๋ฉ์๋์ ์ ํํ๊ฒ ์ผ์นํ ํ์๊ฐ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ์ด Post
์ปดํฌ๋ํธ๋ imperative handle์ ํตํด scrollAndFocusAddComment
๋ฉ์๋๋ฅผ ํ์ํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๋ถ๋ชจ Page
์์ ๋ฒํผ์ ํด๋ฆญํ ๋ ๋๊ธ ๋ชฉ๋ก์ ์คํฌ๋กคํ๊ณ ์
๋ ฅ ํ๋์ ์ด์ ์ ๋ง์ถ ์ ์์ต๋๋ค.
import { useRef } from 'react'; import Post from './Post.js'; export default function Page() { const postRef = useRef(null); function handleClick() { postRef.current.scrollAndFocusAddComment(); } return ( <> <button onClick={handleClick}> Write a comment </button> <Post ref={postRef} /> </> ); }