오늘은 코드 작업량이 조금 많았습니다.
1. textarea의 link부분을 자동으로 하이퍼링크 처리하기
- 원래는 div contenteditable 이었다.
원래 다라쓰는 나중에 작업할 수도 있는 markdown 문법을 위해서,
댓글입력요소를 textarea가 아니라, div contenteditable로 관리하고 있었습니다.
div contenteditable은 입력하는 요소들이 html 로 변환되어 들어가는데요.
그래서 textContent로 text 문자만 추출해서 댓글로 쓰고 있었습니다.
그러다보니 엔터입력이 무시되었고, 이는 사용자에게 조금 불편할 수 있는 요소였습니다.
그래서 innerHTML를 사용하여 사용자가 엔터를 입력시에 들어가는 <br>태그를 그대로 넣어서, 그대로 렌더링하면 엔터가 정상적으로 동작했습니다.
하지만, DB에 html이 저장되는 것이고,
XSS위협이 있을수도있고,
<>태그들이 댓글이 카운팅이 되기 때문에 3000자 글자제한을 정확하게 측정하기 어려웠습니다. (엔터한번에 글자수6개 카운팅됨...)
https://github.com/woowacourse-teams/2021-darass/pull/749
이렇게 엔터입력이 정상적으로 동작하게 되었습니다!
- 문제점
html 요소들이 삽입가능하다보니, 다양한 이미지들도 복붙을 할 수 있었습니다. 그리고 조금 복잡한 svg를 복붙하면 이미지 1개에 3000자가 넘어서 등록할 수 없다는 에러를 띄우기도 했습니다.
그리고, a태그에 링크를 자동으로 삽입하려면 하이퍼링크를 복붙해야만 했습니다.
그리고 div contenteditable 은 크로스 브라우징 이슈가 있었습니다. (사파리, 파이어폭스, 크롬간의 동작에 차이가 있었습니다.)
이건 좀 아니다 싶어서 textarea로 전면 교체하게 되었습니다.
https://github.com/woowacourse-teams/2021-darass/pull/750
- textarea로 입력란들이 모두 교체한 후...
1. textarea의 길이를 가변으로 주기
textarea의 크기가 내용의 크기에 맞추어서 길어지게하는 로직이 필요했습니다.
onChange나 렌더링을 할때
$textarea.current.style.height = "inherit";
$textarea.current.style.height = `${$textarea.current.scrollHeight}px`;
위 코드를 이용하면 textarea의 높이를 가변적으로 늘릴 수 있었습니다.
주의) 처음에 inherit을 해주지 않으면 원하는 대로 동작하지 않을때가 있었습니다. (정확한 상황이 기억이 안나네요 ㅜㅜ)
2. 링크 text에 하이퍼링크를 어떻게 걸어줄지가 문제였습니다.
textarea의 value에는 a태그가 안들어갈것이기 때문입니다.
아무리 찾아봐도 마땅한 방법이 떠오르지 않아서,
textarea를 edit하지 않는 경우에는 span태그로 바꾸어서 그 안에 link문자를 잡아서 a태그로 감싸주는 방식으로 바꾸었습니다.
https://github.com/woowacourse-teams/2021-darass/pull/754
로직은 아래와 같이 바뀌었고
{contentEditable ? (
<Text
ref={textAreaRef}
value={content}
readOnly={!contentEditable}
disabled={!contentEditable}
editable={contentEditable}
isSecretComment={isSecretComment}
isSubComment={isSubComment}
isReadable={isReadable}
onChange={onChangeTextArea}
data-testid="comment-text-box-contenteditable-input"
/>
) : (
<Text
as="span"
isSubComment={isSubComment}
editable={contentEditable}
isSecretComment={isSecretComment}
isReadable={isReadable}
dangerouslySetInnerHTML={{ __html: parseLinkTextToHTML(content) }}
/>
)}
2번째 식을 보면 as로 태그를 span으로 바꿔주는것을 볼 수 있습니다.
그리고 HTML를 삽입하는 것이기 때문에 dangerouslySetInnerHTML를 사용했습니다.
그리고 content에서 link를 감지하여 a태그로 감싸주는 함수는 다음과 같이 생겼습니다.
export const parseLinkTextToHTML = (text: string) => {
const regURL = new RegExp("(http|https|ftp|telnet|news|irc)://([-/.a-zA-Z0-9_~#%$?&=:200-377()]+)", "gi");
const regEmail = new RegExp("([xA1-xFEa-z0-9_-]+@[xA1-xFEa-z0-9-]+.[a-z0-9-]+)", "gi");
return text
.replace(regURL, "<a href='$1://$2' target='_blank'>$1://$2</a>")
.replace(regEmail, "<a href='mailto:$1'>$1</a>");
};
2. simple-react-query 라이브러리 배포
드디어 react-query가 불편한 사람들을 위한 라이브러리
https://github.com/zereight/simple-react-query
를 배포했습니다.
react-query의 기능들을 간단하게 제공할 수 있도록 계속 업데이트하겠습니다.
'개발 > 개발 리포트' 카테고리의 다른 글
2021/10/23 : 구버전 라이브러리를 사용하고 있는 사용자를 위한 설계 (0) | 2021.10.24 |
---|---|
2021/10/22 : 모든 서비스는 결국 고객 중심이다. (0) | 2021.10.23 |
2021/10/20 : 모든 프로젝트에서 react-query 제거 (0) | 2021.10.21 |
2021/10/19 : DB에 저장해야할 정보는? 다크 모드를 감지하는 방법? (0) | 2021.10.20 |
2021/10/18 : 댓글 서비스에 다크모드 구현! (0) | 2021.10.19 |