<리액트 훅스 시리즈 1탄 useRef!>

강민수·2022년 4월 29일
1

리액트 훅스

목록 보기
1/1

최근에는 함수형 컴포넌트가 주류를 이루면서 리액트에서도 그에 맞춰 다양한 훅스들이 생겨났다. 그래서 필자 역시 리액트를 사용하면서 보통 많이 쓰이는 유즈스테이트나 유즈 이펙트외에도 추가적인 훅스들을 더 살펴볼 필요성을 느껴 한 번 공부한 것을 토대로 기술해 보고자 한다.

그 첫 번째로 먼저, useRef를 살펴보겠다.

사실 필자 역시 useRef를 종종 사용하긴 했지만, 명확한 사용법이나 사용해야될 상황에 대해 명확하게 사용한 것은 살짝 의구심이 든다.

1. ref 사용법


유즈 레프를 부르면, 레프 오브젝트를 반환한다. 이 오브젝트를 우리가 접근하고자 하는 태그에 ref속성으로 넣어주기만 하면, 정말 쉽게 해당 요소에 접근할 수 있다.

대표적인 사용 케이스로는 텍스트 박스 같은 인풋 요소에 포커스를 줄 때 많이 사용된다. 예를 들어, 로그인 페이지가 로딩 되었을 때, 아이디를 넣는 공간을 굳이 클릭하지 않더라도 자동적으로 포커스가 되어 있게 해 주면, 바로 인식할 수 있으니 편하다. 레프를 사용하면 손쉽게 돔 요소에 접근해서 이런 작업을 할 수 있다. 마치 바닐라 자바스크립트의 document.queryselector( )처럼 말이다.

2. useRef의 사용 시점?

리액트가 대표적인 단방향 데이터 흐름을 가진 것은 리액트를 써본 프로그래머라면, 누구나 아실 것. 따라서 일반적으로 부모와 자식간의 데이터 소통은 props를 통해 이뤄진다. 하지만, 일반적인 이런 흐름을 벗어나 자식 컴포넌트를 수정해야 하는 경우도 있다. 이때 보통 useRef를 쓰면 좋은 이점들이 많이 있다.

1) 저장 공간.

함수형 컴포넌트는 기본적으로 재 랜더링이 되면 내부 변수들이 전부 초기화 된다.

그렇기 때문에, 우리는 가끔 원하지 않는 랜더링으로 인해 곤란한 경우가 있다.

그렇다면 state대신 ref안에 값을 저장하면?
레프의 유용한 점: 우리가 아무리 재랜더링을 한다고 해도 레프 안의 값은 변경되지 않는다!

값이 변화했을 때, 스테이트와 ref에 따라 달라지는 차이는 다음과 같다.

즉, 기존의 스테이트는 값이 변하면 재랜더링이 된다. 하지만, ref는 다르다.

2) dom에 대한 접근.


물론, 리액트는 직접적인 돔을 지양하는 바이지만, 그럼에도 불구하고 가상 돔을 통해 돔에 접근해야 하는 경우가 있기 마련이다.

한 번 이번에는 직접적으로 코드를 통한 실전 예제로 익혀보자.

만약 자주 바뀌는 값을 스테이트 안에 넣었다고 쳐 보자. 그러면 그 값이 바뀔때 마다 계속 랜더링 되고 또 랜더링 될 것. 이러면 랜더링 될 때마다, 계속 데이터를 요청할 것이고 결국 이는 불필요하게 리소스를 소모하는 형태가 될 것이다. 따라서 성능상에서도 안 좋은 영향을 미친다.

여기서 스테이트가 아니라, 레프를 쓰면, 그 값이 아무리 바뀌어도 랜더링을 발생시키지 않아서 성능상에서도 유리하다. 아래 예시에서도, 스테이트가 올라가면 랜더링이 다시 한 번 일어나는 것을 콘솔에서 볼 수 있다. 하지만, 레프를 올리는 버튼을 누르면, 랜더링 콘솔이 안 찍히고, ref의 값만 올라간다.

