프론트엔드 part 1
CH02
01. 검색 결과로 나타난 게시글 데이터 획득하기
https://brunch.co.kr/search?q=IT&type=article
페이지 캡처
node brunch_01.js
const puppeteer = require("puppeteer");
(async () => {
const browser = await puppeteer.launch({
headless: false,
});
const page = await browser.newPage();
await page.setViewport({
width: 1440,
height: 900,
});
await page.goto("https://brunch.co.kr/search?q=IT&type=article");
await page.screenshot({path: "brunch_01.png"})
await browser.close()
})();
PPTR 메뉴얼: https://pptr.dev/
검색
const puppeteer = require("puppeteer");
(async () => {
const browser = await puppeteer.launch({
headless: false,
});
const page = await browser.newPage();
await page.setViewport({
width: 1440,
height: 900,
});
await page.goto("https://brunch.co.kr/search");
await page.click("input.txt_search")
await page.keyboard.type("Hello World")
검색 후 엔터
const puppeteer = require("puppeteer");
(async () => {
const browser = await puppeteer.launch({
headless: false,
});
const page = await browser.newPage();
await page.setViewport({
width: 1440,
height: 900,
});
await page.goto("https://brunch.co.kr/search");
await page.click("input.txt_search")
await page.keyboard.type("Hello World")
await page.keyboard.press("Enter")
02. 무한 스크롤을 구현하기
자동 스크롤
const puppeteer = require("puppeteer");
(async () => {
const browser = await puppeteer.launch({
headless: false,
});
const page = await browser.newPage();
await page.setViewport({
width: 1440,
height: 900,
});
await page.goto("https://brunch.co.kr/search");
await page.click("input.txt_search")
await page.keyboard.type("Hello World")
await page.keyboard.press("Enter")
// 검색 완료
// 마우스 스크롤을 해서 밑으로 내린다
// 키보드 화살표 아래를 눌러서 화면을 아래로 내린다
// => 무한 스크롤 게시글 데이터가 들어오지 않을까?
// 페이지안에서 일어나는 것을 컨트롤 할 수 있다.
await page.waitForNavigation()
let infiniteScrollInterval = setInterval(async() => {
await page.evaluate(() => {
// 0 에서부터 window.Highght 까지 스크롤한다.
// 서버에서는 window 에서 access 가 되지 않는다.
window.scrollBy(0, window.innerHeight)
});
}, 1000)
// setTimeout(() => {
// clearInterval(infiniteScrollInterval)
// }, 1000 & 10);
})();
03. API 를 통한 무한 스크롤 구현하기
04. 획득한 데이터를 JSON 파일로 저장하기
CH03
06. create-react-app 사용하기
- src
- index.js: 엔트리 포인트
- App.test.js: 테스트 명령 내리거나 직접 실행했을 때 테스트 진행
- public: 정적파일
- favicon.ico: 파비콘 -> 파비콘 제네레이터라는 사이트에서 만들 수 있음
- manifest.json: 웹사이트 기본 정보
07. create-react-app 빌드하기
요청횟수와 리소스가 나와있다.
지난시간 바벨과 웹팩을 배웠다. 코드를 옛날 자바스크립트 문법으로 바꿔주고, 웹팩과 같은 모듈 번들링으로 압축해준다.
build 방법
npm run build
웹서버를 가동해서 index.js 를 켜야 한다.
npm install -g serve
npx serve -s build # serve 설치하지 않고, -s 옵션으로 루트디렉토리로 설정함
npx serve -s build
08. 빌드 환경 설정 변경하기
바벨과 웹팩을 어디서 확인하냐.
eject 명령으로 확인할 수 있다.
eject 환경설정을 방출한다.
09. 컴포넌트 만들고 가져오기
컴포넌트명 파스칼케이스로 작성한다.
- src
- components
- MainHeader.js
- components
MainHeader.js
function MainHeader() {
return <h1>Hello world!</h1>;
}
export default MainHeader;
import logo from "./logo.svg";
import "./App.css";
import MainHeader from "./components/MainHeader";
function App() {
return (
<div className="App">
<MainHeader></MainHeader>
</div>
);
}
export default App;
10. 컴포넌트의 상태 (states)
import React from "react";
function MainHeader() {
// 상태를 처리하는 함수
// [상태 데이터, 상태를 위한 setter 함수]
const [click, setClickState] = React.useState(false)
return <h1 onClick={() => {}}>Hello world!</h1>; // arrow function ES6 문법
}
/** arrow function
*
const name = () => {
}
function name() {
this
}
*/
export default MainHeader;
import React from "react";
function MainHeader() {
// 상태를 처리하는 함수
// [상태 데이터, 상태를 위한 setter 함수]
const [text, setClick] = React.useState("Hello world!")
return <h1 onClick={() => {setClick("Bye world")}}>{text}</h1>; // arrow function ES6 문법
}
export default MainHeader;
중괄호를 넣고싶은데 인라인으로 넣으면 컴파일 에러 발생. 아래와 같이 넣어야 함
return <h1 onClick={() => {setClick("Bye world")}}>{"{"}</h1>; // arrow function ES6 문법
lint 끄기
/* eslint-disable */
import React from "react";
function MainHeader() {
// 상태를 처리하는 함수
// [상태 데이터, 상태를 위한 setter 함수]
const [text, setClick] = React.useState("Hello world!")
return <h1 onClick={() => {setClick("Bye world")}}>{text}</h1>; // arrow function ES6 문법
}
export default MainHeader;
11. 컴포넌트의 속성 (props)
property 전달방법
App.js
import logo from "./logo.svg";
import "./App.css";
import MainHeader from "./components/MainHeader";
function App() {
return (
<div className="App">
<MainHeader text="Connor world!"></MainHeader>
</div>
);
}
export default App;
MainHeader.js
import React from "react";
function MainHeader({text}) {
// 상태를 처리하는 함수
// [상태 데이터, 상태를 위한 setter 함수]
return <h1>{text}</h1>; // arrow function ES6 문법
}
export default MainHeader;
props 로 선언
import React from "react";
function MainHeader(props) {
// 상태를 처리하는 함수
// [상태 데이터, 상태를 위한 setter 함수]
return <h1>{props.text}</h1>; // arrow function ES6 문법
}
export default MainHeader;
언제 state, 언제 props 를 쓰나?
- props: 부모에서 관리
- state: 컴포넌트 각각에서 바뀔 때
import logo from "./logo.svg";
import "./App.css";
import CustomList from "./components/CustomList";
function App() {
const array1 = ["apple", "banana", "orange"];
return (
<div className="App">
<ul>
{array1.map((v) => {
return <CustomList text={v}></CustomList>;
})}
</ul>
</div>
);
}
export default App;
function CustomList({text}) {
return (
<li>{text}</li>
)
}
export default CustomList
import logo from "./logo.svg";
import "./App.css";
import CustomList from "./components/CustomList";
function App() {
const array1 = ["apple", "banana", "orange"];
return (
<div className="App">
<ul>
{array1.map((value, index) => {
return <CustomList text={`${index} ${value}`}></CustomList>;
})}
</ul>
</div>
);
}
export default App;
12. 컴포넌트 스타일링1
App.js
import "./App.css";
위와 같이 하거나, css 폴더 따로 만들어서 관리한다.
npm install node-sass
scss 문법은 태그들에 대해 적용가능
탭 사이즈 수정 (Cmd Shift P 누르고 setting 검색)
모든 버튼안의 span 에 적용
button {
background: white;
color: green;
border: 1px solid blue;
span {
text-align: right;
}
}
button {
background: white;
color: green;
border: 1px solid blue;
& > span {
text-align: right;
}
}
// 같은 문법
button > span {
text-align: right;
}
Button.js
import React from "react";
import "./../style/Button.scss"
export default function Button() {
return <button><span>Green</span></button>
}
Button.scss
button {
background: white;
color: green;
border: 1px solid blue;
& > span {
color: red;
}
}
button 이라는 태그 안에 blue 라는 클래스에 적용해라.
button {
background: white;
color: green;
border: 1px solid blue;
&.blue {
color: red;
}
}
13. 컴포넌트 스타일링2
npm i styled-components
import React from "react";
import "./../style/Button.scss"
import styled from "styled-components";
const MyButton = styled.button`
`
export default function Button() {
return <MyButton>Green</MyButton>
}
플러그인
- styled-components-snippets
- vscode-styled-components
14. 함수형 컴포넌트와 클래스형 컴포넌트
클래스형 컴포넌트는 옛날 react.
import React from "react";
class MainHeader extends React.Component {
render(h) {
return (
<h1>{this.props.text}</h1>
)
}
}
hooks: constructor 를 useState 로 쓰면 됨
15. 조건부 렌더링
import logo from "./logo.svg";
import "./App.css";
import CustomList from "./components/CustomList";
import Button from "./components/Button";
import { useState } from "react";
import MainHeader from "./components/MainHeader";
function App() {
const [text, setText] = useState("감추기")
const buttonClick = () => {
text === "감추기" ? setText("보이기") : setText("감추기")
}
return (
<div className="App">
<h1>적용될까?</h1>
{text === "보이기" && <MainHeader text="hello"></MainHeader>}
<button onClick={() => {buttonClick()}}>{text}</button>
</div>
);
}
export default App;
변수에 조건부 렌더링을 넣어도 된다.
// JSX
const conditionRendering =
text === "World" ? (
<MainHeader text="World"></MainHeader>
) : (
<MainHeader text="Hello"></MainHeader>
)
16. input 상태 관리와 useRef
import logo from "./logo.svg";
import "./App.css";
import CustomList from "./components/CustomList";
import Button from "./components/Button";
import { useState } from "react";
import MainHeader from "./components/MainHeader";
function App() {
const [text, setText] = useState("Hello");
const onChange = (e) => {
const inputText = e.target.value;
setText(inputText);
};
return (
<div className="App">
<h1>{text}</h1>
<input onChange={onChange}></input>
</div>
);
}
export default App;
onChange 에 e 를 생략할 수 있다.
e.target 이란 해당 엘리먼트이다.
e 는 SyntheticBaseEvent
import logo from "./logo.svg";
import "./App.css";
import CustomList from "./components/CustomList";
import Button from "./components/Button";
import { useState } from "react";
import MainHeader from "./components/MainHeader";
function App() {
const [name, setName] = useState({
first: "Connor",
last: "Kim"
})
const confirm = () => {
setName()
}
return (
<div className="App">
<h1>{name.last} {name.first}</h1>
<input name="성" placeholder="성"></input>
<input name="이름" placeholder="이름"></input>
<button onClick={confirm}>확인</button>
</div>
);
}
export default App;
useRef 란 ?
import logo from "./logo.svg";
import "./App.css";
import CustomList from "./components/CustomList";
import Button from "./components/Button";
import { useRef, useState } from "react";
import MainHeader from "./components/MainHeader";
function App() {
const [name, setName] = useState({
first: "Connor",
last: "Kim"
})
const firstNameRef = useRef()
const confirm = () => {
console.log(firstNameRef);
}
return (
<div className="App">
<h1>{name.last} {name.first}</h1>
<input name="성" placeholder="성"></input>
<input name="이름" placeholder="이름" ref={firstNameRef}></input>
<button onClick={confirm}>확인</button>
</div>
);
}
export default App;
console.log(firstNameRef.current.value);
17. 배열을 사용해 할 일 목록 만들기
확인을 누르면 할일목록에 추가되기
import logo from "./logo.svg";
import "./App.css";
import CustomList from "./components/CustomList";
import Button from "./components/Button";
import { useRef, useState } from "react";
import MainHeader from "./components/MainHeader";
function App() {
const [tasks, setTask] = useState([
{
id: 0,
text: "강의 듣기",
},
]);
const inputRef = useRef();
const confirm = () => {
const text = inputRef.current.value;
setTask([
...tasks,
{
id: tasks[tasks.length - 1].id + 1,
text,
},
]);
};
return (
<div className="App">
<div>
<input placeholder="내 목표" ref={inputRef}></input>
<button onClick={confirm}>확인</button>
</div>
<ul>
{tasks.map((v, index) => (
<li key={v.id}>{v.text}</li>
))}
</ul>
</div>
);
}
export default App;
li 태그에는 무조건 key 값을 넣어주자.
18. useEffect와 마운트, 언마운트
버튼 누르면 title 바꾸기
import logo from "./logo.svg";
import "./App.css";
import CustomList from "./components/CustomList";
import Button from "./components/Button";
import { useEffect, useRef, useState } from "react";
import MainHeader from "./components/MainHeader";
function App() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1 )}>Click me</button>
</div>
);
}
export default App;
고장난 코드
import logo from "./logo.svg";
import "./App.css";
import CustomList from "./components/CustomList";
import Button from "./components/Button";
import { useEffect, useRef, useState } from "react";
import MainHeader from "./components/MainHeader";
function App() {
const [secound, setSecound] = useState(0);
setInterval(() => {
setSecound(secound + 1)
}, 1000);
return (
<div>
<p>{secound}초</p>
</div>
);
}
export default App;
정상 코드
// 마운트 이후 실행
useEffect(() => {
let interval = setInterval(() => {
console.log(secound);
setSecound(secound + 1);
}, 1000);
// 언마운트
return () => {
clearInterval(interval);
};
}, [secound]);
19. 리액트 라우터와 페이지 구분하기
npm i react-router-dom
App.js
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { BrowserRouter } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
누르면 페이지가 바뀜
App.js
import logo from "./logo.svg";
import "./App.css";
import CustomList from "./components/CustomList";
import Button from "./components/Button";
import { useEffect, useRef, useState } from "react";
import MainHeader from "./components/MainHeader";
import Profile from "./Profile";
import Board from "./Board";
import { Route, Routes } from "react-router-dom";
function App() {
return (
<div classNAme="App">
<nav>
<ul>
<li>
<a href="/">홈</a>
</li>
<li>
<a href="profile">프로필</a>
</li>
<li>
<a href="board">게시판</a>
</li>
</ul>
</nav>
<Routes>
<Route path="/profile" Component={Profile}></Route>
<Route path="/board" Component={Board}></Route>
</Routes>
</div>
);
}
export default App;
index.js
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { BrowserRouter } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
App 을 BrowserRouter 로 감싸준다.
20. 글로벌 상태관리와 리덕스
21. 리덕스 프로젝트 준비하기
22. 리덕스 액션, 스토어, 리듀서 만들기
23. Provider 로 스토어 연동하기
24. 리덕스와 컴포넌트 연결하기 (1)
24. 리덕스와 컴포넌트 연결하기 (2)
CH04
01. 사이트 UI 디자인 및 상태 생각해보기
프론트엔드 part 2
'Frontend > 스터디' 카테고리의 다른 글
리액트 독학 (0) | 2022.10.04 |
---|---|
한 번에 끝내는 Node.js 웹 프로그래밍 초격차 패키지 Online (1) | 2022.09.23 |
HTML&CSS boost course (0) | 2022.03.10 |
자바스크립트 boost course (0) | 2022.03.10 |