[React] useRef()_DOM 접근(feat.일기장)

Hyun·2022년 1월 4일
0

React

목록 보기
5/22
post-thumbnail

💡useRef란?

  • javascript에서 특정 Dom을 선택하는 역할 ex) getElementById, querySelector
  • 특정 DOM에 접근할 때 사용 / 외부라이브러리 사용할때 유용
  • 접근하고자하는 html DOM요소(=주로 태그)에 ref={} 의 형태로 작성
  • React의 Hook함수 중 하나
  • const refContainer = useRef(initialValue);
  • useRef는 .current 프로퍼티로 전달된 인자(initialValue)로 초기화된 변경 가능한 ref 객체를 반환합니다. 반환된 객체는 컴포넌트의 전 생애주기를 통해 유지될 것입니다.
  • 본질적으로, useRef는 .current 프로퍼티(속성)에 변경 가능한 값을 담을 수 있는 "상자"와 같다.
  • useRef() 를 사용하여 Ref 객체를 만들고, 이 객체를 우리가 선택하고 싶은 DOM 에 ref 값으로 설정해주면, Ref 객체의 .current 값은 우리가 원하는 DOM 을 가르키게 된다.

<React 공식문서>
=> 아래 공식문서 인용글은 밑에 예제를 읽고 마지막에 읽으면 더 이해하기 쉬울거같다.

주로 DOM에 접근하는 방법으로 refs에 익숙할 수 있습니다.
ref 객체를 <div ref={myRef} />로 리액트에 전달하면, React는 노드가 변경될 때마다 .current 프로퍼티(속성)을 해당 DOM 노드에 설정합니다.
그러나 useRef()는 ref 속성보다 더 많은 경우에 유용합니다. 이 기능은 클래스에서 인스턴스 필드를 사용하는 방법과 유사한 어떤 가변값을 유지하는 데에 편리합니다.
이것은 useRef()가 순수 자바스크립트 객체를 생성하기 때문입니다. useRef()와 {current: ...} 객체 자체를 생성하는 것의 유일한 차이점이라면 useRef는 매번 렌더링을 할 때 동일한 ref 객체를 제공한다는 것입니다.
useRef는 내용이 변경될 때 그것을 알려주지는 않는다는 것을 유념하세요. .current 프로퍼티를 변형하는 것이 리렌더링을 발생시키지는 않습니다. React가 DOM 노드에 ref를 attach하거나 detach할 때 어떤 코드를 실행하고 싶다면 대신 콜백 ref를 사용하세요.

🎯useRef 로 특정 DOM 선택하기

JavaScript 를 사용 할 때에는, 우리가 특정 DOM 을 선택해야 하는 상황에 getElementById, querySelector 같은 DOM Selector 함수를 사용해서 DOM을 선택했다.

리액트에서도 DOM을 직접 선택해야 하는 상황이 발생하는데 리액트에서는 ref 라는 것을 사용합니다.
(예를 들어서 특정 엘리먼트의 크기를 가져와야 한다던지, 스크롤바 위치를 가져오거나 설정해야된다던지, 또는 포커스를 설정해줘야된다던지 등 정말 다양한 상황 / 추가적으로 Video.js, JWPlayer 같은 HTML5 Video 관련 라이브러리, 또는 D3, chart.js 같은 그래프 관련 라이브러리 등의 외부 라이브러리를 사용해야 할 때에도 특정 DOM 에다 적용하기 때문에 DOM 을 선택해야 하는 상황이 발생 할 수 있습니다.)

  • 함수형 컴포넌트 = ref를 사용할때에는 useRef()라는 Hook 함수를 사용한다.
  • 클래스형 컴포넌트 = 콜백 함수를 사용하거나 React.createRef 라는 함수를 사용한다.

예제

일기저장버튼을 클릭했을때, 작성자와 일기가 정상적으로 입력이 되었는지 확인하고 입력이 되지않았다면 알람대신 focus하기

📢먼저, React의 Hook함수 중 하나인 useRef기능을 쓸것이기 때문에 상단에 import { useRef } from "react";를 작성해주고 기능을 사용한다고 알려준다.

작성자와 일기가 정상적으로 입력이 되었는지 확인하기위해서는 일기저장버튼을 누르면 문자열갯수를 확인해주고 작성이안되어있으면 input태그의 입력란, textarea태그의 입력란에 focus를 두는 방향으로 했다.

JS에서는 getElementById, querySelector로 태그를 찾아서 지정을했지만,
리액트에서는 const authorInput = useRef();, const contentTextarea = useRef(); useRef()함수를 호출해서 반환값을 authorInput이라는 const(상수)에 담아주었다
상수로 정의한 authorInput에는 React.MutableRefObject가 저장이되고 MutableRefObject은 html DOM요소에 접근할 수 있는 기능을 해준다.

이렇게 정의를했으면 쓰고싶은 태그 안에가서 ref={authorInput},ref={contentTextarea}를 넣어준다. authorInput,contentTextarea라는 객체를 통해서 input,textarea태그에 접근할 수 있게된다.

그 후, 일기저장버튼을 누르면 문자열갯수를 확인하고 focus를 두기위해 handleSubmit에 아래코드와같이 작성해준다.

    const handleSubmit = ()=>{
        if (state.author.length < 1){
            //focus줘야할 곳
            authorInput.current.focus();
            return;
        }
        if (state.content.length < 5){
            //focus줘야할 곳
            contentTextarea.current.focus();
            return;
        }
        alert("저장성공");
    };

ref객체(DOM요소를 선택하는 useRef()라는 기능으로 생성됨) 현재가르키는값을 current라는 프로퍼티로 불러와서 사용할 수 있다.
즉,authorInput.current는 input태그의 입력란이고, contentTextarea.current는 textarea태그의 입력란이다.

<전체코드>

import { useRef, useState } from "react";

const DiaryEditor = () => {
    const  [state, setState] = useState({
        author : "",
        content : "",
        emotion : 1,
    });
    
    const authorInput = useRef();
    const contentTextarea = useRef();

    const handleChangeState = (e)=>{
        setState({
        ...state,
        [e.target.name] : e.target.value,
    });
};
    const handleSubmit = ()=>{
        if (state.author.length < 1){
            authorInput.current.focus();
            return;
        }
        if (state.content.length < 5){
            contentTextarea.current.focus();
            return;
        }
        alert("저장성공");
    };


    return <div className="DiaryEditor">
        <h2>오늘의 일기</h2>
        <div>
            <input 
            ref={authorInput}
            name="author"
            value={state.author} 
            onChange={handleChangeState}
            />
        </div>

        <div>
            <textarea 
            ref={contentTextarea}
            name="content"
            value={state.content} 
            onChange={handleChangeState}
            />
        </div>

        <div>
            <select 
            name="emotion" 
            value={state.emotion} 
            onChange={handleChangeState}>
                <option value={1}>1</option>
                <option value={2}>2</option>
                <option value={3}>3</option>
                <option value={4}>4</option>
                <option value={5}>5</option>
            </select>
        </div>

        <div>
            <button onClick={handleSubmit}>저장하기</button>
        </div>
    </div>
};

export default DiaryEditor;



🚀참고자료

useRef 로 특정 DOM 선택하기
React공식문서_useRef
React강의_이정환강사

profile
FrontEnd Developer (with 구글신)

0개의 댓글