useRef
특징
- 값을 입력창에서 읽어들이고 싶을 때 사용 가능
- 컴포넌트가 재실행되어도 값을 잃지 않음(시스템 내부에서 이루어지기 때문)
* 읽어들이는 목적으로만 사용해야 하며 , 조정하기 위해서 ref를 사용하면
Dom에 직접적으로 접근하게 되기 때문에(react의 개념에 반하게 됨) 사용 자제. 사용자가 아닌 React가 값을 바꾸게 해야함
- useRef로 받는 값은 항상 자바스크립트로 객체
사용방법
export default function Test(){
const testRef = useRef();
function handleClick(){
console.log(testRef.current.value);
}
return (
<>
<input type="text" ref={testRef} />
<button onClick={handleClick}>Click</button>
</>
)
}
=> 위와 같이 ref와 input을 연결하면, input html 속성에 접근 가능함
잘못된 사용
export default function Test(){
const testRef = useRef();
function handleClick(){
console.log(testRef.current.value);
}
return (
<>
<h2>{testRef.current.value ?? 'unknown'}</h2>
<input type="text" ref={testRef} />
<button onClick={handleClick}>Click</button>
</>
)
}
=> 잘못된 ref사용 !
이유 : h2태그에서 오류가 남,
이유는 testRef에 저장된 값을 이 컴포넌트가 처음 렌더링 될 때 가져오고자 함.
첫 렌더링 시에 testRef.current는 정의되지 않은것이기 때문.
다음 렌더링 사이클에서 값에 접근할 수 있음. 하지만 값에 접근 할 수 있더라도 ref는 상태값이 변경 되어도 state와 달리 컴포넌트 함수가 재실행 되지 않기 때문에 State를 사용하는게 올바름
Use State와 Use Refs 비교
State | Refs | |
재실행 여부 | 0 | X |
목적 | UI의 값을 바로바로 적용하고자 할때 | DOM 요소에 직접적인 접근이 필요할 때 |
사용하면 안될 때 | 시스템 내부에 보이지 않는 쪽에서만 다루는 값들이나 UI에 직접적인 영향을 끼치지 않은 값들을 갖고 있을 경우 | 값을 바꾸거나 조정하는 목적으로 사용할 때 |
forwardRef
특징
ref를 자식 컴포넌트에게 전달 할 때 사용
사용방법 - Parent.jsx
export default Parent(){
const [click, setClick] = useState(false);
const parentRef = useRef();
function handleClick(){
parentRef.current.open(); // open()은 Child 컴포넌트에서 userImperativeHandle로 작성한 함수
setClick(!click);
}
return <>
<Child ref={parentRef} text='Clicked'/>
<button onClick={handleClick}>Click</button>
</>
}
사용방법 - Child.jsx
import {forwardRef, useImperativeHandle,useRef} from 'react'
const Child = forwardRef(function Child({text},ref){
const dialog = uesRef();
// 여기서 저장한 함수가 Parent에 있는 ParentRef의 참조에 저장되어 Parent 컴포넌트 내에 존재
useImperativeHandle(ref, ()=>{
return{
open(){
dialog.current.showModal();
}
}
});
return (
<dialog ref={dialog}>
<p>{text}</p>
</dialog>
)
})
export default Child
Portal
특징
컴포넌트에 렌더링이 될 HTML 코드를 DOM 내에 다른 곳으로 옮기는 것
Portal이 필요한 이유 설명
export default Parent(){
const [click, setClick] = useState(false);
const parentRef = useRef();
function handleClick(){
parentRef.current.open(); // open()은 Child 컴포넌트에서 userImperativeHandle로 작성한 함수
setClick(!click);
}
return <>
<Child ref={parentRef} text='Clicked'/>
<button onClick={handleClick}>Click</button>
</>
}
코드의 상황 : 위의 코드에서 Child 컴포넌트의 dialog는 다른 html요소들에 중첩되어 있음, Parent 컴포넌트의 일부로 구성됨
문제 : dialog와 같은 대화상자는 더 높은 층위에 있어야 직관적,
특정 상황에서는 중첩되는 요소가 다른 요소들에 묻혀 숨겨질 수도 있음
해결 : 다른곳으로 위치를 옮겨야 함 => Portal!!
사용방법 - Child.jsx
import {forwardRef, useImperativeHandle,useRef} from 'react'
import { createPortal} from 'react-dom'
// react library - 모든 환경에서 작동 가능한 함수와 기능만 노출
// react-dom library
// react가 dom 과 상호작용
//(브라우저에 redering된 웹사이트와 상호작용)
const Child = forwardRef(function Child({text},ref){
const dialog = uesRef();
// 여기서 저장한 함수가 Parent에 있는 ParentRef의 참조에 저장되어 Parent 컴포넌트 내에 존재
useImperativeHandle(ref, ()=>{
return{
open(){
dialog.current.showModal();
}
}
});
return createPortal(
<dialog ref={dialog}>
<p>{text}</p>
</dialog>
, document.getElementById("modal"))
// 첫번째 인수 : jsx
// 두번째 인수 : Html요소
})
export default Child
사용방법 - index.html
html의 장소를 옮길 div를 하나 추가
<body>
<div id="modal"></div>
<div id="root"></div>
</body>
'React' 카테고리의 다른 글
[React] useContext (0) | 2024.04.08 |
---|---|
[React] useEffect, useCallback (0) | 2024.04.05 |
[React] React Developer Tools (0) | 2024.04.03 |
[React] 정적인 컴포넌트를 보관할 때 (0) | 2024.04.02 |
[React] proxy props 사용하기 (0) | 2024.04.02 |