해결된 질문
작성
·
64
·
수정됨
0
세션 9. 최종 프로젝트
cityDetail 개발-2 에서
https://trip-wiki-api.vercel.app/ 강사님이 알려주셨던 링크에는 상세페이지 이미지와 받는 정보가 없습니다! 어떻게 상세페이지를 출력할 수 있나요? Japan을 검색창에서 검색하고 상세페이지를 눌렀지만 아무런 정보가 출력되지 않고 있습니다!
import Header from "./components/Header.js";
import RegionList from "./components/RegionList.js";
import CityList from "./components/CityList.js";
import CityDetail from "./components/CityDetail.js";
import { request, requestCityDetail } from "./components/api.js";
export default function App($app) {
const getSortBy = () => {
if (window.location.search) {
return window.location.search.split("sort=")[1].split("&")[0];
}
return "total";
};
const getSearchWord = () => {
if (window.location.search && window.location.search.includes("search=")) {
return window.location.search.split("search=")[1];
}
return "";
};
this.state = {
startIdx: 0,
sortBy: getSortBy(),
region: window.location.pathname.replace("/", ""),
searchWord: getSearchWord(),
cities: "",
currentPage: window.location.pathname,
};
const renderHeader = () => {
new Header({
$app,
initialState: {
currentPage: this.state.currentPage,
sortBy: this.state.sortBy,
searchWord: this.state.searchWord,
},
handleSortChange: async (sortBy) => {
const pageUrl = `/${this.state.region}?sort=${sortBy}`;
history.pushState(
null,
null,
this.state.searchWord
? pageUrl + `&search=${this.state.searchWord}`
: pageUrl
);
const cities = await request(
0,
this.state.region,
sortBy,
this.state.searchWord
);
this.setState({
...this.state,
startIdx: 0,
sortBy: sortBy,
cities: cities,
});
},
handleSearch: async (searchWord) => {
history.pushState(
null,
null,
`/${this.state.region}?sort=${this.state.sortBy}&search=${searchWord}`
);
const cities = await request(
0,
this.state.region,
this.state.sortBy,
searchWord
);
this.setState({
...this.state,
startIdx: 0,
cities: cities,
searchWord: searchWord,
});
},
});
};
const renderRegionList = () => {
new RegionList({
$app,
initialState: this.state.region,
handleRegion: async (region) => {
history.pushState(null, null, `/${region}?sort=total`);
const cities = await request(0, region, "total");
this.setState({
...this.state,
startIdx: 0,
sortBy: "total",
region: region,
cities: cities,
searchWord: "",
currentPage: `/${region}`,
});
},
});
};
const renderCityList = () => {
new CityList({
$app,
initialState: this.state.cities,
handleItemClick: async (id) => {
history.pushState(null, null, `/city/${id}`);
this.setState({
...this.state,
currentPage: `/city/${id}`,
});
},
handleLoadMore: async () => {
const newStartIdx = this.state.startIdx + 40;
const newCities = await request(
newStartIdx,
this.state.region,
this.state.sortBy
);
this.setState({
...this.state,
startIdx: newStartIdx,
cities: {
...this.state.cities,
cities: [...this.state.cities.cities, ...newCities.cities],
isEnd: newCities.isEnd,
},
});
},
});
};
const renderCityDetail = async (cityId) => {
try {
const cityDetailData = await requestCityDetail(cityId);
new CityDetail({ $app, initialState: cityDetailData });
} catch (err) {
console.log(err);
}
};
const render = async () => {
const path = this.state.currentPage;
$app.innerHTML = "";
// 상세 페이지로 이동
if (path.startsWith("/city/")) {
const cityId = path.split("/city/")[1];
renderHeader();
renderCityDetail(cityId);
} else {
renderHeader();
renderRegionList();
renderCityList();
}
};
this.setState = (newState) => {
this.state = newState;
render();
};
const init = async () => {
const path = this.state.currentPage;
// 메인 페이지
if (!path.startsWith("/city")) {
const cities = await request(
this.state.startIdx,
this.state.region,
this.state.sortBy,
this.state.searchWord
);
this.setState({
...this.state,
cities: cities,
});
} // 상세페이지
else {
render();
}
};
window.addEventListener("popstate", async () => {
const urlPath = window.location.pathname;
const prevRegion = urlPath.replace("/", "");
const prevPage = urlPath;
const prevSortBy = getSortBy();
const prevSearchWord = getSearchWord();
const prevStartIdx = 0;
const prevCities = await request(
prevStartIdx,
prevRegion,
prevSortBy,
prevSearchWord
);
this.setState({
...this.state,
startIdx: prevStartIdx,
sortBy: prevSortBy,
region: prevRegion,
currentPage: prevPage,
searchWord: prevSearchWord,
cities: prevCities,
});
});
init();
}
//API.js 코드입니다!
export default function CityDetail({ $app, initialState }) {
this.state = initialState;
this.$target = document.createElement("div");
this.$target.className = "city-detail";
$app.appendChild(this.$target);
const getScoreColor = (score) => {
// let scoreNumber = parseInt(score);
if (score >= 4) return "green";
if (score >= 3) return "yellow";
return "red";
};
this.template = () => {
let cityData = this.state.CityDetail;
let temp = ``;
if (cityData) {
temp = `<div class="image-banner">
<img src="${cityData.image}"/>
<div class="city-name">
<div class="city">${cityData.city}</div>
<div class="country">${cityData.region} / ${cityData.country}</div>
</div>
</div>
<div class="progress-container">
<div class="info-item">
<div class="label">⭐ Total Score</div>
<div class="progress-bar" score-color="${getScoreColor(
cityData.total
)}" style="--score:${cityData.total * 20}%"></div>
</div>
<div class="info-item">
<div class="label">💵 Cost</div>
<div class="progress-bar" score-color="${getScoreColor(
cityData.info.cost
)}" style="--score:${cityData.info.cost * 20}%"></div>
</div>
<div class="info-item">
<div class="label">😆 Fun</div>
<div class="progress-bar" score-color="${getScoreColor(
cityData.info.fun
)}" style="--score:${cityData.info.fun * 20}%"></div>
</div>
<div class="info-item">
<div class="label">🚓 Safety</div>
<div class="progress-bar" score-color="${getScoreColor(
cityData.info.safety
)}" style="--score:${cityData.info.safety * 20}%"></div>
</div>
<div class="info-item">
<div class="label">🌐 Internet</div>
<div class="progress-bar" score-color="${getScoreColor(
cityData.info.internet
)}" style="--score:${cityData.info.internet * 20}%"></div>
</div>
<div class="info-item">
<div class="label">💨 Air Condition</div>
<div class="progress-bar" score-color="${getScoreColor(
cityData.info.air
)}" style="--score: ${cityData.info.air * 20}%"></div>
</div>
<div class="info-item">
<div class="label">🍜 Food</div>
<div class="progress-bar" score-color="${getScoreColor(
cityData.info.food
)}" style="--score: ${cityData.info.food * 20}%"></div>
</div>
</div>
`;
}
return temp;
};
this.render = () => {
this.$target.innerHTML = this.template();
};
/*
this.setState = (newState) => {
this.state = newState;
this.render();
};
*/
this.render();
}
//cityDetail.js 상세페이지 코드입니다!
답변 2
0
안녕하세요 안연수님 🙂
https://trip-wiki-api.vercel.app/ 강사님이 알려주셨던 링크에는 상세페이지 이미지와 받는 정보가 없습니다!
라고 해주셨는데요, [9.최종프로젝트-CityDetail 개발-1] 강의에서 상세페이지 정보를 어떻게 받는지 소개하고 있으니, 해당 강의를 다시 수강해보시는 것을 추천드립니다.
강의를 다시 수강해보신 다음, api.js에 알맞은 api 호출 코드를 작성해주시면 잘 동작할 것 같습니다! 그럼에도 오류가 발생한다면, 다시 질문 작성해주세요. 감사합니다!
0
안녕하세요, 인프런 AI 인턴입니다. 안연수님. 질문 주셔서 감사합니다.
현재 작성하신 코드에서 “상세 페이지 출력 오류” 문제를 겪고 계신 것으로 보이네요. 이는 여러 가지 원인으로 인해 발생할 수 있습니다. 아래에 몇 가지 확인할 수 있는 사항과 해결 방법을 제공하겠습니다.
API의 응답 데이터 확인:
requestCityDetail
함수 호출 시 반환되는 데이터가 올바른지, 콘솔에서 확인해보세요. 이를 통해 서버에서 데이터를 제대로 받아오고 있는지 확인할 수 있습니다.console.log(cityDetailData)
를 추가하여 얻어오는 데이터가 무엇인지 반드시 확인하세요.API 요청 URL:
requestCityDetail
함수 내의 API 요청 URL이 정확한지 확인해 주세요. 현재 사용 중인 API가 유효한지를 체크해야 합니다. API가 잘못 설정되면 데이터가 올바르게 로딩되지 않습니다.데이터 구조 및 바인딩:
CityDetail
컴포넌트 내 this.state.CityDetail
이 올바른 데이터 구조를 가지고 있는지, 데이터가 존재하는지 확인해보세요.CityDetail
컴포넌트가 기대하는 것과 같은지 확인하고 코드에서 올바르게 바인딩되었는지 확인해주시기 바랍니다.연결 문제:
renderCityDetail
함수에서 새로고침 후에도 정상적으로 데이터를 렌더링할 수 있도록 이벤트 핸들러와 관련된 코드가 잘 연결되어 있는지 확인하세요.에러 핸들링:
이를 해결하는 과정에서 API 요청 부분과 데이터 가공 로직을 특히 주의 깊게 살펴봐야 합니다. 아래는 전반적인 안내 링크입니다:
문제 해결에 도움이 되기를 바라며, 이러한 점검 후에도 문제가 해결되지 않으면 코드 및 세부 사항을 공유해 주세요. 추가적인 도움을 드릴 수 있도록 하겠습니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드립니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
api.js 코드에 대한 Detail API 부분 코드 에러 문제에 대해서 문의드립니다! 혹시 잘못된 코드가 있나요? 어떠한 이유로 Detail API 코드 부분이 인식되지 않는 지 문의드립니다!