인프런 커뮤니티 질문&답변
TabBar.js 오류가 자꾸 발생하는데 무슨이유인지 모르겠습니다;;
해결된 질문
작성
·
195
0
전체 사진 처음 화면은 로딩 되서 잘나오는데 펭귄이나 다른탭을 클릭하면 아래와 같은 오류가 나오는데 TabBar.js onclick 함수가 아니라는데;; 왜이런건지 함수가 맞는데 아래에 제가 작성한 코드 입니다 검토 좀 부탁드립니다.^^;;
TabBar.js
export default function TabBar({ $app, initialState, onClick }) {
// TabBar 클래스를 생성합니다. 초기값과 클릭 이벤트를 받습니다.
this.state = initialState; // 초기값 설정
this.onClick = onClick; // 클릭 이벤트 설정
this.$target = document.createElement("div"); // 새로운 div 요소를 생성합니다.
this.$target.className = "tab-bar"; // div 요소에 클래스 이름을 추가합니다.
$app.appendChild(this.$target); // $app 요소에 div 요소를 추가합니다.
this.template = () => {
let temp = `<div id="all">전체</div><div id="penguin">펭귄</div>
<div id ="koala">코알라</div><div id ="panda">판다</div>`; // 전체 탭을 추가합니다.
return temp; // temp를 반환합니다.
};
this.render = () => {
// 렌더링 함수
this.$target.innerHTML = this.template(); // div 요소의 innerHTML을 template 함수의 반환값으로 설정합니다.
let $currentTab = document.getElementById(this.state); // 현재 탭을 선택합니다.
// $currentTab ? ($currentTab.className = "clicked") : ""; // 현재 탭이 존재하면 clicked 클래스를 추가합니다. 없으면 변화없음.
$currentTab && ($currentTab.className = "clicked"); // && 연산자를 사용하여 현재 탭이 존재하면 clicked 클래스를 추가합니다.
const $tabBar = this.$target.querySelectorAll("div"); // 모든 div 요소를 tabBar 요소에 담아온다.
$tabBar.forEach((elm) => {
elm.addEventListener("click", () => {
// 각 div 요소에 클릭 이벤트 리스너를 추가합니다.
this.onClick(elm.id); // 클릭한 div 요소의 id를 onClick 함수에 전달합니다.
});
});
};
this.setState = (newState) => {
// state를 변경하는 함수
this.state = newState; // state를 새로 받은 newState로 업데이트합니다.
this.render(); // state가 변경되면 렌더링 함수를 다시 호출하여 화면을 업데이트합니다.
};
this.render(); // 렌더링 함수를 호출합니다.
}
App.js
import TabBar from "./components/TabBar.js"; // TabBar.js 파일을 불러옵니다.
import Content from "./components/Content.js"; // Content.js 파일을 불러옵니다.
import { request } from "./components/api.js"; // api.js 파일을 불러옵니다.
export default function App($app) {
// App 생성자 함수를 생성합니다.
// $app은 App 컴포넌트가 렌더링될 DOM 요소입니다.
this.state = {
//state 초기값 설정
currentTab: "all", // 탭 초기값 설정 tabbar 컴포넌트에 전달할 현재 탭 데이터
photos: [], // 사진 초기값 설정 content 컴포넌트에 전달할 사진 데이터
};
const tabbar = new TabBar({
$app, // App 컴포넌트가 렌더링될 DOM 요소를 전달합니다.
initialState: "", // 초기값 설정
oncClick: async (name) => {
// 클릭 이벤트 설정 변경값을 currentTab에 저장
this.setState({
// 클릭한 탭의 데이터를 state에 저장합니다.
...this.State, // 기존 state를 복사합니다. 스프레드 연산자
currentTab: name, // 클릭한 탭의 이름을 currentTab에 저장합니다.
photos: await request(name === "all" ? "" : name), // 클릭한 탭의 새로운 사진을 request 이름으로 함수를 불러와 저장합니다.
// request 함수는 비동기 함수로 async await를 사용하여 데이터를 받아옵니다.
});
},
});
const content = new Content({
$app, // App 컴포넌트가 렌더링될 DOM 요소를 전달합니다.
initialState: [], // 초기값 설정
});
this.setState = (newState) => {
// 업데이트 값을 newState로 받습니다.
this.state = newState; // state를 새로 받은 newState로 업데이트합니다.
tabbar.setState(this.state.currentTab); // tabbar 컴포넌트에 state를 전달합니다.
content.setState(this.state.photos); // content 컴포넌트에 state를 전달합니다.
};
const init = async () => {
//웹페이지가 로드되면 실행되는 함수
try {
const initialPhotos = await request(); // request 함수를 불러와 initialPhotos에 저장합니다.
this.setState({
// state를 initialPhotos로 업데이트합니다.
...this.state, // 기존 state를 복사합니다. 스프레드 연산자
photos: initialPhotos, // initialPhotos를 photos에 저장합니다.
});
} catch (err) {
console.log(err);
}
};
init(); // 웹애플리케이션이 실행될때 init 함수를 실행합니다.
}
index.js
import App from "../src/App.js";
const $app = document.getElementById("app");
new App($app);
api.js
const API_URL = "https://animal-api-two.vercel.app"; // 이미지 url을 변수에 저장
// const $content = document.querySelector("div.content"); //(api 불러오는 코드만 남겨놓기 위해 삭제제)
// let template = []; // (api 불러오는 코드만 남겨놓기 위해 삭제제)
//API
export const request = async (name) => {
const res = await fetch(name ? `${API_URL}/${name}` : API_URL); // fetch 함수를 사용하여 API_URL을 호출합니다. name이 있으면 name을 호출합니다. 없으면 API_URL을 호출합니다.
try {
if (res) {
let data = await res.json();
return data.photos;
}
} catch (err) {
console.log(err);
}
};
index.html
<!DOCTYPE html>
<head>
<title>Animal Album</title>
<meta charset="UTF-8" />
<link rel="stylesheet" href="../project2/src/style.css" />
<script type="module" src="../project2/src/index.js" defer></script>
</head>
<body>
<div id="app">
<!-- TAB BAR -->
<!-- CONTENT -->
</div>
</body>
content.js
export default function Content({ $app, initialState }) {
this.state = initialState;
this.$target = document.createElement("div");
this.$target.className = "Content";
$app.appendChild(this.$target);
this.template = () => {
let temp = [];
if (this.state) {
this.state.forEach((elm) => {
temp += `<img src="${elm.url}"></img>`;
});
}
return temp;
};
this.render = () => {
this.$target.innerHTML = this.template();
};
this.setState = (newState) => {
this.state = newState;
this.render();
};
this.render();
}
콘솔 오류코드
TabBar.js:26 Uncaught TypeError: this.onClick is not a function
at HTMLDivElement.<anonymous> (TabBar.js:26:14)퀴즈
컴포넌트 기반 웹 개발에서 '상태 관리'를 적용하는 주된 이유는 무엇일까요?
서버 부하를 줄이기 위해
변하는 데이터를 효율적으로 관리하고 불필요한 화면 재렌더링을 막기 위해
초기 페이지 로딩 속도를 빠르게 하기 위해
데이터베이스 연동을 쉽게 하기 위해
답변 2
1
1
안녕하세요, 인프런 AI 인턴입니다. musful님, 질문 주셔서 감사합니다.
열거하신 오류는 TabBar.js의 onClick 이벤트 리스너 관련 설정에서 발생하는 것으로 보입니다. TypeError: this.onClick is not a function이라는 오류는 onClick이 정의되었지만 제대로 함수로 전달되지 않았기 때문에 나타납니다.
문제 해결:
- 오타 확인:
App.js에서TabBar컴포넌트를 생성할 때,oncClick대신onClick으로 명명되었는지 확인하세요. 코드에서 오타가 있는 것 같습니다.
const tabbar = new TabBar({
$app,
initialState: "",
onClick: async (name) => { // 여기를 확인해주세요.
this.setState({
...this.state,
currentTab: name,
photos: await request(name === "all" ? "" : name),
});
},
});
- 함수 전달 확인:
onClick속성에 전달되는 것이 반드시 함수이어야 하며, 적절히App.js내에서 정의된 함수가 전달되었는지 확인하십시오. 이 경우async (name) => { ... }로 설정된 것이 맞습니다.
추가 조치:
- 각 클래스와 함수에서
this가 기대한 대로 바인딩되고 있는지 확인하십시오. 특히 이벤트 핸들러를 화살표 함수(name) => { ... }형태로 사용하면this가 사전에 정의된 컨텍스트로 바인딩됩니다.
관련 질문 URL:
- “TabBar에서 발생할 수 있는 미세한 문제들에 대해 설명/해결한 포스트” - 유사한 코드 패턴에서 자주 발생하는 문제를 들여다볼 수 있는 게시글입니다.
이런 방식으로 코드의 각종 부분을 면밀히 검토하여 이상이 없도록 한다면 문제 해결에 도움이 될 것입니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.






해결하셔서 다행입니다!!