[우테코 레벨2 페이먼츠] input 자동 포커스 autoFocus VS useEffect
우테코 레벨 2 페이먼츠 2단계 미션 중 다음과 같은 기능 요구사항이 있었다.
입력 필드는 사용자의 입력이 완료되면 다음 필드로 자동으로 이동한다.
먼저 페이먼츠 미션의 기능을 간단하게 소개하자면,
사용자에게 카드 정보를 입력받아 카드를 등록(여기서 등록이란, 모든 폼 정보가 유효한지 확인하고, 확인 버튼 클릭 시 카드 등록 완료 페이지로 넘어가는 행위를 말한다.)하는 서비스이다.
궁금하다면 요기서 사용해볼 수 있다!
위의 요구사항을 다른 말로 동적 입력 UI 구현이라고도 할 수 있다.
페이먼츠 미션에서 동적 입력 UI를 구현하기 위해 신경 쓸 부분에는 크게 두 가지가 있었다.
1. 같은 input 내에서의 자동 포커스
ex) 카드 번호 (카드 번호의 총 input은 4개이며, 올바른 값이 입력되면 다음 input으로 자동 이동한다.)
2. 다른 input간의 자동 포커스
ex) 사용자가 유효한 값을 입력할 때마다 다음 input이 차례대로 나타난다. 등장한 새 input에 바로 자동 포커스가 가는 기능
해당 포스팅에서 다룰 내용은 2번이다.
1번의 경우는 별도의 유효성 검증을 통해 처리해 주었다.
서론이 길었는데, 그래서 오늘의 주제는 다음과 같다.
렌더링 된 새 input 요소에 자동 포커스 주기
🥨 [ 방법 1 - useEffect ]
처음 구현한 방식이다.
// CVCInput 컴포넌트 코드 일부
useEffect(() => {
CVCInputRef.current?.focus();
}, []);
모든 input 컴포넌트에 다음과 같은 코드를 추가해, 해당 컴포넌트가 마운트 되면 포커스를 주도록 했다.
🥨 [ 방법 2 - autoFocus ]
이후 리팩토링을 하면서 해당 방식으로 변경했다.
<input autoFocus />
방법은 매우 간단하다.
자동 포커스를 주고 싶은 input 요소에 autoFocus 속성을 추가해 주면 된다. (input 뿐만 아니라 select, textarea 등에도 적용 가능하다고 한다.)
autoFocus={index === 0}
카드 번호의 경우 4개의 input 중 첫 번째 요소에 자동 포커스를 줘야 했기 때문에 index === 0 조건을 추가해서 사용했다.
두 방법의 결과는 동일하다.
🍑 useEffect와 autoFocus의 차이점
항목 | useEffect | autoFocus |
동작 시점 | 컴포넌트 마운트 후 | 브라우저가 HTML 렌더 후 |
선언 방식 | 명령형 | 선언형 |
조건 제어 | 자유롭게 제어 가능 | 제한적 (true/false) |
🍑 동작 시점
// React의 컴포넌트 렌더링 및 마운트 과정
[React 렌더링 시작]
↓
[Virtual DOM 생성]
↓
[실제 DOM 반영 (autoFocus가 여기서 동작)]
↓
[컴포넌트 마운트 완료]
↓
[useEffect 실행 (focus는 여기서 동작)]
체감이 될 정도의 큰 차이는 아니나, autofocus가 조금 더 빠르다.
🍑 선언 방식
🐰 명령형 (useEffect)
컴포넌트가 마운트 되면 inputRef를 통해 DOM을 수동으로 조작한다.
어떤 시점에, 어떤 방식으로 포커스를 줄지 직접 명령한다.
🦊 선언형 (autoFocus)
처음 렌더링될 때 자동으로 포커스를 가져야 한다는 사실만 선언한다.
어떻게 접근해서 focus()를 호출하는지에 대한 자세한 동작 방식은 숨긴다.
🍑 조건 제어
{showInput && <input autoFocus />}
다음은 JSX에서 autoFocus를 조건적으로 사용한 예시다.
바람직한 코드일까?
autoFocus는 컴포넌트가 처음 생성되는 시점에만 작동한다.
따라서, 이후에 showInput 상태가 변경되어도 감지하지 못하는 경우가 많다.
조건부로 포커스를 제어하기에는 useEffect가 더 적절하다.
렌더링 이후에 실행되므로 상태 변화에 반응할 수 있고, 다양한 조건을 조합할 수 있다.
🐣 내가 useEffect 방식에서 autoFocus 방식으로 변경한 이유
- useEffect는 마운트 이후 동작하기 때문에 선언형 컴포넌트 구조에서 부수효과로 작동한다. (꼭 필요한 경우가 아니라면 최소화하는 걸 권장한다.)
- 해당 상황에서는 굳이 useEffect를 쓸 이유가 없다고 판단했다. 조건이 많거나 달라지는 경우가 아니었고, 컴포넌트 렌더링 시 첫 번째 input에 포커스를 주면 되는 공통 기능이었으므로 autoFocus를 사용해서 충분히 구현 가능했다.
🐣 정리
autoFocus는 선언적으로 포커스를 줄 수 있어 코드가 간결하고 읽기 쉽다.
하지만 조건부 렌더링이 많거나 포커스를 더 정교하게 제어하고 싶다면 useEffect가 필요하다.