내용에 맞춰서 textarea의 높이값이 적용되어 나타날까요?
⇒ 아니오.
먼저 게시글을 작성했습니다.
그리고 게시글 수정하기 페이지로 이동합니다.
작성한 게시글 | 게시글 수정 페이지 |
---|---|
쨔잔~ 작성된 게시글의 모든 내용이 보이지 않고 첫 줄만 보입니다!
textarea
에 코드를 살펴봅시다.
<textarea
id="content"
rows={1}
{...register('content', {
required: true,
onChange: textareaAutosize,
})}
/>
// textareaAutosize 코드
const textareaAutosize: FormEventHandler<HTMLTextAreaElement> = (e) => {
const element = e.target as HTMLTextAreaElement;
element.style.height = 'auto';
element.style.height = `${element.scrollHeight}px`;
};
textarea
에 rows={1}
을 적용해놓은 상태이기 때문에 첫 줄만 보입니다.
⇒ rows={1}
를 삭제해도 rows
의 기본값이 2이기 때문에 rows
를 삭제하면 2줄까지만 보입니다.
그리고 onChange
이벤트가 발생하면 textareaAutosize
로 인해 textarea
의 높이값이 자동 조절되면서 모든 내용이 나타납니다.
onChange 이벤트 발생 전 | onChange 이벤트 발생 후 |
---|---|
뭐.. 내용은 문제없이 나타나지만 초기에 모든 내용이 보이지 않는다는 것은 문제가 있습니다.
그래서 게시글 수정 페이지 진입 시 작성했던 내용이 온전히 보이게 하기 위해 onFocus
이벤트를 사용해보겠습니다.
textarea
에 포커스 될 때 onChange
이벤트에 적용했던 것처럼 textarea
의 scrollHeight
값을 적용하는거죠!
React-hook-form은 setFocus
메소드를 제공합니다.
setFocus: (name: string, options: SetFocusOptions) => void
name
: string
, 포커스 할 input field 이름options
: { shouldSelect : boolean }
, 포커스에 입력 내용을 선택할지 여부{ shouldSelect : true }
로 설정하면 해당 내용이 선택되어 있습니다.import { useForm } from "react-hook-form"
type FormValues = {
firstName: string
}
export default function App() {
const { register, handleSubmit, setFocus } = useForm<FormValues>();
const onSubmit = (data: FormValues) => console.log(data);
useEffect(() => {
setFocus("firstName");
}, [setFocus]);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("firstName")} placeholder="First Name" />
<input type="submit" />
</form>
)
}
useEffect
안에 setFocus
메소드를 적용하고 포커스를 줄 입력 필드 이름을 인자로 넘겨주면 끝입니다.
onFocus
이벤트그럼 포커스 이벤트가 발생했을 때의 코드를 작성해봅시다!
textareaAutosize
에 적용했던 것과 동일하게 해당 요소의 높이값에 scrollHeight
를 적용합니다.
const handleOnFocusTextarea: FocusEventHandler<HTMLTextAreaElement> = (e) => {
const { target } = e;
target.style.height = `${target.scrollHeight}px`;
};
혹시 위의 코드가 동작하지 않는다면 setTimeout
을 이용하여 비동기적으로 처리해봅니다.
// setTimeout 적용하여 비동기적으로 처리하기
const handleOnFocusTextarea: FocusEventHandler<HTMLTextAreaElement> = (e) => {
const { target } = e;
setTimeout(() => {
target.style.height = `${target.scrollHeight}px`;
}, 0);
};
React-hook-form의 register는
onFocus
메소드를 제공하지 않습니다. 따라서 해당 요소에 직접 onFocus
이벤트에 위의 코드를 적용합니다.
<textarea
id="content"
rows={1}
{...register('content', {
required: true,
onChange: textareaAutosize,
})}
onFocus={handleOnFocusTextarea} // register 내부에 작성하지 않습니다.
/>
const EditPage = () => {
const { register, setFocus } = useForm<{ content: string; }>();
useEffect(() => {
setFocus('content');
}, [setFocus]);
const handleOnFocusTextarea: FocusEventHandler<HTMLTextAreaElement> = (e) => {
const { target } = e;
setTimeout(() => {
target.style.height = `${target.scrollHeight}px`;
}, 0);
};
return (
...
<textarea
id="content"
rows={1}
{...register('content', {
required: true,
onChange: textareaAutosize,
})}
onFocus={handleOnFocusTextarea}
/>
)
}
게시글 수정하기 페이지 진입하면 다음과 같이 게시글의 모든 내용이 나타나고, 커서가 게시글의 마지막에서 깜빡이는 모습을 볼 수 있습니다!
이렇게 적용하기 전에 다시 한 번 contentEditable
을 적용해보았습니다. contentEditable
을 사용하면 높이 조절에 대해 신경쓰지 않아도 되기 때문인데요..
근데 처참히 실패했습니다.
이전 글의 문제점에서의 개행이 문제입니다. 이놈의 개행 문자..!!
제출 버튼 클릭 시 연속된 개행 문자를 replace를 이용해서 하나의 개행문자만 적용되도록 해보았는데.. 만약 수정 페이지에서 내용 변경 안하고 수정 버튼을 누른다?? 그럼 애먼 연속된 개행문자만 계속 사라지는 현상이 발생합니다.
그래서 contentEditable
을 사용하는 것은 마무리 하고 다른 방법을 찾다가 생각보다 쉽게 해결이 되었습니다. 휴-
참고