๐ ์? (React ์ฌ์ฉ ์ด์ )
โผ Single Page Application์ ๋ง๋ค ๋, ์ฌ์ฉํ๋ค.
๐ฌ Single Page Application์ ์๋ก๊ณ ์นจ ์์ด ๋์๊ฐ๋ ํ์ด์ง๋ก ์ฑ์ฒ๋ผ ๋ถ๋๋ฝ๊ฒ ๋์ํ๋ค.
โผ๋ฐ๋๋ผ JS๋ก ์น ํ์ด์ง๋ฅผ ๋ง๋ค ๊ฒฝ์ฐ, ์ฝ๋๊ฐ ๊ธธ์ด์ง๊ณ ๋๋ฌด ๋ณต์กํด์ง๋ค. ๊ทธ๋์ React ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ค.
โผ React๋ฅผ ์ฌ์ฉํ๋ฉด HTML ์ฌ์ฌ์ฉ์ด ํธ๋ฆฌํด์ง๋ค.
โจ React๋ HTML, CSS, JavaScript ์น ๊ฐ๋ฐ์ ํธ๋ฆฌํ๊ฒ ๋์์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค.
๐ ๊ฐ๋ฐ ํ๊ฒฝ ์ธํ ํ๊ธฐ
1. node js๋ฅผ ์ค์นํ๋ค.
2. ํฐ๋ฏธ๋์์ ์ํ๋ ๊ฒฝ๋ก๋ก ์ด๋ํ ๋ค, npx create-react-app {ํ๋ก์ ํธ ํด๋๋ช } ๋ช ๋ น์ด๋ฅผ ์ ๋ ฅํ๋ค.
๐ฌ create-react-app(cra)๋ React๋ก ๊ฐ๋ฐ ํ๋ก์ ํธ๋ฅผ ์์ํ ๋, ์นํฉ, ๋ฐ๋ฒจ ๋ฑ ๊ธฐ๋ณธ์ ์ธ ํ๋ก์ ํธ ์ธํ ์ ๋์์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค.
๐ฌ ์นํฉ(webpack), ๋ฐ๋ฒจ(babel)์ ์ญํ ์ ES ์ต์ ๋ฒ์ ์ ์ฝ๋๋ค์ ๋ชจ๋ ๋ธ๋ผ์ฐ์ ์์ ํด์ํ ์ ์๋ ์ฝ๋๋ก ๋ฐ๊ฟ์ฃผ๋ ์ญํ ์ ํ๋ค.
3. ๊ฐ์ธ IDE๋ก ํ๋ก์ ํธ๋ฅผ Open ํ๊ณ , ํฐ๋ฏธ๋์์ npm start ๋ช ๋ น์ด๋ฅผ ์ ๋ ฅํ๋ฉด localhost:3000์์ ํ์ธํ ์ ์๋ค.
โ ํ๋ก์ ํธ ๊ตฌ์กฐ
โผ node_modules ํด๋๋ ํ๋ก์ ํธ์ ํ์ํ ๋ชจ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฝ๋ ๋ณด๊ดํจ์ด๋ค.
โผ public ํด๋๋ static ํ์ผ์ ๋ณด๊ดํ๋ ๊ณณ์ด๋ค.
๐ฅ public ํด๋ ์์ ์๋ ํ์ผ๋ค์ bundling ์์ ์ด ์งํ๋ ๋, ์์ถ๋์ง ์๋๋ค.
โผ src/App.js๊ฐ ๋ฉ์ธ ํ์ด์ง๋ฅผ ๊ตฌ์ฑํ๊ณ ์๋ JS ํ์ผ์ด๋ค.
๐ฅ ๋ณดํต์ HTML ํ์ผ๋ก ํ์ด์ง๋ฅผ ๊ตฌ์ฑํ๋ ๊ฒ์ด ๊ธฐ๋ณธ์ด์ง๋ง, src ํด๋ ์๋ html ํ์ผ์ด ์๋ ์ด์ ๋ public ํด๋ ์๋ index.html์ด ์กด์ฌํ๊ณ , App.js์ ์ปดํฌ๋ํธ๋ฅผ index.js์์ root์ render ํ๊ธฐ ๋๋ฌธ์ด๋ค.
โผ package.json์ ํ๋ก์ ํธ ์ ๋ณด๋ค์ด ๊ธฐ์ ๋๋ ํ์ผ์ด๋ค.
๐ JSX
โผ JavaScript ์์์ HTML๋ฅผ ์ฝ๊ฒ ์์ฑ ๋ฐ ์ฌ์ฉํ ์ ์๋๋ก ๋์์ฃผ๋ ๋ฌธ๋ฒ์ด๋ค.
โผ ์๋ React์์ div ํ๊ทธ๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ React.createElement("{ํ๊ทธ๋ช }", null, "{๊ฐ}") ํจ์๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด์๋๋ฐ, ์ด๋ฅผ JSX๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๊ฒ ํ๊ทธ๋ฅผ ๋ง๋ค์ด์ ์ฌ์ฉํ ์ ์๋๋ก ํด์ค๋ค.
โ ์ฌ์ฉ๋ฒ
import "./App.css";
function App() {
return (
<div className="App">
<div className="black-nav">
<h4>Nav</h4>
</div>
</div>
);
}
export default App;
โผ css ํ์ผ์ ์คํ์ผ์ ์ ์ฉํ๊ธฐ ์ํด์๋ class="{ํด๋์ค ๋ช }"์ ์ฌ์ฉํ์๋๋ฐ, JSX ์์๋ className์ ์ฌ์ฉํด์ผ ํ๋ค.
โผ class๋ ์ด๋ฏธ JavaScript์์ class ๋ฌธ๋ฒ์ผ๋ก ์๊ธฐ ๋๋ฌธ์, className์ ์ฌ์ฉํด์ผ ํ๋ค.
import "./App.css";
function App() {
let title = "์ ๋ชฉ์
๋๋ค.";
return (
<div className="App">
<div className="black-nav">
<h4>Nav</h4>
</div>
<h4>{title}</h4>
</div>
);
}
export default App;
โผ JSX์์๋ ์ค๊ดํธ ( {} )๋ฅผ ์ฌ์ฉํด์ ๋ณ์ ๊ฐ์ ๋ฃ์ด์ค ์ ์๋ค.
โผ ์ค๊ดํธ ์์์๋ JavaScript์ if๋ฌธ, for๋ฌธ ๋ฑ์ ์ฌ์ฉํ ์ ์๋ค.
โผ ์ด๋ฌํ ๋ฐฉ๋ฒ์ ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ์ด๋ผ๊ณ ํ๋ค.
...
<h4 style={ { color: "red", fontSize: "50px" } }>{title}</h4>
...
โผ JSX์์ style ์์ฑ์ style={ {color : "red"} } ํ์์ผ๋ก ์ฌ์ฉํ ์ ์๋ค.
โผ font-size์ ๊ฒฝ์ฐ -๋ JavaScript์์ ๋นผ๊ธฐ๋ก ์ฌ์ฉํ๋ฏ๋ก, ์นด๋ฉ ํ๊ธฐ๋ฒ์ ์ฌ์ฉํด์ ๊ธฐ์ ํด์ผ ํ๋ค.
import "./App.css";
function App() {
let title = "์ ๋ชฉ์
๋๋ค.";
return (
<div></div>
<div></div>
);
}
export default App;
โผ return () ์์๋ ๋ณ๋ ฌ๋ก ํ๊ทธ 2๊ฐ ์ด์์ ๊ธฐ์ ํ๋ฉด ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
โผ ์ต์์ ๋ถ๋ชจ ํ๊ทธ๋ 1๊ฐ๋ก ํต์ผ์์ผ์ผ ํ๋ค.
return (
<>
<div></div>
<div></div>
</>
)
โผ return() ์์ ํ๋์ ํ๊ทธ๊ฐ ๋ฃจํธ์ฌ์ผ ํ๊ธฐ ๋๋ฌธ์, ์ฌ๋ฌ ํ๊ทธ๋ฅผ ๋ฌถ๊ธฐ ์ํด์ ์๋ฏธ ์์ด ์ฌ์ฉํ๋ ํ๊ทธ๋ฅผ <></>์ ๊ฐ์ด ์ฌ์ฉํ ์ ์๋ค.
๐ useState
โผ ์๋ฃ๋ฅผ ์ ๊น ์ ์ฅํ ๋๋ ๋ณ์๋ฅผ ์ฌ์ฉํด๋ ๋์ง๋ง, ๊ด๋ฆฌ๊ฐ ํ์ํ ๋ฐ์ดํฐ๋ useState๋ฅผ ์ฌ์ฉํด์ ์ ์ฅํด์ผ ํ๋ค.
โ ๋ณ์์ State์ ์ฐจ์ด์
โผ ๋ณ์๋ฅผ ์ฌ์ฉํด์ HTML์ ๋ฐ์ํด์ ํ๋ฉด์ ์ถ๋ ฅ๋ ์ดํ, ํด๋น ๋ณ์ ๊ฐ์ ์์ ํด๋ ํ๋ฉด์ ๊ฐ์ ๋ณ๊ฒฝ๋์ง ์๋๋ค.
โผ ๋ฐ๋ฉด, State๋ฅผ ์ฌ์ฉํ๊ณ State ๋ณ์ ๊ฐ์ ๋ณ๊ฒฝํ๋ฉด, ์์ ๋ถ๋ถ์ ์ฌ๋ ๋๋ง์ด ๋ฐ์ํ์ฌ ํ๋ฉด์ ๊ฐ๋ ๋ณ๊ฒฝ๋๋ค.
๐ฅ ์ฆ, ๊ฐ์ ๋ณ๊ฒฝํ ๋, HTML์ ๋ฐ์๋๊ฒ ๋ง๋ค๊ณ ์ถ์ผ๋ฉด State๋ฅผ ์ฌ์ฉํ๋ค.
โ ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ
import { useState } from "react";
import "./App.css";
function App() {
let [title, setTitile] = useState("์ ๋ชฉ์
๋๋ค.");
return (
<div className="App">
<div className="black-nav">
<h4>Blog</h4>
</div>
<div className="content-list">
<h4>{title}</h4>
</div>
</div>
);
}
export default App;
โผ [{์ฌ์ฉํ ๋ณ์๋ช }, {๋ณ๊ฒฝ ํจ์๋ช }] = useState("{์ด๊ธฐํ ๊ฐ}")์ผ๋ก ์ฌ์ฉํ ์ ์๋ค.
โผ state ๊ฐ์ ๋ฑํธ๋ก ๋ณ๊ฒฝํ๋ฉด HTML์ ๋ฐ์๋์ง ์๋๋ค. ๋ฐ๋ผ์ ์ฌ๋ ๋๋ง์ด ๊ฐ๋ฅํ๋๋ก ๋ฑ๋กํ ๋ณ๊ฒฝ ํจ์๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
โผ ์ฌ๊ธฐ์ title ๊ฐ์ ๋ณ๊ฒฝํ๊ณ ์ถ๋ค๋ฉด, setTitle("{์ํ๋ ๊ฐ}") ์ฝ๋๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
๐ฅ set~~~ ํจ์๋ ๋ฆ๊ฒ ์คํ๋๋ค. ๊ทธ๋์, set~~ ํจ์๋ฅผ ๋ง๋๋ฉด ์๋ ์ฝ๋ ๋ถํฐ ๋ค ์คํํ ๋ค, set~~ ํจ์๋ฅผ ์คํํ๋ค.
...
let [title, setTitile] = useState(["์ ๋ชฉ1", "์ ๋ชฉ2", "์ ๋ชฉ3"]);
<div className="content-list">
<h4>{title[0]}</h4>
<p>2์ 28์ผ ๋ฐํ</p>
</div>
<div className="content-list">
<h4>{title[1]}</h4>
<p>2์ 28์ผ ๋ฐํ</p>
</div>
<div className="content-list">
<h4>{title[2]}</h4>
<p>2์ 28์ผ ๋ฐํ</p>
</div>
...
โผ ์์ ๊ฐ์ด ๋ฐฐ์ด์ ๋ด๊ณ , ์ธ๋ฑ์ค ์ ๊ทผ์ผ๋ก๋ ์ฌ์ฉํ ์ ์๋ค.
โ state ๋ณ๊ฒฝ ํจ์ ํน์ง
const [titles, setTitile] = useState(["์ ๋ชฉ1", "์ ๋ชฉ2", "์ ๋ชฉ3"]);
const changeTitle = (idx, title) => {
titles[idx] = title;
setTitile(titles);
};
โผ ๊ธฐ์กด state์ ์ ๊ท state๊ฐ ๊ฐ์ ๊ฒฝ์ฐ(๊ธฐ์กด state == ์ ๊ท state) ๋ณ๊ฒฝํ์ง ์๋๋ค.
โผ ๋ฐ๋ผ์ ์์ ์ฝ๋๋ฅผ ์คํํ๋ฉด ๋ณ๊ฒฝ๋์ง ์๋๋ค.
const [titles, setTitile] = useState(["์ ๋ชฉ1", "์ ๋ชฉ2", "์ ๋ชฉ3"]);
// 1๋ฒ
const changeTitle = (idx, title) => {
const copy = [...titles];
copy[idx] = title;
setTitile(copy);
};
// 2๋ฒ
const changeTitle = (idx, title) => {
titles[idx] = title;
setTitles([...titles]);
};
โผ ์์ ๊ฐ์ด 1๋ฒ, 2๋ฒ ๋ฐฉ๋ฒ์ผ๋ก ์๋ก์ด Array๋ฅผ ๋ง๋ค์ด์ state๋ฅผ ๋ณ๊ฒฝํด์ผ ์ ์ฉ๋๋ค.
โผ ์ฆ, state๊ฐ Array๋ Object์ด๋ฉด์ state๋ฅผ ๋ณ๊ฒฝํ ๋, ๋ ๋ฆฝ์ ์ธ ์นดํผ๋ณธ์ ๋ง๋ค์ด์ ์์ ํด์ผ ํ๋ค.
๐ Component
โผ div ํ๊ทธ์ ํ ๋ฉ์ด๋ฆฌ๋ฅผ ํ๋์ ๋จ์ด๋ก ์ฌ์ฉํ ์ ์๋๋ก ๋์์ฃผ๋ ๋ฌธ๋ฒ
โ Component๋ง๋๋ ๋ฐฉ๋ฒ
1. function์ ๋ง๋ ๋ค.
2. return () ์์ html์ ๋ด๋๋ค.
3. <ํจ์๋ช ></ํจ์๋ช >์ผ๋ก ์์ฑํด์ ์ฌ์ฉํ๋ค.
โ Component ์ด๋ค ๊ฒฝ์ฐ์ ์ฌ์ฉํ ๊น?
1. ๋ฐ๋ณต์ ์ธ HTML์ ์ถ์ฝํ ๋
3. ์์ฃผ ๋ณ๊ฒฝ๋๋ HTML์ธ ๊ฒฝ์ฐ
function Modal() {
return (
<div className="modal">
<h4>์ ๋ชฉ</h4>
<p>๋ ์ง</p>
<p>์์ธ ๋ด์ฉ</p>
</div>
);
}
โผ ์์ ๊ฐ์ด Component๋ฅผ ๋ง๋ค๊ณ , <Modal></Modal> or <Modal /> ํ์์ผ๋ก ์ฌ์ฉํ ์ ์๋ค.
๐ ๋ฐ๋ณต๋ฌธ
โผ ์ค๊ดํธ ์์ JavaScript ๋ฌธ๋ฒ์ ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์, for๋ฌธ ๋์ , map()์ ์ฌ์ฉํด์ ๋ฐ๋ณต๋๋ HTML์ ์ฒ๋ฆฌํ ์ ์๋ค.
{titles.map((title, idx) => {
return (
<div className="content-list" key={idx}>
<h4
onClick={() => {
modal ? setModal(false) : setModal(true);
}}
>
{title + " "}
<span
onClick={(event) => {
addLikeCount(idx);
event.stopPropagation();
}}
>
๐ค{" "}
</span>
{likeCounts[idx]}
</h4>
</div>
);
})}
โผ map ํจ์๋ฅผ ์ฌ์ฉํด์ ๊ธ ์ ๋ชฉ ๊ฐ์๋งํผ, div ํ๊ทธ๋ฅผ ๋ง๋ค์ด์ ํ๋ฉด์ ์ถ๋ ฅํ๋ค.
โผ HTML์ ๋ฐ๋ณต ์์ฑํ๋ฉด, key ์์ฑ์ ํตํด Unique ํจ์ ๋ณด์ฅํด์ผ ํ๋ค.
๐ Props
โผ ๋ณ์์ Scope์ ์ํด์, ๋ถ๋ชจ Component์ ๋ณ์๋ฅผ ์ฌ์ฉํ ์ ์์ด ์ง์ํ๋ ๋ฌธ๋ฒ์ด๋ค.
โผ ๋ถ๋ชจ Component์ state๋ฅผ ๋ณต์ฌํด์ ์ ๋ฌํด, ์์ Component์์ ์ฌ์ฉํ ์ ์๋๋ก ๋์์ฃผ๋ ๋ฌธ๋ฒ์ด๋ค.
โผ ํ์ Component๋, ์์ Component์์ ๋ถ๋ชจ Component๋ก์ ์ ๋ฌ์ ๋ถ๊ฐ๋ฅํ๋ค.
<Modal titles={titles} days={days} contentIdx={contentIdx} />
const Modal = ({ titles, days, contentIdx }) => {
return (
<div className="modal">
<h4>{titles[contentIdx]}</h4>
<p>{days[contentIdx]}</p>
<p>์์ธ ๋ด์ฉ</p>
</div>
);
};
โผ ์ ์ฝ๋์ ๊ฐ์ด Modal Component์ ์์ฑ์ผ๋ก ์ ๋ฌํ Props ๋ณ์๋ช ์ ์ ์ธ, ํ ๋น์ ํ๊ณ , Modal ํจ์์์ { {Props ๋ณ์๋ช } }์ผ๋ก ๋ฐ์์ ์ฌ์ฉํ ์ ์๋ค.
๐ ์ด๋ฏธ์ง ์ฒจ๋ถํ๊ธฐ
โ src ํด๋ ์๋ ์กด์ฌํ๋ ์ด๋ฏธ์ง ์ฒจ๋ถํ๊ธฐ
import mainBg from "./img/shopping.png";
function App() {
return (
<div className="App">
<Nav></Nav>
<div
style={{
backgroundImage: `url(${mainBg})`,
backgroundSize: "cover",
backgroundPosition: "center",
height: "300px",
}}
></div>
</div>
);
}
โผ src ํด๋ ๋ด์ ์๋ ์ฌ์ง๋ค์ import๋ฅผ ์ฌ์ฉํด์ src ์๋ ๊ฒฝ๋ก๋ฅผ ๊ธฐ์ค์ผ๋ก ๊ฒฝ๋ก๋ฅผ ๊ธฐ์ ํ๊ณ ์ฌ์ฉํ๋ค.
โ public ํด๋ ์๋ ์กด์ฌํ๋ ์ด๋ฏธ์ง ์ฒจ๋ถํ๊ธฐ
function App() {
return (
<div className="App">
<Nav></Nav>
<div className="container">
<div className="content">
<img src="/car.png" width="50%"></img>
<h4>Car</h4>
<p>์๋์ฐจ์ด๋ค.</p>
</div>
<div className="content">a</div>
<div className="content">a</div>
</div>
</div>
);
}
โผ src="/{ํ์ผ๋ช }" ํ์์ผ๋ก ์์ฑํ๋ฉด ์ฌ์ฉํ ์ ์๋ค.
๐ฅ .com์ ๋ฐํํ๋ ๊ฒ์ด ์๋. com/{์๋ธ ๊ฒฝ๋ก}/ ์ React ํ๋ก์ ํธ๋ฅผ ๋ฐํํ๊ฒ ๋๋ฉด ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
๐ฅ ์์ ๊ฐ์ ๊ฒฝ์ฐ์๋ src={process.env.PUBLIC_URL + "/car.png"} ํ์์ผ๋ก ์ฝ๋๋ฅผ ์์ฑํด์ผ ํ๋ค.
๐ Router
โผ React๋ SPA๋ก index.html ํ์ผ ํ๋๋ง์ ์ฌ์ฉํ๋ค.
โผ ๋ฐ๋ผ์, Router๋ ์ค์ ํ uri ๋ง๋ค ํ์ด์ง๋ฅผ ๋น์ฐ๊ณ , ๋ฑ๋กํ ์ปดํฌ๋ํธ๋ฅผ ๋ณด์ฌ์ค๋ค. (๋ผ์ฐํ )
โผ npm install react-router-dom์ผ๋ก ์ค์นํด์ ์ฌ์ฉํ ์ ์๋ค.
โ react-router-dom ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉํ๊ธฐ
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { BrowserRouter } from "react-router-dom";
import { Routes, Route } from "react-router-dom";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<BrowserRouter>
<Routes>
<Route path="/" element={<App />} />
<Route path="/detail" element={<div>์์ธ ํ์ด์ง</div>} />
<Route path="*" element={<div>์๋ ํ์ด์ง</div>}></Route>
</Routes>
</BrowserRouter>
);
โผ index.js ํ์ผ์์ <BrowserRouter> -> <Routes> -> <Route>๋ก ์ฌ์ฉํ๋ค.
โผ Routes, Route๋ฅผ import ํ๋ค.
โผ Route ์ปดํฌ๋ํธ๋ uri ๋ณ๋ก ํ์ด์ง๋ฅผ ๋๋ ๋, ์ฌ์ฉํ๋ค.
โผ path๋ uri ์ค์ , element๋ ํด๋น uri๋ก ์ด๋ํ์ ๋, ๋ณด์ฌ์ค element๋ฅผ ์์ฑํ ์ ์๋ค.
โผ path๋ฅผ "*"๋ก ์ค์ ํ๋ฉด, ์์ ์ค์ ํ path ์ ์ธ ๋ค๋ฅธ uri๋ฅผ ์ ๋ ฅ ์, ํด๋น element๊ฐ ์ถ๋ ฅ๋๋ค.
import { Link } from "react-router-dom";
const Item = ({ item }) => {
return (
<div className="content">
<img src={item.imageSrc} width="50%" alt="error"></img>
<h4>{item.title}</h4>
<p>{item.price}</p>
<Link to="/detail">์์ธํ์ด์ง</Link>
</div>
);
};
โผ Link ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํด์ ๋๋ ์ ๋, ์ํ๋ uri๋ก ์ด๋ํ๊ฒ ํ๋ค.
โผ to๋ฅผ ์ฌ์ฉํด์ ๋๋ ์ ๋, ์ด๋ํ ๊ฒฝ๋ก๋ฅผ ์์ฑํ๋ค.
โผ Link ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋ฉด a ํ๊ทธ๊ฐ ์์ฑ๋๋ค.
import { useNavigate } from "react-router-dom";
const Item = ({ item }) => {
const navigate = useNavigate();
return (
<div
className="content"
onClick={() => {
navigate("/detail");
}}
>
<img src={item.imageSrc} width="50%" alt="error"></img>
<h4>{item.title}</h4>
<p>{item.price}</p>
</div>
);
};
โผ useNavigate()๋ ํ์ด์ง ์ด๋์ ๋์์ฃผ๋ Hook์ด๋ค.
๐ฅ Hook์ ์ ์ฉํ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ํจ์์ด๋ค.
โผ Link ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋ฉด a ํ๊ทธ๊ฐ ์์ฑ๋๋ฏ๋ก, useNavigate()๋ก ์์ฑํ ํจ์๋ฅผ ์ฌ์ฉํ์ฌ onClick ์์ฑ์ ๋ฃ์ด์ค ์ ์๋ค.
โผ navigate ํจ์์ ์ธ์๋ก ์ซ์๋ฅผ ๋ฃ์ผ๋ฉด, ํด๋น ์ซ์๋งํผ ์ด๋ํ๊ณ , ๊ฒฝ๋ก๋ฅผ ๋ฃ์ผ๋ฉด ํด๋น ๊ฒฝ๋ก๋ก ์ด๋ํ๋ค.
โผ BrowserRouter ์ปดํฌ๋ํธ ์๋์์๋ง ์ฌ์ฉํ ์ ์๋ค.
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<>
<BrowserRouter>
<Routes>
<Route path="/detail" element={<Detail />}>
<Route path="one" element={<div>1์
๋๋ค.</div>}></Route>
<Route path="two" element={<div>2์
๋๋ค.</div>}></Route>
</Route>
</Routes>
</BrowserRouter>
</>
);
โผ Route ์ปดํฌ๋ํธ ์์ Route๋ฅผ ๋ ์ ์ํ๋ฉด, nested routes๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
โผ nested routes๋ฅผ ์ฌ์ฉํ๋ฉด, ๋ถ๋ชจ elements๋ ํ๋ฉด์ ์ถ๋ ฅ๋๋ค.
โผ /detail/one, /detail/two๋ก ๋์ํ๋ค.
๐ฅ nested routes์ path ์์๋ "/"๋ฅผ ๋ถ์ด๋ฉด ์ ๋๋ค.
โผ nested routes๋ ๋ถ๋ชจ element์ ํฐ ์ฐจ์ด๊ฐ ์์ ๋, ์ฌ์ฉํ๋ค.
import { Outlet } from "react-router-dom";
const Detail = ({ imageSrc, title, content, price }) => {
return (
<div>
<div>
<img src={imageSrc} alt="error" width="100%"></img>
<h4>{title}</h4>
<p>{content}</p>
<p>{price}</p>
<Outlet></Outlet>
<button>์ฃผ๋ฌธํ๊ธฐ</button>
</div>
</div>
);
};
โผ nested routes์ element๋ ๋ถ๋ชจ element์ ์ด๋์ ๋ณด์ฌ์ค์ง ์์ฑํด์ผ ํ๋ค.
โผ ๋ฐ๋ผ์, Outlet์ ์ฌ์ฉํ๋ฉด, ํด๋น ์๋ฆฌ์ nested routes์ element๊ฐ ์ ์ฉ๋๋ค.
โ URL ํ๋ผ๋ฏธํฐ ์ฌ์ฉ
import "./detail.css";
import { useParams } from "react-router-dom";
import { useState } from "react";
import data from "../../data";
const Detail = () => {
const [items] = useState(data);
const { id } = useParams();
return (
<div className="container">
<img src={items[id].imageSrc} alt="error" width="100%"></img>
<h4>{items[id].title}</h4>
<p>{items[id].content}</p>
<p>{items[id].price}</p>
<button>์ฃผ๋ฌธํ๊ธฐ</button>
</div>
);
};
export default Detail;
โผ useParams๋ฅผ ์ฌ์ฉํด์ ํ๋ผ๋ฏธํฐ ๊ฐ์ ๋ฐ์ ์ ์๋ค.
๐ Styled Component
โผ npm install styled-compnents๋ก ์ค์นํด์ ์ฌ์ฉํ ์ ์๋ค.
โผ css ํ์ผ๋ก ๊ฐ์ง ์๊ณ , JavaScript ๋ด์์ ๊ฐํธํ๊ฒ Componenet๋ก ์คํ์ผ๋ง์ ์ฌ์ฉํ ์ ์๋ค.
โ ์ฌ์ฉ๋ฒ
import styled from "styled-components";
const Detail = () => {
return (
<DetailBtn bg="black">์ฃผ๋ฌธํ๊ธฐ</DetailBtn>
);
};
const DetailBtn = styled.button`
background: ${(props) => props.bg};
color: ${(props) => (props.bg === "black" ? "white" : "black")};
padding: 10px;
`;
export default Detail;
โผ styled.{ํ๊ทธ}`{style}` ๋ฌธ๋ฒ์ ์ฌ์ฉํด์ ์คํ์ผ ๋ ํ๊ทธ Component๋ฅผ ์์ฑํด์ ์ฌ์ฉํ ์ ์๋ค.
โผ Styled Component๋ ๋ค๋ฅธ js ํ์ผ๋ก ์ค์ผ๋์ง ์๋ ์ฅ์ ์ ๊ฐ์ง๋ค.
๐ฅ React๋ ๋ชจ๋ css ํ์ผ์ bundling ์์ ์์ ํ๋๋ก ํฉ์น๊ธฐ ๋๋ฌธ์ ์ค์ผ๋ ์ ์๋ค.
๐ฅ Styled Component๋ฅผ ์ฌ์ฉํ์ง ์์ผ๋ฉด, ์ค์ผ์ ๋ฐฉ์งํ๊ธฐ ์ํด {์ปดํฌ๋ํธ}.module.css๋ก ํ์ผ๋ช ์ ์ง์ด์ผ ํ๋ค.
โผ style ํ๊ทธ๋ก์จ ์คํ์ผ์ ์ ์ฉํ๊ธฐ ๋๋ฌธ์, ํ์ด์ง ๋ก๋ฉ ์๊ฐ์ด ๋จ์ถ๋๋ค.
โผ props๋ฅผ ์ฌ์ฉํด์ style์ ๋ณ๊ฒฝํ ์ ์๋ค.
โผ ๊ฐ๋จํ ํ๋ก๊ทธ๋๋ฐ ๊ฐ๋ฅํ๋ค.
โ ์ ๋๋ฉ์ด์
const fadeInOut = keyframes`
0% {
opacity: 0;
}
100% {
opacity: 1;
}
`;
const DetailBtn = styled.button`
background: ${(props) => props.bg};
color: ${(props) => (props.bg === "black" ? "white" : "black")};
padding: 10px;
animation: ${fadeInOut} 1s;
`;
โผ keyframes``๋ก ์ ๋๋ฉ์ด์ ์ ๊ตฌ์ฑํ๊ณ , ์ํ๋ ๊ณณ์์ animation: ${๋ณ์๋ช } {์๊ฐ}์ผ๋ก ์ ์ฉํ ์ ์๋ค.
๐ useEffect
๐ฌ Component Lifecycle
โผ Component์ ์๋ช ์ฃผ๊ธฐ: mount, update, unmount
โผ Component๊ฐ ํ๋ฉด์ ๋ณด์ด๋ ๊ฒ์ mount ๋์๋ค๊ณ ํ๋ค.
โผ ๊ฐ๋ฐ์๊ฐ ์ํ์ ๋ฐ๋ผ ๊ฐ์ญํ ์ ์๊ณ , useEffect Hook์ ์ฌ์ฉํด์ ์ฝ๊ฒ ๊ฐ์ญํ ์ ์๋ค.
โ ๊ธฐ๋ณธ ์ฝ๋์์ ์ฐจ์ด์
import { useEffect } from "react";
const Detail = () => {
useEffect(() => {
console.log("Hello"); // 1๋ฒ
});
console.log("Hello"); // 2๋ฒ
return (
<div />
);
};
โผ useEffect๋ ์ ์ฉ๋ Component์ mount, update ์์ ์ ์คํ๋๋ค.
โผ 1๋ฒ ์ฝ๋๋, 2๋ฒ ์ฝ๋ ๋ ๋ค Detail Component์ mount, update ์์ ์ ์คํ๋๋ค. ๊ทธ๋ฌ๋ ์ด ๋์ ์ฐจ์ด๋ 1๋ฒ ์ฝ๋๋ Html ๋ ๋๋ง์ด ๋ค ๋ ์์ ์์ ์คํ๋๋ค.
โผ ๋ฐ๋ผ์, useEffect ์์ ์ ๋ ์ฝ๋๋ค์ ์ด๋ ค์ด ์ฐ์ฐ์ด๋ ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ์์ ๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฌ๋ ์์ ์ ์ฌ์ฉํ๋ค. Html ๋ณด์ฌ์ฃผ๋ ๊ฒ๋ณด๋ค ๋ ์ค์ํ ์์ ๋ค...
โ ์ฌ์ฉ๋ฒ
import { useEffect } from "react";
const Detail = () => {
const [showAlert, setShowAlert] = useState(true);
useEffect(() => {
console.log(1); // 1๋ฒ
setTimeout(() => {
setShowAlert(false);
}, 2000);
}, []);
useEffect(() => {
console.log(2); // 2๋ฒ
}, [showAlert]);
return (
{showAlert ? <div>2์ด ์ด๋ด ๊ตฌ๋งค์, ํ ์ธ!!!!</div> : null}
);
};
โผ useEffect({์ฝ๋ฐฑ ํจ์}, {์คํ ์กฐ๊ฑด})์ผ๋ก ์ฌ์ฉํ๋ค.
โผ ์คํ ์กฐ๊ฑด์ ์ถ๊ฐํ๋ฉด, Component๊ฐ mount ๋ ๋, ์คํ ์กฐ๊ฑด์ด update ๋ ๋, ์คํ๋๋ค.
โผ ์คํ ์กฐ๊ฑด์ ๋น Array๋ก ๋ฃ์ผ๋ฉด, Component๊ฐ mount ๋ ๋๋ง ์คํ๋๋ค.
โผ ์ฆ, 1๋ฒ ์ฝ๋๋ ํ ๋ฒ๋ง ์คํ๋๊ณ , 2๋ฒ ์ฝ๋๋ Component๊ฐ mount ๋ ๋์ showAlert ๊ฐ์ด ๋ณํ๋๋ฉด์ ์ด 2๋ฒ ์คํ๋๋ค.
import { useEffect } from "react";
const Detail = () => {
useEffect(() => {
setTimeout(() => {
setShowAlert(false);
}, 2000);
return () => {} // 1๋ฒ
}, []);
return (
<div />
);
};
โผ 1๋ฒ ์ฝ๋์ฒ๋ผ return () => {}์ ์ฌ์ฉํ์ฌ useEffect์ ๋ฑ๋กํ ์ฝ๋ฐฑ ํจ์๊ฐ ์คํ๋ ๋, ๊ฐ์ฅ ๋จผ์ ์คํ๋๋๋ก ์ค์ ํ ์ ์๋ค.
โผ ๋ํ, 1๋ฒ ์ฝ๋๋ mount ๋ ๋๋ ์คํ๋์ง ์๊ณ , unmount ๋ ๋ ์คํ๋๋ค.
๐ axios
โผ node ํ๊ฒฝ์์ Promise ๊ฐ์ฒด๋ฅผ ๋ฐํํด ์ฃผ๋ Http Client์ด๋ค.
โ ์ฌ์ฉ๋ฒ
import axios from "axios";
<button
onClick={() => {
axios
.get("https://codingapple1.github.io/shop/data2.json")
.then((res) => {
console.log(res.data);
})
.catch((err) => {
console.log(err);
});
}}
>
๋๋ณด๊ธฐ
</button>
โผ axios.get({uri}) ๋ฅผ ์ ๋ ฅํ์ฌ ์๋ก๊ณ ์นจ ์์ด, ์๋ฒ๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ Promise ๊ฐ์ฒด๋ก ๋ฐ์ ์ ์๋ค.
โผ then()์ ํตํด ์๋ต ๋ฐ์ดํฐ๋ฅผ, catch()๋ฅผ ํตํด ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ค.
axios.post("uri", {key: "value"})
.then()
.catch()
โผ ์์ ๊ฐ์ ํ์์ผ๋ก post ์์ฒญ์ ํ ์ ์๋ค.
Promise.all([axios.get("uri1"), axios.get("uri2")])
.then()
.catch()
โผ ์์ ๊ฐ์ ํ์์ผ๋ก uri1๊ณผ uri2์ ๋์์ ์์ฒญ์ ๋ณด๋ผ ์ ์๊ณ , ๋ชจ๋ ์์ฒญ์ ์๋ต์ด ์ค๊ฑฐ๋, ์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด then(), catch()์์ ์ฒ๋ฆฌํ๋ค.
โ async ํจ์
<button onClick={()=>{
setCount(count + 1);
if (count < 10) {
setLimitCount(limitCount + 1);
}
}}></button>
โผ ํด๋น ๋ฒํผ์ ๋๋ฅด๋ฉด, count๊ฐ ์ฆ๊ฐํ๊ณ count์ ๊ฐ์ด 10๋ณด๋ค ์์ ๋๋ง limitCount ๊ฐ์ด ์ฆ๊ฐํ๋๋ก ์ฝ๋๋ฅผ ์์ฑํ์ง๋ง ์ค์ ๋ก๋ limitCount ๊ฐ์ 10์ ๋์ ์ ์๋ค.
โผ state ๋ณ๊ฒฝ ํจ์๋ asyncํ๊ฒ ๋์๋๋ ํจ์์ด๊ธฐ ๋๋ฌธ์, ์ด๋ค ํจ์๊ฐ ๋จผ์ ์ฒ๋ฆฌ ์๋ฃ๋ ์ง ๋ชจ๋ฅธ๋ค.
โผ ๋ฐ๋ผ์, useEffect๋ฅผ ์ฌ์ฉํด์, count๋ฅผ ์คํ ์กฐ๊ฑด์ ๋ฃ์ด์ count๊ฐ ๋ณ๊ฒฝ๋๋ฉด useEffect์ ๋ฑ๋กํ ์ฝ๋ฐฑ ํจ์๊ฐ ๋์ํ๊ฒ ํ๋ ๋ฐฉ๋ฒ์ด ์๋ค.
โ async/await
let [limit, setLimit] = useState(1);
const add = async () => {
let data = 0;
await axios.get("url").then((res) => {
data = res.data;
});
if (data < 10) {
setLimit(0);
} else {
setLimit(100);
}
};
โผ axios ํจ์๋ async๋ก ๋์ํ๊ธฐ ๋๋ฌธ์, axios ํจ์์ ๊ฒฐ๊ณผ ๊ฐ์ ๋ฐํ์ผ๋ก ์ด๋ค ๊ฐ์ ๋ณ๊ฒฝํด์ผ ํ๊ฑฐ๋, ์์ ์ ์งํํด์ผ ํ ๋ async, await์ ์ฌ์ฉํด์ ์คํ์ ์์ฐจ์ ์ผ๋ก ์งํํ ์ ์๋ค.
๐ Automatic batching
โผ React 18 ๋ฒ์ ์ดํ์ ์ถ๊ฐ๋ ๊ธฐ๋ฅ์ผ๋ก, ํ๋์ ์ด๋ฒคํธ ์์ ๋ ๊ฐ์ state ๋ณ๊ฒฝ ์ฝ๋๊ฐ ์กด์ฌํ๋ฉด, state๋ฅผ ๋ค ๋ณ๊ฒฝ์ํจ ํ, ํ ๋ฒ ์ฌ๋ ๋๋ง์ ์์ผ์ค๋ค.
โผ ์ฌ๋ ๋๋ง์ state ๋ณ๊ฒฝ๋ง๋ค ์ฃผ๊ธฐ ์ํด์๋ state ๋ณ๊ฒฝ์ setTimeout ์์ ์ค์ ํด, ์ผ์ ์๊ฐ ๋ค์ ๋ณํํ๊ฒ๋ ํ๋ค.
๐ Redux Toolkit
โ Single Page Application ๋จ์
โผ Component ๊ฐ์ state ๊ณต์ ๊ฐ ์ด๋ ต๋ค.
โผ ๋ถ๋ชจ-์์ 1 Depth ๊ด๊ณ๋ฉด props๋ก ํด๊ฒฐํ ์ ์์ง๋ง, ๋ค๋ฅธ ๊ด๊ณ์ Component ๊ฐ ๋ฐ์ดํฐ ๊ณต์ ๋ ์ด๋ ต๋ค.
โผ Component ๊ฐ์ State ๊ณต์ ๋ฌธ์ ๋ React์ ๊ธฐ๋ณธ ๋ฌธ๋ฒ์ธ Context API ์ฌ์ฉ์ด๋ Redux ๋ฑ์ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํจ์ผ๋ก์จ ํด๊ฒฐํ ์ ์๋ค.
๐ฅ Context API๋ ์ ์ฌ์ฉํ์ง ์๋๋ค. (์ฑ๋ฅ ์ด์(์์ Component๋ ํด๋น State๋ฅผ ์ฌ์ฉํ์ง ์์๋ ์ฌ๋ ๋๋ง๋๋ค.), Component ์ฌํ์ฉ์ด ์ด๋ ต๊ธฐ ๋๋ฌธ)
โ Redux ์ฌ์ฉ ์ด์
โผ Redux๋ฅผ ์ฌ์ฉํ๋ฉด, ์ปดํฌ๋ํธ๋ค์ด props ์์ด state๋ฅผ ๊ณต์ ํ ์ ์๋ค.
๐ฌ Redux Store์ฉ ์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ๋ง๋ค์ด์ state๋ฅผ ๋ณด๊ดํ๊ณ , ๋ชจ๋ Component๋ค์ด ํด๋น js ํ์ผ์์ state๋ฅผ ๊ฐ์ ธ๋ค๊ฐ ์ธ ์ ์๋ค.
โ ์ค์
import { configureStore } from "@reduxjs/toolkit";
export default configureStore({
reducer: {},
});
โผ npm install @reduxjs/toolkit react-redux๋ก ์ค์นํ๋ค.
โผ src ์๋, store.js ํ์ผ์ ์์ฑํ ๋ค, ์ ์ฝ๋๋ฅผ ๋ถ์ฌ ๋ฃ๋๋ค.
import { Provider } from "react-redux";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<Provider store={store}>
<App />
</Provider>
);
โผ index.js ํ์ผ์์ <Provider> Component๋ฅผ root component๋ก ๋ง๋ค์ด ์ค๋ค.
โ ์ ์ฅํ๊ธฐ
import { configureStore, createSlice } from "@reduxjs/toolkit";
const {๋ณ์๋ช
} = createSlice({
name: "{state ๋ณ์๋ช
}",
initialState: "{state ๋ณ์๊ฐ}",
});
export default configureStore({
reducer: {
{๋ณ์๋ช
}: {๋ณ์๋ช
}.reducer,
},
});
โผ store.js ํ์ผ์์ ์ฝ๋๋ฅผ ์์ฑํ๋ค.
โผ createSlice๋ฅผ ์ฌ์ฉํด์ ์ฌ์ฉํ ์ ์ญ state๋ฅผ ์ ์ธํ๋ค. (useState๋ ๋น์ทํ ์ญํ )
โผ ๋ง๋ค์ด์ง state๋ฅผ reducer ์์ ์์ ๊ฐ์ ํ์์ผ๋ก ๋ณด๊ดํ๋ค.
โ ๊ฐ ๊ฐ์ ธ์ค๊ธฐ
const Test = () => {
const states = useSelector((state) => {
return state;
});
return (<div />);
}
โผ useSelector Hook์ ์ฌ์ฉํด์ Redux Store์ ์ ์ฅ๋ ๋ชจ๋ state ๊ฐ์ ๊ฐ์ ธ์ฌ ์ ์๋ค.
โผ useSelector((state) => { return state.{์ํ๋ state ๋ณ์๋ช }; } ์ผ๋ก ์ํ๋ ๊ฐ๋ง ๊ฐ์ ธ์ฌ ์ ์๋ค.
โผ states.{์ ์ฅ๋ state ๋ณ์๋ช }์ผ๋ก ์ํ๋ ๊ฐ์ ์ฐพ์์ ์ฌ์ฉํ ์ ์๋ค.
โ Store ๊ฐ ๋ณ๊ฒฝํ๊ธฐ
import { configureStore, createSlice } from "@reduxjs/toolkit";
const {๋ณ์๋ช
} = createSlice({
name: "{state ๋ณ์๋ช
}",
initialState: "{state ๋ณ์๊ฐ}",
reducers: {
changeName(state, data) { // state๋ ๊ธฐ์กด ๊ฐ์ ์๋ฏธํ๊ณ data๋ ์
๋ ฅ ๋ฐ์ ํ๋ผ๋ฏธํฐ๋ฅผ ์๋ฏธํ๋ค.
return state + data.payload;
}
}
});
export let { changeName } = {๋ณ์๋ช
}.actions;
export default configureStore({
reducer: {
{๋ณ์๋ช
}: {๋ณ์๋ช
}.reducer,
},
});
โผ reducers ์๋ state ์์ ํด์ฃผ๋ ํจ์๋ฅผ ๋ง๋ค๊ณ , ํด๋น ํจ์๋ฅผ ์ด์ฉํด์ ์์ ํ๋ค.
โผ ๋ฐ์ ํ๋ผ๋ฏธํฐ๋ .payload๋ก ์ ๊ทผํด์ ์ฌ์ฉํ๋ค.
โผ ๋ง๋ ํจ์๋ฅผ export ํด์ ์ฌ์ฉํด์ผ ํ๋ค.
import { useDispatch } from "react-redux";
import { addData } from "../store";
function App() {
const dispatch = useDispatch();
dispatch(addData());
return ( <div /> );
}
โผ useDispatch Hook์ ์ฌ์ฉํด์, store.js์ผ๋ก ์์ฒญ์ ๋ณด๋ด ๊ฐ์ ์์ ํ๋ค.
๐ฅ Redux ๋ฐ์ดํฐ๋ฅผ ์์ ํ๊ณ , ์๋ก๊ณ ์นจ์ ๋๋ฅด๊ฑฐ๋ Route ์ด๋์ด ์๋ href๋ก ํ์ด์ง๋ฅผ ์ด๋ํ๋ฉด ๋ฐ์ดํฐ๊ฐ ์ด๊ธฐ ๊ฐ์ผ๋ก ๋ค์ ๋์๊ฐ๋ค.
๐ฌ redux-persist ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฉด, Redux Store์ ์ ์ฅ๋์ด ์๋ ๋ชจ๋ State ๋ค์ localStorage์ ์๋์ผ๋ก ์ ์ฅํด์ ์๊ตฌํ ์ฌ์ฉํ ์ ์๋ค.
๐ useQuery
โผ ajax ์ฑ๊ณต/์คํจ ์ html ๋ณด์ฌ์ฃผ๊ธฐ, ๋ช ์ด๋ง๋ค ์๋์ผ๋ก ajax ์์ฒญํ๊ธฐ, ์คํจ ์ ๋ช์ด ํ ์์ฒญ ์ฌ์๋, prefetch ๋ฑ ๋ค์ํ ๊ธฐ๋ฅ์ ์ฝ๊ฒ ์์ฑํ ์ ์๋๋ก ๋์์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค.
โผ npm install react-query๋ก ์ค์นํ๋ค.
โ ์ค์ ํ๊ธฐ
import { QueryClient, QueryClientProvider } from "react-query";
const queryClient = new QueryClient();
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
);
โผ index.js ํ์ผ์์ QueryClient๋ฅผ ๋ง๋ ํ, QueryClientProvider Component๋ฅผ root component๋ก ์์ฑํ๋ค.
โ ์ฌ์ฉํ๊ธฐ
import { useQuery } from "react-query";
function App() {
const result = useQuery({queryKey}, () => {
return axios.get("{uri}").then((res) => {
return res.data;
});
});
console.log(result.data); // ์๋ต ๋ฐ์ดํฐ ์ถ๋ ฅ
console.log(result.isLoading); // ๋ก๋ฉ ์ค์ด๋ฉด true
console.log(result.error); // ์๋ฌ ๋ฐ์ดํฐ ์ถ๋ ฅ
return (
<div>
{ result.isLoading && <Loding />
{ result.data && <Page data={result.data.data}/> }
{ result.error && <ErrorPage data={error} />
</div>
);
}
โผ ajax ์์ฒญ์ด ์ฑ๊ณต์ธ์ง, ์คํจ์ธ์ง, ๋ก๋ฉ ์ค์ธ์ง ์ฝ๊ฒ ํ์ ํ ์ ์๋ค.
โผ ๋ก๋ฉ ํ์ด์ง, ์ฑ๊ณต ํ์ด์ง, ์คํจ ํ์ด์ง๋ฅผ ๊ตฌ๋ถํด์ ์ถ๋ ฅํ ๋, ์ ์ฉํ๋ค.
โผ useQuery ์์ ajax ์์ฒญ์ด ์ฑ๊ณตํ๋ฉด, ๊ณ์ refetchํ๋ค.
โผ useQuery ์์ ajax ์์ฒญ์ด ์คํจํ๋ฉด, ์์์ retryํ๋ค.
โผ ์บ์ฑ ๊ธฐ๋ฅ์ ์ ๊ณตํ๊ธฐ ๋๋ฌธ์, ์บ์ฑ๋ ์๋ต ๊ฒฐ๊ณผ๋ฅผ ์ฐ์ ๋ฐํํ๊ณ refetch ํ๋ค.
๐ PWA (Progressive Web Apps)
โผ ๋ชจ๋ฐ์ผ ์ฑ์ฒ๋ผ ์ค์นํด์ ์ฌ์ฉํ ์ ์๋ ์น ์ฌ์ดํธ
โผ ์ฑ ์คํ ์ด๋ฅผ ๊ฑฐ์น์ง ์๊ณ ๋ฐฉ๋ฌธ๋ง์ผ๋ก ์ค์นํ๊ฒ ์ ๋ํ ์ ์์ด, ์ค์น ๋น์ฉ์ด ์ ๋ค.
โผ html, css, js ๋ง์ผ๋ก ์ฑ์ผ๋ก ์ฌ์ฉํ๊ฒ ํ ์ ์๊ณ , ํธ์ ์๋ฆผ, ์ผ์ ๋ฑ์ ์ฌ์ฉํ ์ ์๋ค.
โ ์์ฑ ๋ฐฉ๋ฒ
โผ npx create-react-app {ํ๋ก์ ํธ๋ช } --template cra-template-pwa๋ก ํ๋ก์ ํธ๋ฅผ ์์ฑํ ์ ์๋ค.
โผ manifest.json ํ์ผ๊ณผ service-worker.js ํ์ผ์ด ์ค์ํ๋ค. ๋ ํ์ผ์ด ์กด์ฌํ๋ฉด, ์ฑ์ผ๋ก ๋ค์ด ๋ฐ์์ ์ฌ์ฉํ ์ ์๋ค.
โผ manifest.json ํ์ผ์ ๋ง๋ค์ด์ ธ ์์ผ๋ฉฐ, ์ฑ ์ ๋ณด๋ฅผ ๋ํ๋ด๊ณ ์ฑ ์ ๋ณด๋ฅผ ์ค์ ํ ์ ์๋ค.
โผ service-worker.js ํ์ผ์ index.js ํ์ผ์์ serviceWorkerRegistration.register()๋ก ๋ณ๊ฒฝํ๊ณ ๋น๋ํด์ผ ์์ฑ๋๋ค.
โผ service-worker.js ํ์ผ์ ์คํ๋ผ์ธ์์๋ ์ฌ์ดํธ๋ฅผ ์ด ์ ์๊ฒ ๋์์ค๋ค. ๊ตฌ๋์ ํ์ํ ๋ชจ๋ html, js ,css ํ์ผ์ ํ๋์ ์ ์ฅํด์ ์ฌ์ฉํ ์ ์๋๋ก ํ๋ค.
'Frontend > React.js' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
CSR๊ณผ SSR, SSG (0) | 2023.05.07 |
---|---|
React ์ฑ๋ฅ ๊ฐ์ ํ๊ธฐ (0) | 2023.05.01 |