함수 컴포넌트에 ref 전달하기
1. 프롤로그
input, select, button 등 폼 데이터를 다루기 위해
자주 사용되는 요소들이 있다
이러한 엘리먼트에 styled-components로 스타일 구성을 하거나
혹은 커스텀 훅을 사용하여 상태를 관리할 수 있도록
직접 함수 컴포넌트를 만들어 사용한다
🤔🤔🤔
그렇다면
ref를 함수 컴포넌트에서 어떻게 사용하는지 알아보자
2. ref 이해하기
ref가 왜 필요한지 잠시 살펴보자면
(알고 있다면 pass 하도록 하자👏)
기존 자바스크립트에서는
id, class, name, data 등 속성을 지정하여
getElementById와 같은 메서드를 사용하여 선택자로 선언할 수 있었다
ref란
리액트에서 DOM 엘리먼트에 직접 접근하여 여러가지 작업이 필요할 때
엘리먼트에 이름을 달아두고 사용한다고 생각하면 이해하기 쉽다
2-1. 기본적인 사용법
ref를 지정하면 해당 엘리먼트를 .current 객체로 받아 조작할 수 있다
useRef(Hooks API)를 사용하면 간단하게 적용할 수 있다!
2-2. 리렌더링 방지
일반적으로
리액트의 컴포넌트는 state가 변경되면 리렌더링이 발생되지만
const Main = () => {
const [initValue, setInitValue] = useState({
price: "",
qty: ""
});
console.count("렌더링"); // 렌더링 시 콘솔 출력
const handleInput = (e) => {
const {name, value} = e.target;
setInitValue(prevState => ({
...prevState,
[name]: value
}));
};
return (
<>
<input
type="number"
name="price"
placeholder="금액"
value={initValue.price}
onChange={handleInput}
/>
<input
type="number"
name="qty"
placeholder="수량"
value={initValue.qty}
onChange={handleInput}
/>
<input
type="number"
name="total"
placeholder="합계"
value={initValue.price * initValue.qty}
/>
</>
)
}
// 렌더링: 1
// 렌더링: 2
// 렌더링: 3
// ...
ref 객체의 .current 속성을 변형하는 것은 렌더링에 영향을 주지 않는다.
이로 인하여 값을 보유하거나 변경해야 하는 목적에 적합하다
const Main = () => {
const inputPriceRef = useRef("");
const inputQtyRef = useRef("");
const inputTotalRef = useRef("");
const handleInput = () => {
inputTotalRef.current.value = inputPriceRef.current.value * inputQtyRef.current.value;
};
return (
<>
<input
type="number"
name="price"
placeholder="금액"
ref={inputPriceRef}
onChange={handleInput}
/>
<input
type="number"
name="qty"
placeholder="수량"
ref={inputQtyRef}
onChange={handleInput}
/>
<input
type="number"
name="total"
placeholder="합계"
ref={inputTotalRef}
/>
</>
)
}
3. ref 전달하기
리액트 공식문서에 의하면
함수 컴포넌트는 애초에 인스턴스가 없기 때문에 ref 속성을
사용할 수 없다고 안내하고 있다.
😨😨😨
그렇다면
정녕 방법이 없는걸까
3-2. forwardRef
물론 있다.
forwardRef로 함수 컴포넌트에 ref를 받아올 수 있다
import React, {forwardRef} from "react";
const Input = forwardRef((props, ref) => {
return (
<>
<input
type={props.type}
id={props.id}
name={props.name}
value={props.value}
ref={ref}
/>
</>
);
});
export default Input;
좋다.
ref를 제대로 받아오는 것을 확인할 수 있다
3-2. useImperativeHandle
그렇다면
부모 컴포넌트에서도 자식요소의 ref를 호출할 수 도 있을까?
import Import from "./Input";
const inputRef = useRef("");
return (
<Input
type="text"
name="input"
ref={inputRef}
/>
<button type="button" onClick={() => inputRef.current.onFocus()}>focus!</button>
)
있다.
useImperativeHandle 훅을 사용하면 가능하다.
import React, {forwardRef, useImperativeHandle} from "react";
const Input = forwardRef((props, ref) => {
const inputRef = useRef();
useImprativeHandle(ref, () => ({
onFocus: () => {
inputRef.current.focus();
}
}));
return (
<>
<input
type={props.type}
id={props.id}
name={props.name}
value={props.value}
ref={ref}
/>
</>
);
});
export default Input;
이제 부모 컴포넌트에서 forwardRef가 적용된 자식요소의 ref에
접근하여 .current 속성을 원하는대로 사용할 수 있습니다.
3-3. 전체 예제 코드
📁 Home.js
import React, {useRef} from "react"; import Import from "./Input"; const Home = () => { const inputRef = useRef(""); const onCreate = () => { inputRef.current.onFocus(); inputRef.current.value = "Ref"; } return ( <Input type="text" name="input" ref={inputRef} /> <button type="button" onClick={onCreate}>Here!</button> ) } export default Home;
📁 Input.js
import React, {forwardRef, useImperativeHandle} from "react"; const Input = forwardRef((props, ref) => { const inputRef = useRef(); useImprativeHandle(ref, () => ({ value: props.value, onFocus: () => { inputRef.current.focus(); } })); return ( <> <input type={props.type} id={props.id} name={props.name} value={props.value} ref={ref} /> </> ); }); export default Input;
4. 정리
✔ ref가 왜 필요한가 알 수 있다
✔ 함수 컴포넌트에 ref를 전달할 수 있다
✔ 상태 관리를 위해 ref 남용은 자제해야 한다
Author And Source
이 문제에 관하여(함수 컴포넌트에 ref 전달하기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@mujaen/함수-컴포넌트에-ref-전달하기저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)