0️⃣ 소개
이번에 팀 프로젝트를 진행하면서 작성된 할 일의 상세 정보를 표출하는 페이지의 제작을 맡았습니다.
해당 페이지는 케밥 버튼 클릭 시 표출되는 드롭다운 메뉴를 통해 수정 모드로 변경하는 기능을 가지고 있습니다.
이런 부가적인 동작이 UX를 해친다고 생각하여 내용 입력 후 0.5초 동안 입력이 없으면 수정된 내용을 저장하는 기능을 구현해 UX를 향상시키기로 했습니다.
1️⃣ 기능 구현
위에서 설명했던 기능을 구현할 때 Debouncing 기법을 사용할 예정입니다.
리액트에서 보통 텍스트 입력이 변경된 것을 감지할 때 onChange 이벤트 핸들러를 사용합니다.
이 핸들러로 내용이 변경된 순간마다 API를 호출하게 된다면 너무 자주 호출되어 서버에 부담이 될 수 있습니다.
이를 해결하기 위해 setTimeout() 함수를 사용해 타이핑과 관련된 이벤트가 종료한 후 일정 시간 후에 API를 호출하는 방식이 Debouncing 기법입니다.
해당 기법과 useEffect 훅을 사용해 입력된 내용을 감지하고 그 값을 저장하기 위해 API를 호출하는 기능을 구현하려 합니다.
본격적으로 코드를 작성해보겠습니다.
const [text, setText] = useState<string>();
const timer = useRef<NodeJS.Timeout | null>(null);
const newDescription = useRef<string>(description);
const newName = useRef<string>(name);text 상태를 이용해 입력된 내용이 변경되었는지 감지합니다.
API 호출 함수의 딜레이를 줄 setTimeout() 함수 값을 담을 변수를 useRef를 통해 선언합니다.
newDescription과 newName은 각각 입력된 내용, 제목을 저장하는 역할을 수행합니다.
ref로 선언한 이유는 해당 이벤트에 직접 접근하여 입력된 내용을 가져와 API로 전송하기 위함입니다.
만약 state로 선언해서 사용하게 된다면 마지막으로 리렌더링이 일어나기 전의 내용이 API로 전송됩니다.
// 입력한 내용
'안녕하세요'
// state로 저장된 값
'안녕하세ㅇ'이런 문제를 방지하기 위해 ref를 사용했습니다.
const handleDescriptionChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
newDescription.current = e.target.value.trim();
setText(e.target.value);
};
const handleNameChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
newName.current = e.target.value.trim();
setText(e.target.value);
};내용과 이름의 변경 핸들러입니다.
textarea에서 입력되는 내용을 trim() 함수를 통해 맨 앞과 맨 뒤의 공백을 제거한 후 ref에 저장합니다.
또한 state의 값을 변경해 리렌더링을 유발하여 useEffect() 훅의 로직이 실행되도록 합니다.
useEffect(() => {
if (isPending) return;
timer.current = setTimeout(() => {
mutate({
groupId,
taskListId,
taskId,
data: {
name: newName.current,
description: newDescription.current,
done: !!doneAt,
},
});
}, 500);
return () => {
timer.current && clearTimeout(timer.current);
};
}, [isPending, text]);useEffect 훅의 로직입니다.
먼저 컴포넌트가 렌더링 될 때 isPending 상태를 확인합니다. 이 상태는 기존에 상세 정보가 있는지 확인하고 불러오는 tanstack-query의 상태입니다.
데이터가 있는 상태라면 setTimeout() 함수안에 콜백으로 내용 저장을 위한 함수를 500ms 이후에 실행하도록 합니다.
500ms 이내로 타이핑이 계속된다면 useEffect 훅 내부의 로직이 게속 실행되고, 타이핑을 다 멈추고 나서 500ms가 지나면 API를 호출합니다.

이렇게 데이터의 유실 방지 및 UX를 향상시킨 텍스트 입력창을 제작해보았습니다.