React - form 구현과 useRef

sebinnnnn·2023년 6월 7일
1

React

목록 보기
4/5
post-thumbnail

리액트로 웹 서비스를 만들다 보면 사용자의 입력 데이터를 받아서 이를 사용하는 경우가 필요하다.
보통, 검색 서비스를 제공할 때 사용자가 입력한 검색 데이터 키워드를 전달받거나 혹은 로그인 및 회원가입을 통해서 사용자의 정보를 얻는 경우가 모두 사용자의 입력 데이터를 받아 이를 사용하는 경우다.
이때, html에서 사용한 form과 input, textarea 등의 form 요소를 사용하게 되는데 여기서 중요한 점은 리액트에서는 html에서와는 다르게 form 요소를 다룬다는 점이다.


1️⃣ 리액트에서의 form 구현

🔗 제어 컴포넌트와 비제어 컴포넌트

리액트에서 form을 구현하는 방식에는 크게 2가지가 있다.
바로 제어 컴포넌트 방식비제어 컴포넌트 방식이다.
간단히 용어를 풀어서 설명하자면, 제어 컴포넌트는 리액트에 의해서 값이 제어되는 입력 form이라는 것이다. 즉, form으로 전달받은 사용자의 입력값을 컴포넌트 내부에서 state로 관리를 한다는 의미인 것이다.
이에 반해 비제어 컴포넌트는 리액트가 제어하는 것이 아니라 form 태그 자체로 사용자 입력 데이터가 관리된다는 것이다.

[ ✨ 제어 컴포넌트 ]
간단하게 제어 컴포넌트에 대해 먼저 살펴보자면, 제어 컴포넌트는 input 태그 등의 데이터 입력 태그에서 사용자가 입력한 값을 그대로 가져오게 된다. 이때, event 객체를 사용하게 되는데 만약 form 요소가 1개가 아닌, 다중 입력 form일 경우 form 요소마다 구분을 하기 위해서 name이라는 속성을 이용하게 된다.
즉, event.target.name을 통해서 해당 form 요소를 가져오게 되고 해당 입력값을 리액트에서 직접 제어를 하게 되는 것이다.
event.target.name을 통해서 가져온 사용자 입력 데이터를 컴포넌트 내부에서 state로 상태관리할 수 있게 된다.

[ ✨ 비제어 컴포넌트 ]
앞서 살펴본 제어 컴포넌트의 경우 event 객체를 통해 사용자 입력 데이터를 가져와 컴포넌트 내부에서 state로 상태 관리를 한다고 했다.
이러한 방식은 dom 자체에 직접적으로 접근하는 것이 아닌 데이터만 가져오는 방식이다.

하지만, 비제어 컴포넌트 방식을 이용하면 사용자 입력 데이터는 물론 해당 dom에 직접 접근할 수도 있다.
이때 사용하는 것이 바로, 함수 컴포넌트의 useRef다.
useRef는 useState나 useEffect와 같이 리액트에서 제공하는 Hook 함수이기 때문에 사용하기 전에는 반드시 import를 해줘야 한다!

제어 컴포넌트에서는 다중 입력 form을 다룰 때 name이라는 속성을 통해 form 요소를 구분한다고 했는데 useRef는 따로 이러한 과정 없이 useRef를 통해 생성한 객체를 해당 form 요소 태그에 연결만 해주면 된다.

- useRef를 사용하기 전에 반드시 import!

const inputRef = useRef()

return (
	<>
  		<input ... ref={inputRef}... />
  	</>
)

위의 코드와 같이 useRef를 통해 생성된 객체를 변수의 값으로 할당을 해준 다음에 이를 연결시킬 태그에 ref 속성으로 식별자를 넣어주면 된다.

이렇게 ref와 input tag를 연결해 주면 inputRef.current를 통해서 해당 input 태그에 직접적인 접근이 가능하고 inputRef.current.value를 사용해서 입력된 사용자 데이터 값을 가져올 수 있게 된다.

