[JS - Project] 검색어 자동완성 기능 구현하기 | Issue & Solution
ByteDgree 1차 과제로 검색어 자동완성 기능을 구현하는 페이지를 만들고 있다.
배열 처리 / string 자료형 가공 / Mock API 활용한 비동기 처리를 활용하여 서비스 구현하기
🔥 Issues
1. favicon 오류가 생겼다
Failed to load resource: the server responded with a status of 500 (Internal Server Error)
❌ 캐시 삭제를 했는데도 react 파비콘이 그대로 남아있었다
❗ 구글링 한 결과, 아래 코드를 HTML에 추가하면 된대서 넣어봄 → error 해결
<link rel="icon" href="data:;base64,=">
- Chrome이나 FireFox에서는 favicon.ico에 링크가 걸려있지 않으면 서버를 다시 호출하고 404 에러가 발생한다.
이를 막기 위해서 favicon이 없음을 알려줘야 한다. <head></head> 태그사이에 위 코드를 넣어준다.
2. fetch API 이용해 JSON 데이터 받아오기, 뭐가 문젤까 계속 안된다..
❌ 하도 안되니까 지금 문제가 저게 맞는지도 의심됨.. 유튜브로 강의 보기
❗ 미쳤다 하루 종일 잡고 있다가 해결했다.. 정말 정말 별거 아니고 async, await로 try, catch 써서 출력하면 되는 거였는데 너무 어렵게 생각했다.. 나 진짜 갈길이 멀다.. 그래도 행복하다..
//data fetch
async function dataLoad() {
let searchWord = searchBox.value;
try {
await fetch(`http://localhost:3000/autocomplete?keyword=${searchWord}`)
.then((response) => response.json())
.then((data) => makeList(data));
} catch (error) {
console.log(error);
}
}
3. innerHTML, innerTEXT, textContent
- 문득 저 property들의 차이점이 궁금해져서 찾아봤다.
innerHTML vs innerTEXT
//innerText
o.innerText="<b>abc</b>";
// <b>abc</b>
//innerHTML
o.innerHTML="<b>abc</b>";
// abc
- innerHTML는 태그를 인식하여 내부의 text만 출력하고, innerTEXT는 태그와 text 전체를 문자로 인식한다
innerTEXT vs textContent
//예시
<p> Hi, My name is Heeyeon </p>
//innerText
const desc = document.querySelector('p').innerText;
console.log(desc);
Hi My name is Heeyeon // 불필요한 공백 제거
//textContent
const desc = document.querySelector('p').textContent;
console.log(desc);
Hi, My name is Heeyeon //공백까지 출력
- innerText는 불필요한 공백을 제거 후 출력하고,
- IE의 경우 위와 같이 나타나지만, 현재의 크롬 버전에서는 둘 다 동일하게 결과가 나타난다.
- textContent가 더 먼저 사용되어 브라우저 호환성도 좀 더 높다. 또한 큰 차이는 아니지만 더 가볍다고 알려져 있다.
4. 출력된 list 내부의 keyword를 클릭하면 input의 입력값이 해당 keyword로 바뀌기
//keyword click시 input value 변경
function valueChange(e) {
const userChoice = e.target.innerHTML;
searchBox.value = userChoice;
dataLoad(searchBox.value);
}
- 뭔가 맘에 안 드는 코드.. 근데 돌아가긴 하네..
// 🔥 제출! Review 내용은 추가 기록 예정
🔥 Review
1. async, await구문과 then은 같이 사용하지 않는다.
await fetch(`http://localhost:3000/autocomplete?keyword=${searchWord}`)
.then((response) => response.json())
.then((data) => paintList(data));
↓
const response = await fetch(`http://localhost:3000/autocomplete?keyword=${searchWord}`);
const data = await response.json();
paintList(data);
2. 각각의 리스트 아이템마다 클릭 이벤트 리스너를 붙이기 보다, '이벤트 위임' 개념을 사용하여 조금 더 효율적으로 이벤트 리스너 등록하기
2-1. 리스트 아이템 선택시, 새로운 데이터 로드하지말고 목록을 초기화해보기
//list 출력
function paintList(words) {
completeBox.innerHTML = "";
for (let i = 0; i < words.length; i++) {
const completeWord = document.createElement("li");
completeBox.appendChild(completeWord);
completeWord.innerHTML = words[i];
completeWord.addEventListener("click", valueChange);
}
}
//keyword click시 input value 변경
function valueChange(e) {
const userChoice = e.target.innerHTML;
searchBox.value = userChoice;
loadData(searchBox.value);
}
//list 출력
function paintList(words) {
completeBox.innerHTML = "";
for (let i = 0; i < words.length; i++) {
const completeWord = document.createElement("li");
completeBox.appendChild(completeWord);
completeWord.innerHTML = words[i];
}
}
// //keyword click시 input value 변경
function valueChange(e) {
const userChoice = e.target.innerHTML;
searchBox.value = userChoice;
completeBox.innerHTML = "";
}
completeBox.addEventListener("click", valueChange);
- for문으로 만들어진 list마다 이벤트를 걸어 뒀는데, 이벤트 위임 개념을 사용하여 for문의 event를 제거하고 list를 감싸는 ul에 event를 걸어 e.target으로 value를 가져왔다.
- 검색어 완성 리스트에서 user가 클릭한 단어를 input 창에 뜨게 하는 기능이다. 생각해보니 클릭하는 동시에 리스트를 비워야하는데 그에 맞는 검색어를 다시 load하여 데이터를 또 받아왔다. → 'loadData' 함수를 제거하고 'completeBox'를 비웠다.