라이프 사이클 함수는 클래스형 컴포넌트에서만 사용할 수 있습니다.
라이프 사이클을 아는 건 중요한데 왜 우리는 클래스형 컴포넌트보다 함수형 컴포넌트를 많이 쓰냐구요?
리액트 공식 매뉴얼에서 함수형 컴포넌트를 더 권장하기 때문입니다!
(리액트 16.8버전부터 등장한 React Hooks으로 라이프 사이클 함수를 대체할 수 있거든요.)
더 많은 라이프 사이클 함수는 공식 문서에서 확인할 수 있어요 😉
3) constructor()
생성자 함수라고도 부릅니다. 컴포넌트가 생성되면 가장 처음 호출되는 친구죠!
4) render()
컴포넌트의 모양을 정의하는 친구입니다!
여기에서도 state, props에 접근해서 데이터를 보여줄 수 있어요.
리액트 요소를 return에 넣어 반환해줬던 거 기억하시죠?
render() 안에 들어갈 내용은 컴포넌트의 모양에만 관여하는 것이 가장 좋습니다.
즉, state나, props를 건드려 데이터를 수정하려고 하면 안됩니다!
5) componentDidMount()
컴포넌트가 화면에 나타나는 것을 마운트(Mount)한다고 표현합니다. didMount()는 마운트가 완료 되었다는 소리겠죠?
이 함수는 첫번째 렌더링을 마친 후에만 딱 한 번 실행됩니다. 컴포넌트가 리렌더링할 때는 실행되지 않아요.
보통은 이 안에서 ajax 요청, 이벤트 등록, 함수 호출 등 작업을 처리합니다.
또, 이미 가상돔이 실제돔으로 올라간 후니까 DOM 관련 처리를 해도 됩니다!
6) componentDidUpdate(prevProps, prevState, snapshot)
DidMount()가 첫 렌더링 후에 호출 되는 함수라면, DidUpdate()는 리렌더링을 완료한 후 실행되는 함수입니다.
이 함수에 중요한 파라미터가 2개 있는데, prevProps와 prevState입니다. 각각 업데이트 되기 전 props, state예요. 이전 데이터와 비교할 일이 있다면 가져다 쓰도록 합시다.
DidUpdate()가 실행될 때도 가상돔이 실제돔으로 올라간 후니까 DOM 관련 처리를 해도 됩니다!
7) componentWillUnmount()
컴포넌트가 DOM에서 제거 될 때 실행하는 함수입니다.
만약 우리가 스크롤 위치를 추적 중이거나, 어떤 이벤트 리스너를 등록했다면 여기에서 꼭꼭 해제를 해줘야 합니다.
컴포넌트 없이 이벤트만 남겨둘 순 없잖아요!
Component는 클래스형과 함수형이 있습니다.
이제 클래스형 컴포넌트는 잘 쓰지 않지만, 두 가지를 알아야한다.
→ 왜냐하면 이미 기개발된 프로젝트들(아마 여러분이 가야할 회사에서도...!)은 클래스형 컴포넌트를 사용 중일수도 있거든요. 최소한 코드를 알아보고 고칠 수 있을 정도는 알아두는 편이 좋습니다.
위에서 리액트는 레고라면 컴포넌트는 블록입니다!
Component는 웹 사이트의 조각이고, 우리는 이 조각을 모아서 웹사이트에 뿌려준다.
웹 사이트를 잘 조각낼 줄 아는 사람 === 리액트를 잘 쓰는 사람
state는 Component가 가지고 있는 데이터입니다.
헤더에 들어갈 데이터는 뭐가 있을까요?
→ 로고 이미지 경로, 메뉴 이름(온라인, 오프라인, 기업교육, 내 강의실)이 있을 겁니다!
이 데이터는 나
컴포넌트에서는 쓰지 않겠죠!즉,
컴포넌트에서만 쓰는 정보인 셈입니다.state는 한 컴포넌트에서만 사용하는 정보를 주로 넣어놓고 생성, 수정하는 데이터입니다.
생성도 수정도 오직 해당 컴포넌트 내에서만 이뤄집니다. 내꺼니까 생성도 수정도 자유롭죠!
props는 Component가 부모 Component로부터 받아온 데이터입니다.
가 가지고 있는 이미지 경로를 에게 전달해주면, 이 이미지 경로가 컴포넌트의 props가 됩니다.
다시 말해, 부모 컴포넌트로부터 전달 받은 데이터를 props라고 합니다.
그럼 부모 컴포넌트가 가지고 있는 데이터를 컴포넌트가 추가 하거나 수정할 수 있을까요?
Props로 받은 데이터는 수정할 수 없습니다! 남의 것이니까요!
리액트 코딩 룰 1:
폴더는 소문자로 시작하는 카멜케이스를 사용
JS파일, 컴포넌트 이름은 대문자로 시작하는 카멜케이스를 사용
// 리액트 패키지를 불러옵니다.
import React from 'react';
// 함수형 컴포넌트는 이렇게 쓸 수도 있고
// function Bucketlist(props){
// return (
//
// 이렇게 쓸 수도 있어요. =>가 들어간 함수를 화살표 함수라고 불러요.
// 저희는 앞으로 화살표 함수를 사용할거예요.
// 앗 () 안에 props! 부모 컴포넌트에게 받아온 데이터입니다.
// js 함수가 값을 받아오는 것과 똑같이 받아오네요.
const BucketList = (props) => {
// 컴포넌트가 뿌려줄 ui 요소(리엑트 엘리먼트라고 불러요.)를 반환해줍니다.
return (
<div>
버킷 리스트
</div>
);
}
// 우리가 만든 함수형 컴포넌트를 export 해줍니다.
// export 해주면 다른 컴포넌트에서 BucketList 컴포넌트를 불러다 쓸 수 있어요.
export default BucketList;
그리고 App.js로 돌아가서 BucketList 컴포넌트를 불러와 봅시다.
import React from 'react';
import logo from './logo.svg';
import './App.css';
// BucketList 컴포넌트를 import 해옵니다.
// import [컴포넌트 명] from [컴포넌트가 있는 파일경로];
import BucketList from './BucketList';
function App() {
return (
<div className="App">
<h1>내 버킷리스트</h1>
{/* 컴포넌트를 넣어줍니다. */}
<BucketList/>
</div>
);
}
export default App;
class 이름 짓기에서 해방됩니다!
컴포넌트에 스타일을 적기 때문에, 간단하고 직관적입니다!
CSS-in-JS 라이브러리 중 하나입니다!
컴포넌트에 스타일을 직접 입히는 방식이라고 편하게 생각하셔도 됩니다!
먼저 import를 해준다!
import styled from "styled-components";
예)
그런데 만약에, 내가 어떤 인풋박스에서 텍스트를 가져오고 싶으면 어떻게 접근해야할까요?
(render()가 끝나고 가져오면 될까요? 아니면 mount가 끝나고?
아니, 그 전에 가상돔에서 가져오나? 아니면 DOM에서? 😖)
→ 답은, 리액트 요소에서 가져온다!
useRef()는 리액트 훅 중 하나예요. 🙂
리액트 훅은 사용방법이 무지무지 간단합니다!
이름에서부터 감이 오지 않나요?
데이터는 위에서 아래로, 부모에서 자식으로 넘겨줘야 한다는 소리입니다.
(1) 왜 단방향으로 써야하지?
라이프 사이클을 볼 때 잠깐 봤던 setState()!
클래스형 컴포넌트의 state를 업데이트할 때 사용하는 함수입니다.
(1) 새 CRA 만들기
yarn create react-app nemo
(2) App.js를 class형 컴포넌트로 바꾸고 시작!
// App component를 class형으로!
import React from 'react';
class App extends React.Component {
constructor(props){
super(props);
this.state = {}
}
componentDidMount(){
}
render(){
return (
<div className="App">
</div>
);
}
}
export default App;
(3) state에 count라는 변수를 추가하고, count 숫자만큼 네모칸을 화면에 띄우기
import React from "react";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 3, // 숫자넣기!
};
}
componentDidMount() {}
render() {
// 배열을 만듭니다.
// Array.from()은 배열을 만들고 초기화까지 해주는 내장 함수입니다.
// Array.from()의 첫번째 파라미터로 {length: 원하는 길이} 객체를,
// 두번째 파라미터로 원하는 값을 반환하는 콜백함수를 넘겨주면 끝!
// array의 내장함수 대부분은 콜백 함수에서 (현재값, index넘버)를 인자로 씁니다.
const nemo_count = Array.from({ length: this.state.count }, (v, i) => i);
// 콘솔로 만들어진 배열을 확인해봅니다. 숫자가 0부터 순서대로 잘 들어갔나요?
console.log(nemo_count);
return (
<div className="App">
{nemo_count.map((num, idx) => {
return (
<div key={idx}
style={{
width: "150px",
height: "150px",
backgroundColor: "#ddd",
margin: "10px",
}}
>
nemo
</div>
);
})}
</div>
);
}
}
export default App;
(4) 더하기, 빼기 버튼을 만들고,
return (
<div className="App">
{nemo_count.map((num, idx) => {
return (
<div key={idx}
style={{
width: "150px",
height: "150px",
backgroundColor: "#ddd",
margin: "10px",
}}
>
nemo
</div>
);
})}
<div>
<button>하나 추가</button>
<button>하나 빼기</button>
</div>
</div>
);
(5) 함수를 만들어서
addNemo = () => {
// this.setState로 count를 하나 더해줍니다!
this.setState({ count: this.state.count + 1 });
};
removeNemo = () => {
// 네모 갯수가 0보다 작을 순 없겠죠! if문으로 조건을 걸어줍시다.
if (this.state.count > 0) {
// this.setState로 count를 하나 빼줍니다!
this.setState({ count: this.state.count - 1 });
}else{
window.alert('네모가 없어요!');
}
};
(6) 연결하자!
return (
<div className="App">
{nemo_count.map((num, idx) => {
return (
<div
key={idx}
style={{
width: "150px",
height: "150px",
backgroundColor: "#ddd",
margin: "10px",
}}
>
nemo
</div>
);
})}
<div>
{/* 함수를 호출합니다. 이 클래스 안의 addNemo 함수를 불러오기 때문에 this.addNemo로 표기해요. */}
<button onClick={this.addNemo}>하나 추가</button>
<button onClick={this.removeNemo}>하나 빼기</button>
</div>
</div>
);
(7) 완성본 코드
네모칸 만들기 완성본
import React from "react";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 3, // 숫자넣기!
};
}
componentDidMount() {}
addNemo = () => {
// this.setState로 count를 하나 더해줍니다!
this.setState({ count: this.state.count + 1 });
};
removeNemo = () => {
// 네모 갯수가 0보다 작을 순 없겠죠! if문으로 조건을 걸어줍시다.
if (this.state.count > 0) {
// this.setState로 count를 하나 빼줍니다!
this.setState({ count: this.state.count - 1 });
}else{
window.alert('네모가 없어요!');
}
};
render() {
// 배열을 만듭니다.
// Array.from()은 배열을 만들고 초기화까지 해주는 내장 함수입니다.
// Array.from()의 첫번째 파라미터로 {length: 원하는 길이} 객체를,
// 두번째 파라미터로 원하는 값을 반환하는 콜백함수를 넘겨주면 끝!
// array의 내장함수 대부분은 콜백 함수에서 (현재값, index넘버)를 인자로 씁니다.
const nemo_count = Array.from({ length: this.state.count }, (v, i) => i);
// 콘솔로 만들어진 배열을 확인해봅니다. 숫자가 0부터 순서대로 잘 들어갔나요?
console.log(nemo_count);
return (
<div className="App">
{nemo_count.map((num, idx) => {
return (
<div
key={idx}
style={{
width: "150px",
height: "150px",
backgroundColor: "#ddd",
margin: "10px",
}}
>
nemo
</div>
);
})}
<div>
{/* 함수를 호출합니다. 이 클래스 안의 addNemo 함수를 불러오기 때문에 this.addNemo로 표기해요. */}
<button onClick={this.addNemo}>하나 추가</button>
<button onClick={this.removeNemo}>하나 빼기</button>
</div>
</div>
);
}
}
export default App;
이번에는 함수형 컴포넌트에서 어떻게 state를 쓸 수 있는 지 봅시다.
함수형 컴포넌트는 클래스형처럼 자체적으로 state를 가지고 있지 않지만, react hooks를 사용하면 state를 가질 수 있습니다!
(1) Nemo 컴포넌트 만들기
앞으로 새 함수형 컴포넌트를 만들 때는 파일을 만들고, 함수형 컴포넌트 껍데기까지 만들어주세요! export 잊지 말기! 😉
import React from "react";
const Nemo = (props) => {
// 반환할 리액트 요소가 없을 때는 null을 넘겨주세요! 처음 껍데기 잡으실때도 null을 넘겨주면 굳!
return null;
}
export default Nemo;
(2) App에서 불러오기
// import 먼저 하고
import Nemo from "./Nemo";
...
<div className="App">
{/*컴포넌트 불러다 쓰기*/}
<Nemo/>
...
...
(3) useState()로 count를 state로 등록하자
// count에는 state 값이, setCount는 count라는 state 값을 수정하는 함수가 될거예요.
// useState(초기값): () 안에 초기값을 넣어줍니다.
const [count, setCount] = React.useState(3);
(4) 뷰를 만들고(=반환할 리액트 요소를 만들고),
const nemo_count = Array.from({ length: count }, (v, i) => i);
// 반환할 리액트 요소가 없을 때는 null을 넘겨주세요!
return (
<div className="App">
{nemo_count.map((num, idx) => {
return (
<div
key={idx}
style={{
width: "150px",
height: "150px",
backgroundColor: "#ddd",
margin: "10px",
}}
>
nemo
</div>
);
})}
<div>
<button>하나 추가</button>
<button>하나 빼기</button>
</div>
</div>
);
(5) 함수를 만들어서,
const addNemo = () => {
// setCount를 통해 count에 저장된 값을 + 1 해줍니다.
setCount(count + 1);
};
const removeNemo = () => {
// setCount를 통해 count에 저장된 값을 - 1 해줍니다.
// 이번엔 if문 대신 삼항 연산자로 해볼거예요!
setCount(count > 0 ? count - 1 : 0);
};
(6) 연결하자!
<div>
{/* 함수를 호출합니다. */}
<button onClick={addNemo}>하나 추가</button>
<button onClick={removeNemo}>하나 빼기</button>
</div>
(7) 완성본 코드
import React from "react";
const Nemo = (props) => {
// count에는 state 값이, setCount는 count라는 state 값을 수정하는 함수가 될거예요.
// useState(초기값): () 안에 초기값을 넣어줍니다.
const [count, setCount] = React.useState(3);
const addNemo = () => {
// setCount를 통해 count에 저장된 값을 + 1 해줍니다.
setCount(count + 1);
};
const removeNemo = () => {
// setCount를 통해 count에 저장된 값을 - 1 해줍니다.
// 이번엔 if문 대신 삼항 연산자로 해볼거예요!
setCount(count > 0 ? count - 1 : 0);
};
const nemo_count = Array.from({ length: count }, (v, i) => i);
// 반환할 리액트 요소가 없을 때는 null을 넘겨주세요!
return (
<div className="App">
{nemo_count.map((num, idx) => {
return (
<div
key={idx}
style={{
width: "150px",
height: "150px",
backgroundColor: "#ddd",
margin: "10px",
}}
>
nemo
</div>
);
})}
<div>
{/* 함수를 호출합니다. */}
<button onClick={addNemo}>하나 추가</button>
<button onClick={removeNemo}>하나 빼기</button>
</div>
</div>
);
};
export default Nemo;
정말 중요한 부분입니다. 헷갈리지 않도록 꼭 손에 익혀야해요!
특히 제가 컴포넌트를 만들고→ state를 쓰는 순서! 뷰 먼저→ 그 다음은 state를 만들고(기본값도 잡아주고!)→ state를 조작하는 무언가를 만들어서→연결한다!
이 순서가 중요해요!
오늘은 이상하게 피곤했던거 같다.
반복이 매우 중요해 보인다. 무조건 반복하자..
되새기자 꿈에서도 나올정도로 되새기자
나는 많이 부족하니깐 남들과 같은 시간을 공부하면 안된다.
더 열심히 하자