다음 예시를 살펴 보자.

이번에는 변수와 더불어 ref를 비교해 봤다. 보이시는 가? 그렇다. 재 랜더링이 된다는 것은 결국 해당 변수의 값도 초기화가 된다는 것이다. 하지만, ref는 여전히 값을 유지하고 있다. 이유가 뭘까?

왜냐하면, 레프의 값은 컴포넌트의 전 생애 주기를 가지고 유지가 되기 때문이다.

다음은 일반적인 랜더링에서 랜더링 횟수를 세려고 할 때, 흔히 하는 실수다.


다음과 같이 카운트를 일씩 증가시키는 함수가 있다. 우리의 앱이 몇 번 랜더링 되었는 지 보려고 한다. 그냥 단순히 드는 생각은 다른 랜더 카운트 스테이트를 만들어서 유즈 이펙트 안에 넣어서 올려주면 되겠지? 라고 생각할 수 있다.
과연 그럴까?

무한 루프에 갇히는 것을 볼 수 있다. 에러는 계속 늘어나고, 끊임없는 랜더링 문제가 발생한다. 왜 그럴까? 카운트를 누르면 재랜더링이 될 것이고, 그러면 유즈 이펙트가 돌면서 다시 랜더 스테이트 함수도 계속 발생한다. 그러면 또 랜더링이 발생하고 또 유즈 이펙트 -> 랜더 스테이트 실행. 이런 무한 굴례의 반복이 발생된 것이다.

여기서 ref가 빛을 발하게 된다.

이제 랜더 카운트를 더이상 스테이트가 아닌, ref로 저장해 보자. 그리고 다시 유즈 이펙트 안에 ref를 넣어보자.

레프는 재랜더링을 발생시키지 않으므로, 무한루프에 빠지지 않는다.

이처럼 레프는 변화는 감지해야 하지만, 그 값이 재랜더링을 발생시켜서는 안 될 때 사용한다.

3. 로그인 포커싱 예제.

지금 매우 간단한 로그인 인풋 창이 있다.

지금은 마우스로 인풋창을 눌러야지만, 파랗게 포커싱이 되는 것을 볼 수 있다. 이것을 따로 클릭 없이도 포커싱 되게 만들려고 한다면 어떻게 해야 할까? 이때 레프를 활용해서 돔에 접근하면 훨씬 수월하게 가능하다.

레프에 대한 참조 값으로

const inputRef = useRef();

유즈레프를 선언해 준다. 그리고 유즈 이펙트 안에

useEffect(()=>{
inputRef.current.focus();
},[])

만 해주고 새로고침을 해주면 끝이다. 여기에 로그인 버튼을 누르면, 알러트로 인풋 창에 적은 값을 토대로 환영 문구가 나오도록 추가해 보자.

이것 역시 그렇게 어렵지 않다.
새로운 로그인 함수 안에, 다음과 같이 인풋레프를 활용해서 벨류 값만 넣어주면 된다. 추가로 로그인 후에 다시 인풋창에 포커싱이 가도록 기존의 유즈 이펙트 내부의 포커스 이벤트를 적어주면 좋다.

const login = () =>{
	alert(`환영합니다. ${inputRef.current.value}!`
	inputRef.current.focus();
}

이렇게 유즈레프는 돔 요소에 접근하는 것 외에도 효율적인 컴포넌트 랜더링과 변수 관리에도 효과적이다.

자 이렇게 useRef를 왜 사용하는 지, 그리고 언제 사용하면 좋은 지에 대해 간단하게 살펴봤다. 필자 역시 이번에 공부를 하면서 이제는 조금은 알고 쓸 수 있을 듯하다. 추가적으로 다른 훅스들도 아직 기고할 것들이 남아있기에... 또 공부하고 추가해 보겠다.

긴 글 읽어주셔서 감사하다~ 그러면 다음 훅스까지 안녕히~

profile
개발도 예능처럼 재미지게~

0개의 댓글