728x90
const termSubmit = document.getElementById("btn_add_term");
const termList = document.getElementById("list_terms");
const termBox = document.getElementById("text_term");
const termLi = document.querySelectorAll("ul li");
termSubmit.addEventListener("click", () => {
addRelatedTerm(termBox.value);
}, false);
termBox.addEventListener("keyup", (e) => {
const keyCode = e.keyCode;
if (e.keyCode == 188 || e.keyCode == 32 || e.keyCode == 13) {
addRelatedTerm(termBox.value);
}
});
function addRelatedTerm(name) {
const special = /[^ㄱ-힣a-zA-Z0-9+#]/gi;
const newTerm = name.replace(/[^ㄱ-힣a-zA-Z0-9+#]/gi, "");
if (!newTerm) {
return;
}
console.log(newTerm);
const trimmedTerm = newTerm.trim();
const liElem = document.createElement("li");
liElem.innerText = trimmedTerm;
const removeBtn = document.createElement("button");
removeBtn.innerText = 'X';
removeBtn.addEventListener('click', () => {
removeBtn.parentNode.removeChild(removeBtn);
liElem.parentNode.removeChild(liElem);
})
const items = document.querySelectorAll("#list_terms > li");
for (let i = 0; i < items.length; i++) {
if (items[i].innerHTML.split('<')[0] === newTerm) {
alert('중복 단어');
termBox.value = '';
return;
}
};
termList.appendChild(liElem).appendChild(removeBtn);
termBox.value = '';
return;
}
addRelatedTerm("**(*(*(*");
요새 리액트를 배우고 있는데, 이 것을 써먹을 곳이 좀 필요했다. 그래서 위의 JS 코드를 리액트로 리팩토링 해봐야겠다는 생각이 들었다. 그리하여 새로운 React app을 만들고, 컴포넌트를 짜봤다.
import React, { useState } from "react";
import "./App.css";
const TermRelated = () => {
const [relatedTerms, setRelatedTerms] = useState([{ id: "", text: "" }]);
const [inputTerm, setInputTerm] = useState("");
const [nextId, setNextId] = useState("");
const onChange = (e) => setInputTerm(e.target.value);
const onClick = () => {
const nextRelatedTerms = relatedTerms.concat({
id: nextId,
text: inputTerm,
});
setNextId(nextId + 1);
setRelatedTerms(nextRelatedTerms);
setInputTerm("");
};
const onKeyPress = (e) => {
if (
(e.charCode === 188 || e.charCode === 13 || e.charCode === 32) &&
e.target.value
) {
onClick();
}
};
const onRemove = (id) => {
const nextRelatedTerms = relatedTerms.filter(
(relatedTerms) => relatedTerms.id !== id
);
setRelatedTerms(nextRelatedTerms);
};
const relatedTermsList = relatedTerms.map((relatedTerm) => (
<>
<li key={relatedTerm.id}>
{relatedTerm.text}
<button onClick={() => onRemove(relatedTerm.id)}>X</button>
</li>
</>
));
return (
<>
<input
value={inputTerm}
onChange={onChange}
onKeyPress={onKeyPress}
maxLength="15"
/>
<button onClick={onClick}>추가</button>
<ul id="list_terms">{relatedTermsList}</ul>
</>
);
};
export default TermRelated;
ul 내 각 li마다 id와 text 각각을 부여하고, 이 id는 X키를 눌러서 li를 지울 때 사용한다.
onClick을 했을 때,
concat
을 이용하여, 새로운inputText
와nextId
를 가진 값을 배열에 합친다.nextId
에 1을 더한 값을 새로운nextId
로 설정한다.setRelatedTerms
를 이용해 nextRelatedTerms의 값을 반영한다.- inputText의 값을 비워준다.
이 onClick 함수가 핵심이다. 엔터 및 스페이스바를 눌렀을 때도 추가가 되게끔 구현하고자 onKeyPress 이벤트에 각각의 charCode를 추가했다. 이 때, 아무 값도 없을 때에도 <li></li>
와 같이 추가되는것을 방지하고자 () && e.target.value
를 추가해줬다.
그리고, onRemove
함수를 통해 relatedTerms.id와 지우려는 id가 같지 않은 경우를 제외하는 코드를 추가했고, 이를 li 내에 button을 만들어서 그쪽에다가 명령을 줬다.
그러나, 아직 완성되지 않았기 때문에 계속 더 해봐야 한다.
알게 된 점
- 리액트에서는 각 키당 번호를 이용해서 코딩하려면 e.keyCode가 아니라 e.charCode를 이용해야 한다.
궁금한 점
- 바닐라 JS로 코딩했을 때는 엔터 키가 두 번 눌리는 문제가 있었다. 근데, 리액트로 코딩을 하니까 영문일 때는 스페이스바를 누르면 공백이 추가되지 않은 상태로 바로 명령이 실행되지만 한글일 때는 스페이스바가 추가되고 난 후 한 번 더 스페이스바를 눌러야 추가가 된다. 이게 왜 그런지 잘 모르겠다.
앞으로 더 해야 할 점
- replace문을 사용하여 input값에 특수문자 및 공백이 들어가지 못하게 하기
- 중복을 어떻게 체크하고 방지할 것인가?
'토이프로젝트' 카테고리의 다른 글
[React] 관련용어 태그 작업 완성 (0) | 2021.07.30 |
---|---|
[개발용어사전] 바닐라 JS -> React 코드 리팩토링(2) (0) | 2021.03.12 |
2/8 maplestory JS 코드 리팩토링 완성 (0) | 2021.02.08 |
2/2 maplestory JS 코드 리팩토링 (0) | 2021.02.02 |
1/20 maplestory JavaScript 코드 리팩토링 (0) | 2021.01.20 |