리액트 프로젝트 템플릿 작성하기
1. npm install -g yarn
2. yarn -version
3. yarn create react-app template2023
4. yarn init --force 엔터 한 후 질문지에 대해 모두 엔터 치면 자동 완성됨
현재 페이지가 몇 번째 페이지인지 알고 있어야 한다 → 변하는 값이니 let으로 설정
현재 페이지가 몇번째 페이지인지 기억하는 변수가 필요하다
const store = {
currentPage: 1
}
이전페이지일 경우, 내가 현재 바라보는 페이지를 기준으로 -1 한다
주의할 점은 -1은 되지 않아야 한다(페이지는 1부터 시작하기에) → 삼항연산자 이용
// store.currentPage가 1보다 크면 -1하고 아니라면 1 유지
store.currentPage > 1 ? store.currentPage - 1 : 1
다음 페이지일 경우, 내가 현재 바라보는 페이지를 기준으로 +1 한다
// 아래 코드는 3페이지까지 있는 경우를 가정
store.currentPage < 3 ? store.currentPage + 1 : 3
currentPage의 초기값은 1(전역변수로 선언함)
왜냐하면 상세 보기 화면으로 갔다가 다시 목록으로 돌아갈 때 이전에 바라보던 페이지로 돌아가려면 이 값이 공유되어야 함 → 그렇기에 전변으로 처리
내가 바라보는 페이지가 1번이면 배열의 0~9 인덱스만 호출
i = (1-1)*10 → 0
i < 1*10 → 10
내가 바라보는 페이지가 2번이면 배열의 10~19 인덱스만 호출
i = (2-1)*10 → 10
i < 2*10 → 20
내가 바라보는 페이지가 3번이면 배열의 20~29 인덱스만 호출
i = (3-1)*10 → 20
i < 3*10 → 30
for(let i = (store.currentPage - 1) * 10; i < store.currentPage * 10; i++) {
}
<step 5>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>페이징 처리 - step5</title>
<script defer src="./app.js"></script>
</head>
<body>
<h2>실습제목: 페이징 처리</h2>
<div id="title"></div>
</body>
</html>
const xhr = new XMLHttpRequest();
const NEWS = "https://api.hnpwa.com/v0/news/1.json";
const CONTENT = "https://api.hnpwa.com/v0/item/@id.json";
const container = document.querySelector("#title");
const divContent = document.createElement("div"); // 제목에 대한 상세내용
// 페이징 처리 <step 1>
const store = {
currentPage: 1, // 현재 내가 바라보는 페이지 번호
};
// 아래 함수의 사용처는 두 군데
// 요청 URL만 바뀜 나머지는 같음 -> 그래서 파라미터를 url로 줌
function getData(url) {
xhr.open("GET", url, false);
xhr.send();
return JSON.parse(xhr.responseText);
}
// 뉴스 목록 가져오기
function newsList() {
const news = getData(NEWS);
// li태그를 담을 배열 선언하기
const getList = [];
// li 태그를 담기 전에 ul태그 먼저 담기
getList.push("<ul>"); // push()는 배열의 끝에 요소를 추가하고 배열의 새로운 길이를 반환
for (let i = (store.currentPage - 1) * 10; i < store.currentPage * 10; i++) {
getList.push(`
<li>
<a href = '#/show/${news[i].id}'>${news[i].title}(${news[i].comments_count})</a>
</li>
`);
} // end of for
getList.push("</ul>");
// 배열의 맨 뒤에 추가하는 함수가 push이다
getList.push("<div>"); // 스타일 추가 고려한 div태그 추가
getList.push(
`<a href='#/page/${
store.currentPage > 1 ? store.currentPage - 1 : 1
}'>이전페이지</a>`
);
getList.push("  "); // 링크 사이 띄어쓰기
getList.push(
`<a href='#/page/${
store.currentPage < 3 ? store.currentPage + 1 : 3
}'>다음페이지</a>`
);
getList.push("</div>");
// 빈문자열 주면 구분자 없는 하나의 합쳐진 HTML 문자열을 얻음
container.innerHTML = getList.join(""); // join()은 배열의 모든 요소를 연결해 하나의 문자열로 만듦
} // end of newsList
// 뉴스 상세 내용 보기
function newsDetail() {
const id = this.location.hash.substring(7); // 상세보기시 앞의 #/show/를 제거하고 가져옴
const newsContent = getData(CONTENT.replace("@id", id));
const h1 = this.document.createElement("h1");
container.innerHTML = `
<h1>${newsContent.title}</h1>
<div>
<a href = '#/page/${store.currentPage}'>목록으로</a>
</div>
`;
} // end of newDetail
// 라우터에서 화면 전환하기
function router() {
// 글 목록의 링크는 # -> location.href에 #에왔는데 왜 참인가?
// location.href에 #만 들어오면 빈값을 반환
// 그렇기에 이 코드가 작동하는 것
const routePath = location.hash;
console.log(routePath);
// 첫 진입(첫 요청시)일 때는 해시값이 없으니까 newsList를 호출한다
if (routePath === "") {
newsList();
} else if (routePath.indexOf("#/page/") >= 0) {
// 해시값 중에서 숫자값만 추출하기
// #/page/를 제거하고 문자열을 숫자로 바꿔야함
store.currentPage = Number(routePath.substring(7));
newsList();
} else {
newsDetail();
}
} // end of router
window.addEventListener("hashchange", router);
router();
<step 1>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>클론코딩 - step1[mostPopular]</title>
<link rel="stylesheet" href="./youtube.css" />
<script defer src="./youtube.js"></script>
</head>
<body>
<h3>유튜브 클론코딩 실습 1</h3>
<div id="root"></div>
</body>
</html>
const ajax = new XMLHttpRequest();
let content = "";
const key = "";
const MOST_URL = `https://youtube.googleapis.com/youtube/v3/videos?part=snippet&chart=mostPopular&maxResults=25&key=${key}`;
ajax.open("GET", MOST_URL, false);
ajax.send();
const most = JSON.parse(ajax.response);
const items = most.items;
console.log(items);
console.log(items.length); // 25
content += `<ul class = "videos">`;
// 25번 반복 - 25개의 li
for (let i = 0; i < items.length; i++) {
content += `<li class="container">`;
content += `<div class="video">`;
content += `<img class = "thumbnail" src='${items[i].snippet.thumbnails.medium.url}' />`;
content += `<div">`;
content += `<p class = "title">${items[i].snippet.title}</p>`;
content += `<p class = "channelTitle">${items[i].snippet.channelTitle}</p>`;
content += `</div">`;
content += `</div">`;
content += `</li">`;
}
content += `</ul>`;
document.querySelector("#root").innerHTML = content;
* {
box-sizing: border-box;
/* border: 1px solid red; */
}
.videos {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
list-style: none;
padding-left: 0px;
margin: 0;
gap: 14px;
}
.container {
width: 100%;
padding: 0.2em;
}
.video {
width: 100%;
height: 100%;
display: flex;
align-items: center;
border: 1px solid lightgray;
box-shadow: 3px 3px 5px 0px rgb(185, 185, 185);
transition: transform 250ms ease-in;
cursor: pointer;
}
.video:hover {
transform: scale(1.02);
}
.thumbnail {
width: 40%;
height: 100%;
}
.title,
.channelTitle {
margin: 10px;
font-size: 0.8rem;
}
.channelTitle {
font-size: 0.6rem;
}
자바는 구조지향적
main을 어디에 넣든 먼저 실행됨
html은 절차지향적
그렇기에 javascript에 defer 넣어줌(html 태그를 모두 읽고 나서 js 적용하기 위해)
<step 2>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>클론코딩 - step2[mostPopular]</title>
<link rel="stylesheet" href="./youtube.css" />
<script defer src="./youtube.js"></script>
</head>
<body>
<h3>유튜브 클론코딩 실습 2</h3>
<div id="root"></div>
</body>
</html>
<!--
실습제목: 문자열을 배열로 바꾸어 처리하기
let content = "";
const videoList = [];
-->
const ajax = new XMLHttpRequest();
const videoList = [];
const key = "";
const MOST_URL = `https://youtube.googleapis.com/youtube/v3/videos?part=snippet&chart=mostPopular&maxResults=25&key=${key}`;
ajax.open("GET", MOST_URL, false);
ajax.send();
const most = JSON.parse(ajax.response);
const items = most.items;
console.log(items);
console.log(items.length); // 25
// push()는 배열의 끝에 요소를 추가하고 배열의 새로운 길이를 반환함
videoList.push(`<ul class = "videos">`);
// 25번 반복 - 25개의 li
for (let i = 0; i < items.length; i++) {
videoList.push(`<li class="container">`);
videoList.push(`<div class="video">`);
videoList.push(
`<img class = "thumbnail" src='${items[i].snippet.thumbnails.medium.url}' />`
);
videoList.push(`<div">`);
videoList.push(`<p class = "title">${items[i].snippet.title}</p>`);
videoList.push(
`<p class = "channelTitle">${items[i].snippet.channelTitle}</p>`
);
videoList.push(`</div">`);
videoList.push(`</div">`);
videoList.push(`</li">`);
}
videoList.push(`</ul>`);
// join()은 배열의 모든 요소를 연결해 하나의 문자열로 만듦
// ()기본은 , / ("")은 공백 / ("-")은 -
document.querySelector("#root").innerHTML = videoList.join("");
* {
box-sizing: border-box;
/* border: 1px solid red; */
}
.videos {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
list-style: none;
padding-left: 0px;
margin: 0;
gap: 14px;
}
.container {
width: 100%;
padding: 0.2em;
}
.video {
width: 100%;
height: 100%;
display: flex;
align-items: center;
border: 1px solid lightgray;
box-shadow: 3px 3px 5px 0px rgb(185, 185, 185);
transition: transform 250ms ease-in;
cursor: pointer;
}
.video:hover {
transform: scale(1.02);
}
.thumbnail {
width: 40%;
height: 100%;
}
.title,
.channelTitle {
margin: 10px;
font-size: 0.8rem;
}
.channelTitle {
font-size: 0.6rem;
}
<step 3>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>클론코딩 - step3[search-검색기]</title>
<link rel="stylesheet" href="./youtube.css" />
<link
rel="shortcut icon"
href="../../../images/youtube/logo.ico"
type="image/x-icon"
/>
<script defer src="./youtube.js"></script>
</head>
<body>
<h3>유튜브 클론코딩 실습 3</h3>
<header class="header">
<div class="logo">
<img src="../../../images/youtube/logo.png" alt="logo" />
<h1 class="headerTitle">Youtube</h1>
</div>
<!-- name은 자바에서 id는 자바스크립트에서 쓸 예정 -->
<input
class="input"
type="search"
name="keyword"
id="keyword"
placeholder="Search"
/>
<button class="btnSearch">
<img
class="imgSearch"
src="../../../images/youtube/search.png"
alt="search"
/>
</button>
</header>
<div id="root"></div>
</body>
</html>
<!--
검색기 붙여보기
패비콘(favicon) 이미지 붙이기
배열 - 내장함수(prototype)
-->
const keyword = document.querySelector("#keyword");
// input textfield에 입력한 후 엔터쳤을 때를 잡아내는 함수
keyword.addEventListener("keypress", (event) => {
console.log("keypress => " + event.keyCode);
// 사용자가 입력한 검색어를 찾는 함수 호출
handleSearch();
});
// 사용자가 입력한 검색어 읽어오기
const handleSearch = () => {
const user = document.querySelector("#keyword").value;
console.log("사용자가 입력한 검색어 => " + user);
search(user);
};
// 사용자가 입력한 검색어로 조건 검색 구현하기
const search = (query) => {
console.log("사용자가 입력한 btns 받음 => " + query);
const ajax = new XMLHttpRequest();
const videoList = [];
const key = "";
const SEARCH_URL = `https://youtube.googleapis.com/youtube/v3/search?part=snippet&maxResults=30&q=${query}&key=${key}`;
ajax.open("GET", SEARCH_URL, false);
ajax.send();
const most = JSON.parse(ajax.response);
const items = most.items;
videoList.push(`<ul class = "videos">`);
for (let i = 0; i < items.length; i++) {
videoList.push(`<li class="container">`);
videoList.push(`<div class="video">`);
videoList.push(
`<img class = "thumbnail" src='${items[i].snippet.thumbnails.medium.url}' />`
);
videoList.push(`<div">`);
videoList.push(`<p class = "title">${items[i].snippet.title}</p>`);
videoList.push(
`<p class = "channelTitle">${items[i].snippet.channelTitle}</p>`
);
videoList.push(`</div">`);
videoList.push(`</div">`);
videoList.push(`</li">`);
}
videoList.push(`</ul>`);
document.querySelector("#root").innerHTML = videoList.join("");
}; // end of search
* {
box-sizing: border-box;
/* border: 1px solid red; */
}
.header {
display: flex;
height: 4rem;
padding: 0.5rem 1rem;
margin: 0 0.2rem;
background-color: black;
}
.logo {
display: flex;
align-items: center;
margin-right: 1em;
}
.headerTitle {
color: white;
margin: 0.2rem 0.5rem;
}
.input {
flex-basis: 100%;
font-size: 1.1rem;
outline: 0;
margin: 0rem 0.5rem;
}
.btnSearch {
background-color: rgb(223, 50, 50);
outline: 0;
}
.imgSearch {
height: 100%;
padding: 0.5em 0.2em;
}
.videos {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
list-style: none;
padding-left: 0px;
margin: 0;
gap: 14px;
}
.container {
width: 100%;
padding: 0.2em;
}
.video {
width: 100%;
height: 100%;
display: flex;
align-items: center;
border: 1px solid lightgray;
box-shadow: 3px 3px 5px 0px rgb(185, 185, 185);
transition: transform 250ms ease-in;
cursor: pointer;
}
.video:hover {
transform: scale(1.02);
}
.thumbnail {
width: 40%;
height: 100%;
}
.title,
.channelTitle {
margin: 10px;
font-size: 0.8rem;
}
.channelTitle {
font-size: 0.6rem;
}
Babel은 Javascript 컴파일러이다
컴파일러(Compiler) 언어 해석기, 특정 언어를 다른 프로그래밍 언어로 옮기는 프로그램
내가 쓴 내용
const element = <h1>Hello, React</h1>
Babel이 바꿔준 내용
"use strict"; // 엄격모드(제약조건 생김)
const element = /#PURE/React.createElement("h1", null, "Hello, React");
<React, Babel 예제 1>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>바벨소개</title>
<script
crossorigin
src="https://unpkg.com/react@18/umd/react.development.js"
></script>
<script
crossorigin
src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<style>
.title {
color: green;
}
</style>
<!-- type을 babel로 해야 바닐라스크립트 -> 리액트 섞어쓰기 가능 -->
<script type="text/babel">
const rootElement = document.querySelector("#root");
const element = React.createElement(
"h1",
{
className: "title",
},
["Java", "React", "Spring"]
);
ReactDOM.createRoot(rootElement).render(element);
</script>
</body>
</html>
<React, Babel 예제 2>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>바벨소개</title>
<script
crossorigin
src="https://unpkg.com/react@18/umd/react.development.js"
></script>
<script
crossorigin
src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<style>
.title {
color: red;
}
</style>
<!-- type을 babel로 해야 바닐라스크립트 -> 리액트 섞어쓰기 가능 -->
<script type="text/babel">
const rootElement = document.querySelector("#root");
const element = <h1 className="title">JAVA</h1>;
ReactDOM.createRoot(rootElement).render(element);
</script>
</body>
</html>
<React, Babel 예제 3>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>바벨소개</title>
<script
crossorigin
src="https://unpkg.com/react@18/umd/react.development.js"
></script>
<script
crossorigin
src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<style>
.title {
color: purple;
font-size: 58px;
}
</style>
<!-- type을 babel로 해야 바닐라스크립트 -> 리액트 섞어쓰기 가능 -->
<script type="text/babel">
const rootElement = document.querySelector("#root");
const subject = "React";
const 클래스이름 = "title";
const element = <h1 className={클래스이름}>{subject}</h1>;
ReactDOM.createRoot(rootElement).render(element);
</script>
</body>
</html>
<React, Babel 예제 4>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>바벨소개</title>
<script
crossorigin
src="https://unpkg.com/react@18/umd/react.development.js"
></script>
<script
crossorigin
src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<style>
.title {
color: blue;
font-size: 58px;
}
</style>
<!-- type을 babel로 해야 바닐라스크립트 -> 리액트 섞어쓰기 가능 -->
<script type="text/babel">
const rootElement = document.querySelector("#root");
const subject = "React";
const 클래스이름 = "title";
const 사용자정의태그 = <h1 className={클래스이름}>{subject}</h1>;
ReactDOM.createRoot(rootElement).render(사용자정의태그);
</script>
</body>
</html>
<React, Babel 예제 5>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>바벨소개</title>
<script
crossorigin
src="https://unpkg.com/react@18/umd/react.development.js"
></script>
<script
crossorigin
src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<style>
.title {
color: yellow;
background-color: blue;
font-size: 58px;
}
</style>
<!-- type을 babel로 해야 바닐라스크립트 -> 리액트 섞어쓰기 가능 -->
<script type="text/babel">
const rootElement = document.querySelector("#root");
const subject = "React";
const 클래스이름 = "title";
const props = { className: 클래스이름, children: subject };
const 사용자정의태그 = <h1 {...props} />;
ReactDOM.createRoot(rootElement).render(사용자정의태그);
</script>
</body>
</html>
<React, Babel 예제 6>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>바벨소개</title>
<script
crossorigin
src="https://unpkg.com/react@18/umd/react.development.js"
></script>
<script
crossorigin
src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<style>
.title {
color: pink;
background-color: lightgray;
font-size: 58px;
}
</style>
<!-- type을 babel로 해야 바닐라스크립트 -> 리액트 섞어쓰기 가능 -->
<script type="text/babel">
const rootElement = document.querySelector("#root");
const subject = "React";
const 클래스이름 = "title";
const props = { className: 클래스이름, children: subject };
const 사용자정의태그 = (
<h1 className={props.className} children={props.children}></h1>
);
ReactDOM.createRoot(rootElement).render(사용자정의태그);
</script>
</body>
</html>
'국비학원 > 수업기록' 카테고리의 다른 글
국비 지원 개발자 과정_Day53 (1) | 2023.02.13 |
---|---|
국비 지원 개발자 과정_Day52 (1) | 2023.02.10 |
국비 지원 개발자 과정_Day50 (0) | 2023.02.08 |
국비 지원 개발자 과정_Day49 (0) | 2023.02.07 |
국비 지원 개발자 과정_Day48 (0) | 2023.02.04 |
댓글