본문 바로가기

React

[React] Refs, Portals

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