
React Hooks
React Hooks는 React 16.8 버전에서 도입된 기능으로 함수형 컴포넌트에서도 상태 관리와 생명 주기 기능을 사용할 수 있게 해줍니다. Hook을 이용하여 기존 Class 바탕의 코드를 작성할 필요 없이 상태 값과 여러 React의 기능을 사용할 수 있으므로 함수형 컴포넌트를 사용하는데 있어 더욱 편리하고 유연하게 개발 할 수 있습니다.
React에서 제공하는 내장 hook과 별도의 custom hooks이 만들어져 있기 때문에 로직을 재사용하고 코드를 더욱 간결하게 만들 수 있습니다.
State Hook(useState)
useState는 현재의 state 값과 그 값을 업데이트 하는 함수를 쌍으로 제공하여 이벤트 핸들러나 다른 곳에서 호출할 수 있습니다.
초기 상태를 인자로 받아 현재 상태와 그 상태를 업데이트하는 함수를 튜플로 반환합니다.
import React, { useState } from 'react';
function Example() {
// "count"라는 새 상태 변수를 선언
// useState의 매개변수가 count의 초기값
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
{/* 버튼을 누르면 count의 값이 1씩 증가 */}
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
Effect Hook(useEffect)
side effects를 함수형 컴포넌트에서 다루기 위한 Hook으로 데이터를 가져오거나 DOM 조작, 이벤트 리스너 등록 및 제거와 같은 작업에 사용됩니다.
useEffect(()=>{});
useEffect(()=>{},[]);
useEffect(()=>{},[count]);
useEffect(()=>{},[count,count2]);
각각의 차이점을 알고가는게 좋습니다.
import React, { useState, useEffect } from 'react';
function ExampleComponent() {
const [count, setCount] = useState(0);
const [count2, setCount2] = useState(0);
// useEffect(()=>{});
useEffect(()=>{
console.log("컴포넌트가 렌더링 될 때마다 로그 출력");
});
// useEffect(()=>{},[]);
useEffect(()=>{
console.log("컴포넌트가 마운트될때 한 번만 실행");
},[]);
// useEffect(()=>{},[count]);
// 배열에 상태값이 있으면 그 상태값이 변하는지 주시
useEffect(()=>{
console.log("count의 상태가 변하면 출력");
},[count]);
// useEffect(()=>{},[count, count2]);
useEffect(() => {
console.log("count, count2 둘 중 하나라도 상태값이 변하면 로그 출력");
}, [count, count2]);
return (
<div>
<p>Count: {count} | Count2: {count2}</p>
<button onClick={() => setCount(count + 1)}> + Count </button>
<button onClick={() => setCount2(count2 + 1)}> + Count2 </button>
</div>
);
}
달력 만들기
useState와 useEffect를 사용하여 달력을 만들어 보며 hook과 component에 대한 연습 진행
프로젝트 구조

초기 설정
React 프로젝트 파일 생성
npx create-react-app calender
components/Container.jsx
현재 월을 기준으로 일수를 계산
// rafce를 입력하여 자동완성으로 기본 구조 생성
import React from "react";
function DateArr(Year, Month) {
let getArr = [];
let nullArrBefore = [];
let nullArrAfter = [];
let getDay = 0;
// 월의 자리수를 맞추기 위해 1자리 월의 경우 0을 붙여줌
if (Month < 10) {
getDay = new Date(`${Year}-0${Month}-01`).getDay();
} else {
getDay = new Date(`${Year}-${Month}-01`).getDay();
}
// 이번달 일수를 가져옴
const getArrlength = new Date(Year, Month, 0).getDate();
// 숫자에 일을 붙여 배열에 저장
for (let i = 1; i < getArrlength + 1; i++) {
getArr.push(i + " 일");
}
// 앞 부분에 빈공간을 null로 채우기 위해 오늘 요일만큼 null을 채움
for (let j = 0; j < getDay; j++) {
nullArrBefore.push(null);
}
const Arrlength = 42 - (getArr.length + nullArrBefore.length);
// 42칸의 배열중 요일수 + null로 채운만큼의 길이를 빼고난 나머지 만큼 null로 채움
for (let x = 0; x < Arrlength; x++) {
nullArrAfter.push(null);
}
// 앞을 null로 채운뒤 요일을 넣고 남은 공간을 null로 채움
let Arr = [...nullArrBefore, ...getArr, ...nullArrAfter];
return Arr.map((e) => (
<div className="dates">
<span>{e}</span>
</div>
));
}
const Container = ({ Year, Month }) => {
return <div className="ContainerWrap">{DateArr(Year, Month)}</div>;
};
export default Container;
components/Footer.jsx
달력의 맨 아래 공간에 글 출력(없어도 됨)
import React from "react";
// <> 이거로 쓰닌까 div가 따로 만들어지는게 아니라 제일 하단에 span 한줄만 붙음
const Footer = () => {
return (
<>
<span className="FooterSpan">완성!</span>
</>
);
};
export default Footer;
components/Header.jsx
달력의 윗부분에 대한 내용 출력
import React, { useEffect, useState } from "react";
import Container from "../components/Container";
const Header = () => {
let getYear = new Date().getFullYear();
let getMonth = new Date().getMonth() + 1;
const [active, setActive] = useState(false);
// active 속성이 바뀌는걸 감지
useEffect(() => {}, [active]);
function ContainerOnOff() {
const ContainerWrap = document.querySelector(".ContainerWrap");
if (!active) {
ContainerWrap.classList.add("active");
setActive(true);
} else {
ContainerWrap.classList.remove("active");
setActive(false);
}
}
function DrawDays() {
const Days = ["일", "월", "화", "수", "목", "금", "토"];
return Days.map((days) => (
<div className="days">
<span>{days}</span>
</div>
));
}
return (
<div className="HeaderWrap">
<div className="HeaderTop">
<div className="btnBox">
<div className="redBtn"></div>
<div className="yellowBtn"></div>
<div className="greenBtn"></div>
</div>
</div>
<div className="HeaderMiddle">
<div className="title">
<span>
{getYear}년 {getMonth}월
</span>
</div>
<div className="hamber" onClick={ContainerOnOff}>
<span className="hamberSpan"></span>
</div>
</div>
<div className="HeaderBottom">
<div className="BottomWrap">{DrawDays()}</div>
</div>
<Container Year={getYear} Month={getMonth} />
</div>
);
};
export { Header };
pages/Main.jsx
Header와 Footer를 불러들임
import React from "react";
import { Header } from "../components/Header";
import Footer from "../components/Footer";
const Main = () => {
return (
<div className="AppWrap">
<Header />
<Footer />
</div>
);
};
export default Main;
App.js
import "./App.css";
import Main from "./pages/Main";
function App() {
return (
<div className="App">
<Main />
</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";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
// 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();

'React' 카테고리의 다른 글
| [React] Redux와 OpenWeather (1) | 2023.09.14 |
|---|---|
| [React] react-router-dom을 알아보기 (1) | 2023.09.07 |
| [React] Babel과 webpack 알아보기 (0) | 2023.09.07 |
| [React] React 시작하기 (3) | 2023.06.28 |