일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- 팀워크최고
- 달리기반
- NotionAI
- TDD
- ReactNative
- 프론트엔드
- 멍친구
- 맥린이
- 챗GPT
- 프로그래머스
- REACT
- Ai
- D반8조
- ChatGPT
- 알고리즘기초주차
- 7기
- rn
- 웹개발종합반
- 스파르타코딩클럽
- 실전프로젝트
- 항해99
- 사전준비
- Programmers
- 리액트
- 필수강의
- TS
- typeScript
- Expo
- 코린이
- 알pdf #파일탐색기미리보기안될때
- Today
- Total
FrontEnd :-)
[항해99] 리액트 기초반 - 2주차 본문
스파르타코딩클럽 #리액트 기초반 2주차
[수업 목표]
- 컴포넌트의 라이프 사이클을 이해한다.
- 컴포넌트의 state를 관리할 수 있다.
- 패키지를 찾아서 설치할 수 있다.
- React hook을 사용할 수 있다.
2-1. 라이프 사이클이란?
1) 가상돔이란?
DOM은 html 단위 하나하나를 객체로 생각하는 모델.
DOM 트리 중 하나가 수정될 때마다 모든 DOM을 뒤지고, 수정할 걸 찾고, 싹 수정을 한다면?
→ 필요없는 연산이 너무 많이 일어난다! → 그래서 등장한 게 가상돔!
가상돔의 동작 방식:
기존 DOM과 어떤 행동 후 새로 그린 DOM(가상 돔에 올라갔다고 표현합니다)을 비교해서 정말 바뀐 부분만 갈아끼움.
2) 라이프 사이클이란?
라이프 사이클(= 컴포넌트 생명주기):
컴포넌트가 렌더링을 준비하는 순간부터, 페이지에서 사라질 때까지
(공식문서) https://ko.reactjs.org/docs/state-and-lifecycle.html
State and Lifecycle – React
A JavaScript library for building user interfaces
ko.reactjs.org
- 수정(업데이트)는 사용자의 행동(클릭, 데이터 입력 등)으로 데이터가 바뀌거나, 부모 컴포넌트가 렌더링할 때 업데이트 됩니다. 아래의 경우죠!
- props가 바뀔 때 : 부모가 자식에게 주는 데이터
- state가 바뀔 때 : 내가 가진 데이터
- 부모 컴포넌트가 업데이트 되었을 때(=리렌더링했을 때)
- 또는, 강제로 업데이트 했을 경우! (forceUpdate()를 통해 강제로 컴포넌트를 업데이트할 수 있습니다.)
2-2.라이프 사이클 함수로 보는 라이프 사이클
라이프 사이클 함수는 클래스형 컴포넌트에서만 사용할 수 있습니다.
리액트 공식 매뉴얼에서 함수형 컴포넌트를 더 권장!
constructor()
👉 생성자 함수라고도 함. 컴포넌트가 생성되면 가장 처음 호출됨.
render()
👉 컴포넌트의 모양을 정의! 여기에서도 state, props에 접근해서 데이터를 보여줄 수 있음.
render() 안에 들어갈 내용은 컴포넌트의 모양에만 관여하는 것이 가장 좋습니다.
즉, state나 props를 건드려 데이터를 수정하려고 하면 안됩니다!
componentDidMount()
👉 컴포넌트가 화면에 나타나는 것을 마운트(Mount)한다고 표현. DidMount()가 첫 렌더링 후에 호출 되는 함수.
didMount() = 마운트 완료. 이 함수는 첫번째 렌더링을 마친 후에만 딱 한 번 실행. 컴포넌트가 리렌더링할 때는 실행되지 않음. 보통은 이 안에서 ajax 요청, 이벤트 등록, 함수 호출 등 작업을 처리. 또, 이미 가상돔이 실제돔으로 올라간 후니까 DOM 관련 처리를 해도 됨!
componentDidUpdate(prevProps, prevState, snapshot)
👉 DidUpdate()는 리렌더링을 완료한 후 실행되는 함수.
이 함수에 중요한 파라미터가 2개 있는데, prevProps와 prevState입니다. 각각 업데이트 되기 전 props, state예요. 이전 데이터와 비교할 일이 있다면 가져다 쓰기. DidUpdate()가 실행될 때도 가상돔이 실제돔으로 올라간 후니까 DOM 관련 처리를 해도 됨!
componentWillUnmount()
👉 컴포넌트가 DOM에서 제거 될 때 실행하는 함수. 만약 우리가 스크롤 위치를 추적 중이거나, 어떤 이벤트 리스너를 등록했다면 여기에서 꼭꼭 해제를 해줘야 함. 컴포넌트 없이 이벤트만 남겨둘 순 없음!
🔥 componentWillUnmount()가 호출되는 걸 보려면, app.js에서 <LifecycleEx/>를 없애야 함.
삼항연산자를 사용해서 컴포넌트를 보여주거나, 없애는 걸 조건부 렌더링이라고 부름.
2-3. Component (1)
컴포넌트(Component)
=> 웹 사이트의 조각
=> 리액트는 레고, 컴포넌트는 블록
==> 컴포넌트를 이해하고 잘 써먹으려면 웹 사이트를 잘 조각낼 줄 알아야 한다!
=> 종류: 클래스형과 함수형
==> 이제 클래스형 컴포넌트는 잘 쓰지 않지만, 아직 사용 중인 회사가 많기에 읽고 수정할 정도는 알아야 함.
- <header/>
- <container/>
- <imagebanner/>
- <contents1/>
- <footer/>
즉, 이 웹 사이트는, 크게 <header/>, <container/>, <footer/> 세 개의 컴포넌트가 있고,
<container/> 컴포넌트는, <imagebanner/>, <contents1/> 컴포넌트로 이루어져 있다!
웹 사이트를 잘 조각낼 줄 아는 사람 === 리액트를 잘 쓰는 사람
State
=> Component가 가지고 있는 데이터
=> 하나의 컴포넌트에서만 사용하는 정보를 주로 넣어놓고 생성, 수정하는 데이터
Props
=> Component가 부모 Component로부터 받아온 데이터
=> Props로 받은 데이터는 수정할 수 없다
2-4. Component (2)
vscode에서 새 폴더, 새 파일 만들기
(yarn create react-app bucket_list)
(cd bucket_list)
리액트 코딩 룰 1:
폴더명(src, public)은 소문자로 시작
자바스크립트(js) 파일, 컴포넌트 이름은 대문자로 시작(CamelCase)
함수형 컴포넌트
2-5. Component (3)
11) 클래스형 Component
import React from 'react';
import logo from './logo.svg';
import './App.css';
// BucketList 컴포넌트를 import 해옵니다.
// import [컴포넌트 명] from [컴포넌트가 있는 파일경로];
import BucketList from './BucketList';
// 클래스형 컴포넌트는 이렇게 생겼습니다!
class App extends React.Component {
constructor(props){
super(props);
// App 컴포넌트의 state를 정의해줍니다.
this.state = {
list: ['영화관 가기', '매일 책읽기', '수영 배우기'],
};
}
// 랜더 함수 안에 리액트 엘리먼트를 넣어줍니다!
render() {
return (
<div className="App">
<h1>내 버킷리스트</h1>
{/* 컴포넌트를 넣어줍니다. */}
<BucketList/>
</div>
);
}
}
export default App;
2-6. Quiz_버킷리스트 페이지를 만들어봅시다!
2-7. 화면을 예쁘게! React에서 CSS 사용하기
(2) CSS 파일을 가져다 쓰려면? import!
import React from 'react';
import logo from './logo.svg';
// BucketList 컴포넌트를 import 해옵니다.
// import [컴포넌트 명] from [컴포넌트가 있는 파일경로];
import BucketList from './BucketList';
// 이 import를 통해 css 파일을 불러다 씁니다!
import './style.css';
2-8. 화면을 예쁘게! - styled-components
15) styled-components 설치하기
yarn add styled-components
16) styled-components란?
=> CSS-in-JS 라이브러리 중 하나
=> 컴포넌트에 스타일을 직접 입히는 방식
// scss 문법 1: 네스팅! 내가 포함하고 있는 요소에 접근할 수 있어요. ex)내 것{ 자식 것: {}}
// scss 문법 2: &는 나 자신!
const MyStyled = styled.div`
width: 50vw;
height: 150px;
background-color: ${(props) => (props.bg_color ? "red" : "purple")};
p {
color: blue;
}
&:hover{
background-color: yellow;
}
`;
2-9. Quiz_버킷리스트에 styled-components 적용하기
2-10. Ref! 리액트에서 돔요소를 가져오려면?
19) Ref
내가 어떤 인풋박스에서 텍스트를 가져오고 싶으면 어떻게 접근해야할까요? DOM에서 다루는 방법은 1주차에 배웠는데, 리액트에선 어떻게 하면 좋을까요? (render()가 끝나고 가져오면 될까요? 아니면 mount가 끝나고? 아니, 그 전에 가상돔에서 가져오나? 아니면 DOM에서? 😖) → 답은, 리액트 요소에서 가져온다!
React 요소를 가지고 오는 방법1 : React.createRef() // App.js에서
// 클래스형 컴포넌트는 이렇게 생겼습니다!
class App extends React.Component {
constructor(props) {
super(props);
// App 컴포넌트의 state를 정의해줍니다.
this.state = {
list: ["영화관 가기", "매일 책읽기", "수영 배우기"],
};
// ref는 이렇게 선언합니다!
this.text = React.createRef();
}
componentDidMount(){
// 콘솔에서 확인해보자!
console.log(this.text);
console.log(this.text.current);
}
// 랜더 함수 안에 리액트 엘리먼트를 넣어줍니다!
render() {
return (
<div className="App">
<Container>
<Title>내 버킷리스트</Title>
<Line />
{/* 컴포넌트를 넣어줍니다. */}
{/* <컴포넌트 명 [props 명]={넘겨줄 것(리스트, 문자열, 숫자, ...)}/> */}
<BucketList list={this.state.list} />
</Container>
<div>
<input type="text" ref={this.text}/>
</div>
</div>
);
}
}
React 요소를 가지고 오는 방법2 : React.useRef() // BuketList.js에서
import React from "react";
import styled from "styled-components";
const BucketList = ({ list }) => {
const my_lists = list;
const my_wrap = React.useRef(null);
console.log(my_wrap); // 콘솔로 확인해봐요!
window.setTimeout(() => { // 1초 뒤에는?!
console.log(my_wrap);
}, 1000);
return (
<div ref={my_wrap}>
{my_lists.map((list, index) => {
return <ItemStyle key={index}>{list}</ItemStyle>;
})}
</div>
);
};
const ItemStyle = styled.div`
padding: 16px;
margin: 8px;
background-color: aliceblue;
`;
export default BucketList;
2-11. State 관리 (1)
20) 단방향 데이터 흐름이란?
데이터는 위에서 아래로, 부모에서 자식으로 넘겨줘야 한다는 소리!
21) 클래스형 컴포넌트에서 state 관리 - setState()
라이프 사이클을 볼 때 잠깐 봤던 setState()!
클래스형 컴포넌트의 state를 업데이트할 때 사용하는 함수
App.js에서
// App component를 class형으로!
import React from 'react';
class App extends React.Component {
constructor(props){
super(props);
this.state = {
count: 3
};
}
componentDidMount(){}
addNemo = () => {
this.setState({count: this.state.count +1});
}
removeNemo = () => {
if(this.state.count > 0){
this.setState({count: this.state.count -1});
} else{
window.alert("네모가 없어요!");
}
}
render(){
const nemo_count = Array.from({length: this.state.count}, (v, i) => i);
console.log(nemo_count);
console.log(this.state);
return (
<div className="App">
{nemo_count.map((n, i) => {
return (
<div
key={1}
style={{
width: "150px",
height: "150px",
backgroundColor: "#ddd",
margin: "10px"
}}>
nemo
</div>
)
})}
<div>
<button onClick={() => {
this.addNemo();
}}>하나 추가</button>
<button onClick={() => {
this.removeNemo();
}}>하나 빼기</button>
</div>
</div>
);
}
}
export default App;
2-12. State 관리 (2)
Nemo.js 파일을 만들고 시작
(1) Nemo 컴포넌트 만들기
import React from "react";
const Nemo = (props) => {
// 반환할 리액트 요소가 없을 때는 null을 넘겨주세요! 처음 껍데기 잡으실때도 null을 넘겨주면 굳!
return null;
}
export default Nemo;
(2) App에서 <Nemo/>불러오기
(3) useState()로 count를 state로 등록하자
// count에는 state 값이, setCount는 count라는 state 값을 수정하는 함수가 될거예요.
// useState(초기값): () 안에 초기값을 넣어줍니다.
const [count, setCount] = React.useState(3);
(4) 뷰를 만들고(=반환할 리액트 요소를 만들고),
(5) 함수를 만들어서,
const addNemo = () => {
// setCount를 통해 count에 저장된 값을 + 1 해줍니다.
setCount(count + 1);
};
const removeNemo = () => {
// setCount를 통해 count에 저장된 값을 - 1 해줍니다.
// 이번엔 if문 대신 삼항 연산자로 해볼거예요!
setCount(count > 0 ? count - 1 : 0);
};
(6) 연결하자!
{/* 함수를 호출합니다. */}
<button onClick={addNemo}>하나 추가</button>
<button onClick={removeNemo}>하나 빼기</button>
</div>
2-13. Quiz_버킷리스트에 아이템을 추가해보자!
import React from "react";
import BucketList from "./BucketList";
import styled from "styled-components";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
list: ["영화관 가기", "매일 책읽기", "수영 배우기"],
};
this.text = React.createRef();
}
componentDidMount() {
}
addBucket = () => {
console.log(this.text.current.value);
const new_item = this.text.current.value;
// ... => 스프레드 문법
// [...this.state.list, 넣고 싶었던 어떤 값]
this.setState({ list: [...this.state.list, new_item] });
}
render() {
return (
<AppWrap className="App">
<Container>
<Title>내 버킷리스트</Title>
<Line />
<BucketList list={this.state.list} />
</Container>
<InputWrap>
<input type="text" ref={this.text} />
<button onClick={this.addBucket}>추가하기</button>
</InputWrap>
</AppWrap>
);
}
}
const AppWrap = styled.div`
background-color: #eee;
height: 100vh;
width: 100vw;
display: flex;
flex-direction: column;
`;
const Container = styled.div`
background-color: #fff;
width: 50vw;
max-width: 350px;
margin: auto;
height: 80vh;
padding: 16px;
border: 1px solid #ddd;
border-radius: 5px;
`;
const Title = styled.h1`
color: slateblue;
text-align: center;
`;
const Line = styled.hr`
margin: 16px 0px;
`;
const InputWrap = styled.div`
background-color: #fff;
width: 50vw;
max-width: 350px;
margin: auto;
padding: 16px;
border: 1px solid #ddd;
border-radius: 5px;
`;
export default App;
console.log(this.text) 확인이 어렵네 => console.log(this.text.current.value); 바로 값 확인 가능.
2-14. 끝
오우 강의를 들어도 '잘 모르겠다'는 느낌뿐.
2-11은 그나마 가장 흥미로웠던 부분ㅋㅋ map함수가 박스 추가에 쓰이는 구나.. 알고리즘 주차때 숫자랑 문자 빼고 더하기만 하다가 박스를 추가하고 빼니까 느낌이 다른, 동시에 자바스크립트 공부 필요성을 다시 한번 강하게 느꼈다.