이처럼, 리액트에서 form을 구현하기 위해서는 제어 컴포넌트 방식 혹은 비제어 컴포넌트 방식을 사용해야 하는데, 보통의 경우 비제어 컴포넌트 방식보다는 제어 컴포넌트 방식을 사용한다고 한다.
하지만, 어떤 방식이 더 좋은 것인지는 개인적인 생각이고 프로젝트의 성격마다 다르기 때문에 개인적으로 고민을 해보고 알맞은 방식을 사용하면 될 것 같다!


2️⃣ 리액트의 useRef( )

앞서 비제어 컴포넌트의 방식으로 useRef를 사용하는 예시를 살펴봤는데, 사실 dom에 접근하는 방법 말고도 여러 용도로 useRef를 사용할 수 있다.

  1. 포커스나 텍스트 선택 영역 등을 관리할 때
  2. 애니메이션을 직접적으로 실행하고자 할 때
  3. 부모 컴포넌트에서 자식 컴포넌트의 dom에 접근할 때 - forwardRef
  4. useState와 같이 상태 값을 관리하고자 할 때
    ...

위의 4가지 말고도 useRef를 활용할 수 있는 경우가 다양할 수 있지만, 대표적인 사용 예시로 forwardRef와 상태 값 관리에 대해서만 간단히 살펴보려고 한다.

[ ✨ forwardRef ]
컴포넌트 단위로 웹 사이트를 만들다 보면 예기치 못하게 부모 컴포넌트에서 자식 컴포넌트의 dom에 접근해야 하는 경우가 있다.
하지만, 각각 독립적으로 존재하는 컴포넌트가 서로에게 영향을 주는 것은 캡슐화를 깨는 것이기 때문에 지양해야 하는 부분이지만 어쩔 수 없이 꼭 필요한 상황에서는 forwardRef를 활용하면 된다.

(1) 부모 컴포넌트 Func1

function Func1() {
  const inputRef = useRef();

  return (
    <>
      <Func2 ref={inputRef} />
    </>
  );
}

위의 코드와 같이 부모 컴포넌트에서는 기존 useRef 사용 방법과 동일하게 useRef 객체를 생성하면 된다.
이렇게 생성한 useRef를 Func2라는 자식 컴포넌트에게 ref로 넘겨준다.

(2) 자식 컴포넌트 Func2

const Func2 = forwardRef((props, ref) => {
  return <input type="text" ref={ref} />;
});

Func2 자식 컴포넌트는 forwardRef로 해당 컴포넌트를 감싼 후 props를 받는 것처럼 ref로 부모 컴포넌트에서 전달한 useRef 객체를 받은 다음에 해당 ref를 input에 연결을 해준다.

이렇게 설정을 하고 나면 부모 컴포넌트에서 inputRef로 자식 컴포넌트의 input 태그에 직접적인 접근이 가능하게 된다.

[ ✨ useRef로 상태 값 관리 ]
더불어, useRef를 사용해서 useState처럼 상태 값 관리도 가능한데, 그전에 useState를 사용하는 것과 어떤 차이점이 있는지 살펴봐야 한다.

useState의 경우 컴포넌트 내부에서 상태 값을 관리하는 Hook 함수 중 하나로, setState를 통해서 값이 변경되면 컴포넌트가 다시 실행된다. 즉, useState의 경우 상태 값이 변경되면 re-rendering 되는 것이다.
이에 반해, useRef를 통해 생성된 객체의 경우 해당 값이 변경된다고 해도 re-rendering이 되지 않는다.

따라서, 컴포넌트 내부에서 상태 값을 관리하고 싶지만 해당 값이 변경됨에 따라 불필요한 렌더링이 발생하지 않기를 원한다면 useState가 아닌 useRef를 사용하면 된다.

const count = useRef(1);

사용법은 위의 코드와 같이 매우 간단하다.
useRef를 통해서 ( )안에 초기값을 설정해 주면 된다.

이렇게 생성된 useRef 상태 값은 해당 값이 특정 함수 동작으로 변경이 값만 변경이 될 뿐, 컴포넌트가 다시 렌더링 되지 않는다.

profile
🏠 블로그 이전 중 → https://medium.com/@sebinndev

0개의 댓글