코로 넘어져도 헤딩만 하면 그만
[MD]ReactQuill register로 텍스트 글자 수 제한(MaxLength) 본문
React Quill을 사용하면서 텍스트 수를 1500자까지만 받아야 되는 조건이 붙었다.
input 라면 아래처럼 maxLength를 사용해서 처리하면 되는데... ...
<input
ref={inputRef}
type="text"
value={value}
maxLength={15}
/>
이상하게도 React Quill에는 maxLength가 존재하지 않아 당혹스러웠다. 텍스트 에디터인데 글자 수 max 조건을 거는 게 이렇게 어려워서야. 가장 자주 쓰는 기능이 아닌가? (아직도 왜 maxLength가 없는지 모르겠다.)
하지만 서치를 해도 간단하게 해결하는 방법은 찾을 수 없었고... 공식 문서에서도 찾지 못한 것인지 없는 것인지...
어쩔 수 없이 아래와 같이 삽질을 시작했다.
1. onChange의 함수로 통제 시도... but...
처음에는 별 생각 없이 onChange를 통해 텍스트를 MAX_TEXT_LENGTH를 넘으면 잘라내는 함수를 전달하는 방식을 시도했다. 물론 MAX_TEXT_LENGTH는 1500자로 상위에 상수를 설정했다.
const handleTextChange = (content: string, source: string) => {
if (source === 'user') {
if (content.length > MAX_TEXT_LENGTH) {
setValues(content.slice(0, MAX_TEXT_LENGTH));
} else {
setValues(content);
}
}
};
이제 QuillWrapper에다가 onChange를 걸어서 변화할 때마다 handeTextChange를 실행시킨다.
<QuillWrapper
theme="snow"
modules={modules}
formats={['bold', 'color']}
value={values}
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
className={styles.customQuill}
onChange={handleTextChange}
/>
결론적으로는 텍스트에 slice가 되기는 하는데... onChange가 실시간으로 먹히지 않아 텍스트를 쓰던 중 1500자를 넘었는데도 계속 이어서 작성이 가능한 문제가 생겼다. onChange는 외부를 클릭하여 focus가 에디터로부터 벗어났을 때 적용되며, 이때 handleTextChange함수가 실행되면서 텍스트를 MAX LENGTH만큼 잘라내게 된다.
즉, 유저는 1500자 넘었는데도 warning 없이 계속 글을 이어서 쓰다가... 드디어 다 썼다고 생각하며 외부를 클릭하면...
초과된 글자 수가 썩둑 잘려버리는 비극이 발생한다.
끔찍하다. 이것만은 안 된다는 생각에 다른 방법을 찾기 시작했다.
그렇다고 무한히 텍스트 제한을 풀어줄 수도 없고....
2. Ref를 적용하는 방법
서치하다가 발견한 것인데 QuillWrapper에 ref를 걸어 직접 글자 수를 감시하는 방법이 있었다. Quill 에디터 인스턴스를 참조하고 text-change 이벤트를 통해 실시간으로 텍스트 길이를 제한하는 방식이다.
문제는 QuillWrapper에 직접 ref를 쓸 수 없다고 에러가 떴다. ReactQuill 컴포넌트가 기본적으로 ref를 지원하지 않기 때문이다. ref가 아니라 forwardRef로 ReactQuill을 감싸는 래퍼 컴포넌트를 작성해야 한다고 하는데, .......
... 글자수 제한 좀 하겠다고 외부에 래퍼 컴포넌트까지 만드는 게 옳은 선택인지 알 수가 없었다.
작은 기능을 위한 전체 구조의 변경은 신중해야 하는 것이다.
다시 서치.
💡 3. Quill.register로 커스텀 모듈 추가
최종적으로 적용한 방식이다. Quill의 register을 사용한다.
import { Quill } from 'react-quill-new';
Quill.register를 사용해 글자 수 제한을 처리하는 커스텀 모듈을 정의하는 방식이다.
이 방법은 Quill 내부에서 직접 글자 수 제한을 관리하므로 성능과 일관성 면에서 유리하다.
타입 스크립트를 쓰고 있기 때문에 interface로 따로 타입도 지정해주었다.
const MAX_TEXT_LENGTH = 12;
interface MaxLengthOptions {
maxLength: number;
}
Quill.register(
'modules/maxlength',
function (quill: InstanceType<typeof Quill>, options: MaxLengthOptions) {
quill.on('text-change', function () {
const currentText = quill.getText().trim();
if (currentText.length > options.maxLength) {
quill.deleteText(
options.maxLength,
currentText.length - options.maxLength
);
}
});
}
);
Quill.register로 Quill 에디터에 새로운 모듈을 등록한다. 모듈의 이름은 maxlength로 첫 번째 매개변수이며 두 번째 매개변수는 모듈 기능의 구현이다.
text-change는 에디터의 내용이 변경될 때마다 호출한다는 뜻이다. getText를 통해 순수 텍스트만 가져온 뒤 trim으로 공백 제거한다. 이렇게 가공된 텍스트가 options.maxLength보다 크면 넘친 만큼 삭제한다. 원리 자체는 함수와 다를 것도 없는데, quill의 모듈을 커스텀하여 텍스트가 변경될 때마다 감시하게 한다는 점이 다른 것 같다.
이후 아래와 같이 modules에 maxlength란을 추가하고 QuillWrapper에 modules를 설정한다.
내 경우 툴바 기능을 커스텀하느라 이미 modules를 따로 만들어 사용 중이었기 때문에 maxlength만 추가하면 되었다.
const modules = {
toolbar: [['bold', 'italic'], [{ list: 'bullet' }]],
maxlength: { maxLength: 12 }, // 최대 글자 수 12자로 설정
};
<QuillWrapper
modules={modules}
value={values}
/>
에디터 외부를 클릭하지 않아도, 특정 length를 넘어선 순간 아예 입력되지 않게 적용된 것을 확인할 수 있다. 현재까지 몇 자를 썼고 얼마나 더 쓸 수 있는지 UI로 유저에게 표시할 수 있다면 더 좋을 것도 같다.
공식 문서에도 modules 제작에 관련해 나와 있기 때문에 필요하면 참조한다.
+) 25.02.05 추가: Next.js를 쓰는 경우 모듈 충돌 에러가 발생할 수 있다. 한번 확인해볼 것.
[MD]Next의 SSR과 Quill의 module 충돌 문제 (500 Server Error)
언젠가부터 콘솔에 도통 알 수 없는 에러 하나가 괴롭히고 있었으니...... 500번대 에러가 갑자기 뜰 게 뭐란 말인가? 심지어 개발 환경에서 구현할 때에는 문제 없어서 흐린 눈 하고 끝까지 미
hj97codeart.tistory.com
'Project' 카테고리의 다른 글
React 리펙토링 중에 만난 defaultProps 경고 에러 (1) | 2025.02.05 |
---|---|
[MD]Next의 SSR과 Quill의 module 충돌 문제 (500 Server Error) (0) | 2025.02.03 |
[MD]Quill의 placeholder에서 한글 IME 인식 문제: 기능 구현 (0) | 2025.01.07 |
[MD]React-quill의 칼라 팔레트 개수 변경 (0) | 2024.12.30 |
[MD]처음 페이지에 진입하면 5초 뒤 사라지는 버블 컴포넌트(feat. localStorage) (0) | 2024.10.30 |