해결된 질문
작성
·
64
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
가 사전에 정의된 컨텍스트로 바인딩됩니다.이런 방식으로 코드의 각종 부분을 면밀히 검토하여 이상이 없도록 한다면 문제 해결에 도움이 될 것입니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
해결하셔서 다행입니다!!