[코뮤니티 모각코] 웹 리액트 과정 - 2주차
2021-12-27 MON~2021-12-31 FRI의 기록 💻
📌 6일차 데이터 준비
✅ 오늘의 문제 | 데이터 구조 파악하기
⭐ 정답 예시 보충 <id, channelId, channelUrl의 사용 방법>
https://www.youtube.com/watch?v=id
https://www.youtube.com/channel/channelId
https://www.youtube.com/c/channelUrl
- for문을 활용하여 youtubeData['data']의 모든 배열 요소에 대한 각각의 열두가지 정보를 conole.log를 활용하여 출력
🔽 src/App.js
import './App.css';
import youtubeData from './data/youtubeData.json';
function App() {
for (var i=0; i<youtubeData['data'].length; i++) {
console.log("id :\n", youtubeData['data'][i]['id'], "-> 영상의 링크 주소");
console.log("channelId :\n", youtubeData['data'][i]['channelId'], "-> 채널의 링크 주소");
console.log("date :\n", youtubeData['data'][i]['date'], "-> 영상의 업로드 일시");
console.log("title :\n", youtubeData['data'][i]['title'], "-> 영상의 제목");
console.log("thumbnail :\n", youtubeData['data'][i]['thumbnail'], "-> 영상의 썸네일");
console.log("description :\n", youtubeData['data'][i]['description'], "-> 영상의 설명");
console.log("channelTitle :\n", youtubeData['data'][i]['channelTitle'], "-> 채널의 이름");
console.log("category :\n", youtubeData['data'][i]['category'], "-> 영상의 종류");
console.log("viewCount :\n", youtubeData['data'][i]['viewCount'], "-> 영상의 조회 수");
console.log("likeCount :\n", youtubeData['data'][i]['likeCount'], "-> 영상의 좋아요 수");
console.log("channelUrl :\n", youtubeData['data'][i]['channelUrl'], "-> 채널의 링크 주소");
console.log("channelThumbnail :\n", youtubeData['data'][i]['channelThumbnail'], "-> 채널의 썸네일");
}
return <div>리액트로 데이터 불러오기</div>;
}
export default App;
🔽 Console 출력결과 (일부)
📌 7일차 레이아웃 구성
✅ 오늘의 문제 | 조건부 렌더링 ① - 버튼 클릭 이벤트
⭐ 핵심 <조건부 렌더링>
return ( <div> {true && <div>True일 때 출력되는 메세지</div>} {false && <div>False일 때 출력되는 메세지</div>} </div> );
- src/Layout.js 와 src/Button.js 는 5일차 코드와 동일한 코드 활용
- src/App.js 에 isTrue 변수와 setIsTrue 함수를 useState를 활용하여 선언
- isTrue 변수 값을 true일 경우 false로, false일 경우 true로 바꿔주는 onClick 함수 생성하고 Button 컴포넌트에 연동
- Message 컴포넌트에 props로 isTrue 값을 넘겨줌
- src/Message.js 에서는 props로 넘겨받은 isTrue 값을 검토하여 true일 경우와 false일 경우에 따라 조건부 렌더링
🔽 src/App.js
import React, { useState } from 'react';
import Layout from './Layout';
import Button from './Button';
import Message from './Assignment07/Message';
function App() {
const [isTrue, setIsTrue] = useState(true);
function onClick() {
setIsTrue(!isTrue);
}
return (
<Layout>
<Button onClick={onClick} text="True?" />
<Message isTrue={isTrue}/>
</Layout>
);
}
export default App;
🔽 src/Assignment07/Message.js
function Message(props) {
return (
<div>
{props.isTrue === true && <div>True!</div>}
{props.isTrue === false && <div>False...</div>}
</div>
);
}
export default Message;
📌 8일차 아이콘과 헤더
✅ 오늘의 문제 | 조건부 렌더링 ② - 삼항연산자
⭐ CSS 관련 추가 공부
👉 Module CSS 활용 시 styles 객체 내의 값 조회 방법
- 기본
<div className={styles.클래스이름}></div>
- 클래스 이름에 - 가 들어가 있는 경우
<div className={styles['클래스-이름']}></div>
- 클래스 여러 개를 적용하고 싶은 경우
<div className={'${styles.첫번째} ${styles.두번째}'></div>
👉 box-sizing
- content-box일 경우 테두리 미포함, border-box일 경우 테두리 포함하여 width 및 height 계산
👉 flex
- 첫 번째 값은 flex-grow(기본값 0)
- 0일 경우 flex-basis보다 커질 수 없음, 1일 경우 있음
- 0 보다 큰 숫자로 지정 시 컨테이너의 크기가 늘어날 경우 지정된 숫자의 비율로 아이템의 크기를 증가시킴 (여백 부분을 채운다는 느낌)
- 두 번째 값은 flex-shrink(기본값 1)
- 0일 경우 flex-basis보다 작아질 수 없음, 1일 경우 있음
- 0 보다 큰 숫자로 지정 시 컨테이너의 크기가 줄어들 경우 지정된 숫자의 비율로 아이템의 크기를 감소 시킴
- 세 번째 값은 flex-basis(기본값 auto)
- 아이템의 기본 크기 설정(flex-direction이 row일 경우 너비, column일 경우 높이 설정)
⭐ 정답 예시 보충
두 가지 이상의 클래스에 공통적으로 적용하고 싶은 CSS에 대해서
공통의 클래스이름을 하나 추가적으로 정의할 수도 있지만,
아래와 같이 콤마(,)로 적용할 수도 있음!.blue, .red { color: white; border: 1px solid black; width: 300px; height: 300px; }
- src/Assignment08/Day8.module.css 추가 및 src/Layout.module.css 수정
- src/App.js에 삼항연산자를 활용하여 조건에 따라 div의 className을 다르게 지정
🔽 src/App.js
import React, { useState } from 'react';
import Layout from './Layout';
import Button from './Button';
import styles from './Assignment08/Day8.module.css';
function App() {
const [isTrue, setIsTrue] = useState(true);
function onClick() {
setIsTrue(!isTrue);
}
return (
<Layout>
{isTrue === true ? <div className={`${styles.box} ${styles.blue}`}>True에용</div> : <div className={`${styles.box} ${styles.red}`}>False에용</div>}
<Button onClick={onClick} text="색바꾸기!" />
</Layout>
);
}
export default App;
🔽 src/Assignment08/Day8.module.css
.box {
color: white;
width: 400px;
height: 400px;
margin-bottom: 10px;
padding: 40px;
box-sizing: border-box;
font-size: 20px;
}
.blue {
background-color: blue;
}
.red {
background-color: red;
}
🔽 src/Layout.module.css
.container {
width: 400px;
margin: 20px auto;
padding: 10px;
border: 1px solid black;
border-radius: 10px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
}
📌 9일차 SPA와 링크
✅ 오늘의 문제 | 새로운 페이지 생성
⭐ 핵심 <Routes, Route, Link>
- Routes Route 컴포넌트를 묶어주는 컴포넌트
- Route 링크를 생성하는 컴포넌트 (주소 값 변경 시 Route 컴포넌트 중 path 속성이 겹치는 컴포넌트를 렌더링)
- Link 페이지 이동을 구현 (to 속성에 이동할 주소 값을 넣어줌)
- 아래 첨부된 스크린샷과 같이 8일차 과제에 활용된 파일들을 모아 Assignment09 폴더 구성 (8일차의 App.js 는 Assignment.js 로 변경)
- 그 외 부연 설명에 대해서 오늘부터는 코드에 주석으로 표시 🙌
🔽 src/App.js
import { Route, Routes } from 'react-router-dom';
import Home from './pages/Home';
import Explore from './pages/Explore';
import Subscription from './pages/Subscription';
import Assignment from './Assignment09/Assignment';
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/explore" element={<Explore />} />
<Route path="/subscription" element={<Subscription />} />
<Route path="/assignment" element={<Assignment />} /> // Assignment 컴포넌트로의 링크를 생성하는 Route 컴포넌트 추가
</Routes>
);
}
export default App;
🔽 src/components/shared/Menu.js
import { Link } from 'react-router-dom';
import styles from './Menu.module.css';
function Menu() {
return (
<div>
<div>
<Link to="/">홈</Link>
</div>
<div>
<Link to="/explore">탐색</Link>
</div>
<div>
<Link to="/subscription">구독</Link>
</div>
<div>
<Link to="/assignment">과제</Link> // Assignment 페이지로 이동하는 Link 컴포넌트 추가
</div>
</div>
);
}
export default Menu;
🔽 src/Assignment09/Assignment.js
import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import Layout from './Layout';
import Button from './Button';
import styles from './Day8.module.css';
function Assignment() {
const [isTrue, setIsTrue] = useState(true);
function onClick() {
setIsTrue(!isTrue);
}
return (
<div>
<Layout>
/* 8일차 과제의 정답 예시를 보고 보다 간결하게 삼항연산자를 수정해본 부분*/
<div className={isTrue ? `${styles.box} ${styles.blue}` : `${styles.box} ${styles.red}`}>{isTrue ? "True에용" : "False에용"}</div>
/***********************************************************************/
<Button onClick={onClick} text="색바꾸기!" />
<div>
<Link to="/">홈으로 돌아가기</Link> // Home 페이지로 이동할 수 있는 Link 컴포넌트 추가
</div>
</Layout>
</div>
);
}
export default Assignment;
📌 10일차 메뉴 구현
✅ 오늘의 과제 | 메뉴 없애기 ①
- props로 변수 뿐만 아니라 함수도 넘길 수 있음을 생각해내야 하는 것이 포인트!
- 그 외 부연 설명은 코드에 주석으로 표시 🙌
🔽 src/components/shared/Layout.js
import { useState } from 'react';
import styles from './Layout.module.css';
import Header from './Header';
import Menu from './Menu';
function Layout({ children, activeMenu }) {
/* useState를 활용하여 Menu의 visibility를 관리하는 변수 및 함수 선언 */
const [isMenuOn, setIsMenuOn] = useState(true);
function menuOnOff() {
setIsMenuOn(!isMenuOn);
}
/*********************************************************************/
return (
<div className={styles.container}>
<Header menuOnOff={menuOnOff}/> // Header 컴포넌트에 menuOnOff 함수를 props로 넘겨줌
<div className={styles.layout}>
{isMenuOn ? <Menu activeMenu={activeMenu}/> : null} // isMenuOn 변수의 값에 따라 Menu 컴포넌트의 표시 여부 다르게 조건부 렌더링
<div className={styles.contents}>{children}</div>
</div>
</div>
);
}
export default Layout;
🔽 src/components/shared/Header.js
import styles from './Header.module.css';
import youtube_logo from '../../data/youtube_logo.png';
import { FiMenu } from 'react-icons/fi';
import { IoSearchOutline } from 'react-icons/io5';
import { BsGrid3X3Gap } from 'react-icons/bs';
import { HiOutlineDotsVertical } from 'react-icons/hi';
function Header( {menuOnOff} ) { // props로 menuOnOff 함수 넘겨받음
return (
<div className={styles.header}>
<div className={styles.tab}>
<FiMenu className={styles.icon} onClick={menuOnOff}/> // FiMenu 아이콘 클릭 시 menuOnOff 함수 실행되도록 연동
<img src={youtube_logo} alt="로고" className={styles.logo} />
</div>
<div className={styles['center-tab']}>
<input className={styles.input} />
<IoSearchOutline className={styles['search-icon']} />
</div>
<div className={styles.tab}>
<BsGrid3X3Gap className={styles.icon} />
<HiOutlineDotsVertical className={styles.icon} />
</div>
</div>
);
}
export default Header;
Author And Source
이 문제에 관하여([코뮤니티 모각코] 웹 리액트 과정 - 2주차), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@dianestar/코뮤니티모각코-웹리액트과정-2주차저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)