ref는 key와 마찬가지로 React의 독특한 prop이다.
<input ref={inputRef} />
이렇게 ref을 넘기면
inputRef.current를 통해 input 엘리먼트에 직접 접근할 수 있다.
ref prop에는 특정 형태의 객체(current 속성을 갖는)만을 할당할 수 있다.
import React, { useRef } from "react"
function Field() {
const inputRef = useRef(null)
function handleFocus() {
inputRef.current.disabled = false
inputRef.current.focus()
}
return (
<>
<input disabled type="text" ref={inputRef} />
<button onClick={handleFocus}>활성화</button>
</>
)
}
button 엘리먼트의 클릭(click) 이벤트 핸들러에서 inputRef.current로 간단하게 input 엘리먼트를 제어할 수 있다.
import React, { useRef } from "react"
import music from "./music.mp3"
function Player() {
const audioRef = useRef(null)
const handlePlay = () => {
audioRef.current.play()
}
const handlePause = () => {
audioRef.current.pause()
}
return (
<>
<figure>
<figcaption>Eyes on You (Sting) - Network 415:</figcaption>
<audio src={music} ref={audioRef}>
Your browser does not support the
<code>audio</code> element.
</audio>
</figure>
<button onClick={handlePlay}>재생</button>
<button onClick={handlePause}>중지</button>
</>
)
}
useRef() 훅(hook) 함수로 audioRef 객체를 생성한 후, 엘리먼트의 ref prop에 설정해주었다. 따라서, 이벤트 핸들러 함수 내에서는 audioRef.current를 통해 엘리먼트의 play()와 pause() 함수를 호출할 수 있습니다.
import React, { useRef } from "react"
function Input({ ref }) {
return <input type="text" ref={ref} />
}
function Field() {
const inputRef = useRef(null)
function handleFocus() {
inputRef.current.focus()
}
return (
<>
<Input ref={inputRef} />
<button onClick={handleFocus}>입력란 포커스</button>
</>
)
}
Field >> Input >> input 엘리먼트 순서로 ref를 전달한다.
그럴듯 해보이지만
ref는 일반 prop이 아니기 때문에 Input에서 받아올때 ref1과 같은 다른 이름을 사용해야함
→ 보기 힘들어진다.
위에 Input엘리먼트를 다음과 같이 forwardRef()함수로 감싸면 ref를 그대로 전달할 수 있다.
const Input = forwardRef((props, ref) => {
return <input type="text" ref={ref} />
})
// Player.jsx
import React, { useRef } from "react"
import Audio from "./Audio"
import Controls from "./Controls"
function Player() {
const audioRef = useRef(null)
return (
<>
<Audio ref={audioRef} />
<Controls audio={audioRef} />
</>
)
}
export default Player
/ Audio.jsx
import React, { forwardRef } from "react"
import music from "./music.mp3"
function Audio(prop, ref) {
return (
<figure>
<figcaption>Eyes on You (Sting) - Network 415:</figcaption>
<audio src={music} ref={ref}>
Your browser does not support the
<code>audio</code> element.
</audio>
</figure>
)
}
export default forwardRef(Audio)
→ forwardRef는 한 다리 건너서(할아버지가 손주에게) 엘리먼트의 속성에 접근할때 유용하다.
// Controls.jsx
import React from "react"
function Controls({ audio }) {
const handlePlay = () => {
audio.current.play()
}
const handlePause = () => {
audio.current.pause()
}
return (
<>
<button onClick={handlePlay}>재생</button>
<button onClick={handlePause}>중지</button>
</>
)
}
export default Controls
forwardRef() 함수를 호출할 때 다음과 같이 익명 함수를 넘기면 브라우저에서 React 개발자 도구를 사용할 때 컴포넌트의 이름이 나오지 않아서 불편할 수가 있다.
const Input = forwardRef((props, ref) => {
return <input type="text" ref={ref} />
})
const Input = forwardRef(function Input(props, ref) {
return <input type="text" ref={ref} />
})
function Input(props, ref) {
return <input type="text" ref={ref} />
}
Input = forwardRef(Input)
const Input = forwardRef((props, ref) => {
return <input type="text" ref={ref} />
})
Input.displayName = "Input"
import React, {useState, useImperativeHandle, forwardRef } from 'react'
// props와 ref를 인자로 받음
function ChildCompo(props,ref){
const [name, setName]=useState('');
const [age, setAge]=useState(0);
// 1번인자 : ref
// 2번인자 : 현재 컴포의 값을 부모컴포가 접근할수 있는 CB함수를 전달
useImperativeHandle(ref, () => ({
addAge : value => setAge(age + value),
getNameLength : ()=> name.length,
}))
return (
<div>
<p>{`name is ${name}`}></p>
<p>{`age is ${age}`}></p>
// ...
</div>)
}
// 여기서 forwardRef를 씌워줌으로 ref 매개변수를 사용할수 있게됨
// 부모컴포넌트에서 useRef()를 사용하고 자식의 useImprerativeHandle에 전달한 객체를 사용해 값 수정 가능
export default forwardRef(ChildCompo)
function ParentCompo () {
const childCompoRef = useRef();
const onClick = () => {
if (childCompoRef.current) {
console.log('current name length:', childCompoRef.current.getNameLength();)
childCompoRef.current.addAge(5);
}
}
return (
<div>
<Profile ref={profileRef} />
<button onClick={onClick}>add age 5</button>
</div>
)
}
→ 자식컴포넌트의 ref를 이용해 메소드 호출이 가능해짐