[TIL] Day28 #SPA #React-Router

Beanxxยท2022๋…„ 6์›” 3์ผ
0

TIL

๋ชฉ๋ก ๋ณด๊ธฐ
28/120
post-thumbnail

[TIL] Day28
[SEB FE] Day28

โ˜‘๏ธย React SPA

์ „ํ†ต์ ์ธ ์›น์‚ฌ์ดํŠธ๋Š” ํŽ˜์ด์ง€ ์ด๋™ ์‹œ ๋งค๋ฒˆ HTML ํŒŒ์ผ๋กœ ๋œ โ€˜ํŽ˜์ด์ง€ ์ „์ฒด'๋ฅผ ๋ถˆ๋Ÿฌ์™€์•ผ๋งŒ ํ–ˆ์Œ โ†’ โ€˜๊นœ๋นก์ธ๋‹คโ€™
โ†’ ์‚ฌ์šฉ์ž/์„œ๋น„์Šค ์‚ฌ์ด์˜ ์ƒํ˜ธ์ž‘์šฉ ์ฆ๊ฐ€๋กœ ํŠธ๋ž˜ํ”ฝ ์ฆ๊ฐ€์™€ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ ์ €ํ•˜ ์•ผ๊ธฐ
โ†’ ์—…๋ฐ์ดํŠธ์— ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋งŒ ์„œ๋ฒ„์—์„œ ์ „๋‹ฌ๋ฐ›์•„ ์ด ๋ฐ์ดํ„ฐ๋ฅผ JS๊ฐ€ ๋™์ ์œผ๋กœ HTML ์š”์†Œ๋ฅผ ์ƒ์„ฑํ•ด์„œ ํ™”๋ฉด์— ๋ณด์—ฌ์ฃผ๋Š” ๋ฐฉ์‹์ด ๊ฐœ๋ฐœ๋˜์–ด ์‚ฌ์šฉ๋˜๊ธฐ ์‹œ์ž‘ โ‡’ SPA

โžฐย SPA(Single Page Application)
: ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์™„์ „ํ•œ ์ƒˆ๋กœ์šด ํŽ˜์ด์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ์•Š๊ณ  ํŽ˜์ด์ง€ ๊ฐฑ์‹ ์— ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋งŒ ๋ฐ›์•„ ๊ทธ ์ •๋ณด๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ˜„์žฌ ํŽ˜์ด์ง€๋ฅผ ์—…๋ฐ์ดํŠธํ•จ์œผ๋กœ์จ ์‚ฌ์šฉ์ž์™€ ์†Œํ†ตํ•˜๋Š” ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ / ์›น ์‚ฌ์ดํŠธ

โœ‹ย SPA๋Š” JavaScript์— ์˜์กด์ 
โœ‹SPA๋Š” ํ•˜๋‚˜์˜ ์›น ๋ฌธ์„œ๊ฐ€ ์•„๋‹ˆ๋ผ, ํ•˜๋‚˜์˜ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์Œ
โœ‹ย ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ฐ˜ ๊ฐœ๋ฐœ ๋ฐฉ๋ฒ• - ์–ด๋–ค ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค๊ณ  ์ด๋“ค์„ ์กฐํ•ฉํ• ์ง€๋ถ€ํ„ฐ ๊ตฌ์ƒ

๐Ÿ“Žย SPA ์žฅ์ 

  • ํ•„์š”ํ•œ ๋ถ€๋ถ„์˜ ๋ฐ์ดํ„ฐ๋งŒ ๋ฐ›์•„์„œ ํ™”๋ฉด์„ ์—…๋ฐ์ดํŠธํ•จ์œผ๋กœ ์‚ฌ์šฉ์ž์™€์˜ Interaction์— ๋น ๋ฅด๊ฒŒ ๋ฐ˜์‘
  • ์„œ๋ฒ„์—์„  ์š”์ฒญ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋งŒ ๋„˜๊ฒจ์ฃผ๋ฉด ๋˜๋ฏ€๋กœ ์„œ๋ฒ„ ๊ณผ๋ถ€ํ•˜ ๋ฌธ์ œ๊ฐ€ ํ˜„์ €ํ•˜๊ฒŒ ๊ฐ์†Œ
  • ์ „์ฒด ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•  ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋” ๋‚˜์€ ์œ ์ €๊ฒฝํ—˜ ์ œ๊ณต

๐Ÿ“Žย SPA ๋‹จ์ 

  • JS ํŒŒ์ผ ํฌ๊ธฐ๊ฐ€ ํผ โ†’ ์ฒซ ํ™”๋ฉด ๋กœ๋”ฉ ์‹œ๊ฐ„์ด ๊ธธ์–ด์ง
  • ๊ฒ€์ƒ‰ ์—”์ง„ ์ตœ์ ํ™”(SEO; ๊ฒ€์ƒ‰์—”์ง„์ด ์ž๋ฃŒ ์ˆ˜์ง‘ํ•˜๊ธฐ ์ข‹๋„๋ก ์›น ํŽ˜์ด์ง€๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ)๊ฐ€ ์ข‹์ง€ ์•Š์Œ
    • SPA๋Š” HTML์ด ๊ฑฐ์˜ ๋น„์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฒ€์ƒ‰ ๋กœ๋ด‡์ด ์ถฉ๋ถ„ํ•œ ์ž๋ฃŒ๋ฅผ ์ˆ˜์ง‘ํ•˜์ง€ ๋ชปํ•˜๊ธฐ ๋•Œ๋ฌธ

โžฐย Wireframe
: ์›นํŽ˜์ด์ง€์˜ ๋ ˆ์ด์•„์›ƒ๊ณผ UI ์š”์†Œ ๋“ฑ์— ๋Œ€ํ•œ ๋ผˆ๋Œ€

โžฐย Mockup
: ๋ฐ๋ชจ ์‹œ์—ฐ, ํ‰๊ฐ€๋ฅผ ์œ„ํ•œ ์ตœ์†Œํ•œ์˜ ๊ธฐ๋Šฅ๋งŒ ๋‹ด์€ ๋ชจํ˜•


โ˜‘๏ธย React Router

โžฐย Routing(๋ผ์šฐํŒ…)
: ๋‹ค๋ฅธ ์ฃผ์†Œ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ๋ทฐ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ณผ์ • โ‡’ โ€˜๊ฒฝ๋กœ์— ๋”ฐ๋ผ ๋ณ€๊ฒฝํ•œ๋‹คโ€™๋ผ๋Š” ์˜๋ฏธ

๐Ÿ“Žย React Router ์ฃผ์š” ์ปดํฌ๋„ŒํŠธ

  • BrowseRouter: ๋ผ์šฐํ„ฐ ์—ญํ• (router)
    • ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ๊ณ ์นจํ•˜์ง€ ์•Š๊ณ ๋„ ์ฃผ์†Œ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ
    • ์ƒ์œ„์— ์ž‘์„ฑ
  • Routes: ๊ฒฝ๋กœ ๋งค์นญ(route matchers)
    • ์—ฌ๋Ÿฌ <Route> ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ์‹ธ์„œ ๊ทธ ์ค‘ ๊ฒฝ๋กœ๊ฐ€ ์ผ์น˜ํ•˜๋Š” ํ•˜๋‚˜์˜ ๋ผ์šฐํ„ฐ๋งŒ ๋ Œ๋”๋ง
    • <Routes>๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ๋งค์นญ๋˜๋Š” ๋ชจ๋“  ์š”์†Œ ๋ Œ๋”๋ง
  • Route: ๊ฒฝ๋กœ ๋งค์นญ(route matchers)
    • path ์†์„ฑ์„ ์ง€์ •ํ•ด์„œ ํ•ด๋‹น path์—์„œ ์–ด๋–ค ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณด์—ฌ์ค„์ง€ ์ •ํ•จ
    • element ์†์„ฑ์œผ๋กœ ์—ฐ๊ฒฐํ•˜๊ณ ์ž ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ ์ง€์ •
    • <Link> ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ •ํ•ด์ฃผ๋Š” URL ๊ฒฝ๋กœ์™€ ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ์ž‘๋™
  • Link: ๊ฒฝ๋กœ ๋ณ€๊ฒฝ(route changers) โ‡’ ๊ฒฝ๋กœ ์—ฐ๊ฒฐ
    ๐Ÿคทโ€โ™€๏ธย Q: <a> ์š”์†Œ๊ฐ€ ์•„๋‹Œ <Link>๋ฅผ ๊ตณ์ด ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š”?
    ย ย ย ย  A: <a> ์š”์†Œ๋Š” ํŽ˜์ด์ง€ ์ „ํ™˜ ๊ณผ์ •์—์„œ ํŽ˜์ด์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ๋•Œ๋ฌธ์— ์ฒ˜์Œ๋ถ€ํ„ฐ ๋ Œ๋”๋ง์‹œํ‚ด โ‡’ ์ƒˆ๋กœ๊ณ ์นจ ํ˜„์ƒ
    ย ย ย ย ย ย ย ย ย ย But, <Link> ์ปดํฌ๋„ŒํŠธ๋Š” ํŽ˜์ด์ง€ ์ „ํ™˜ ๋ฐฉ์ง€ ๊ธฐ๋Šฅ์ด ๋‚ด์žฅ๋˜์–ด ์žˆ์–ด SPA ๊ตฌํ˜„ ๊ฐ€๋Šฅ

    โœ‹ย ์ง€์ •๋œ ์ฃผ์†Œ ์ด์™ธ์˜ ์ฃผ์†Œ๋กœ ์ ‘๊ทผํ•˜๊ฒŒ ๋˜๋ฉด ์˜๋„ํ•œ ํ™”๋ฉด์ด ๋ณด์ด์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Œ
    โ‡’ path=โ€*โ€ (๋ฏธ์ง€์ • ์ฃผ์†Œ ์ ‘๊ทผ์‹œ ์ด ์†์„ฑ์ด ์„ค์ •๋˜์–ด ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณด์—ฌ์คŒ)
// react-router ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ install
// @version์€ ์„ ํƒ์‚ฌํ•ญ
npm install react-router-dom@^6.3.0

// import๋Š” ํ•„์š”ํ•œ ๋ชจ๋“ˆ์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์—ญํ• 
// ๊ตฌ์กฐ ๋ถ„ํ•ด ํ• ๋‹น ๋ฌธ๋ฒ•๊ณผ ๋น„์Šทํ•˜๊ฒŒ ์ด์šฉ - {}
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
// App.js์—์„œ ๊ธฐ๋ณธ์ ์ธ react-router ์‚ฌ์šฉํ•  ๋•Œ
function App() {
	return(
		<BrowserRouter>
			<div>
				<nav>
					<ul>
						<li>
							<Link to="/">Home</Link>
						</li>
						<li>
							<Link to="/mypage">MyPage</Link>
						</li>
					</ul>
				</nav>

				<Routes>
					<Route path="/" element={<Home/>} />
					<Route path="/mypage" element={<MyPage/>} />
                </Routes>
			</div>
		</BrowserRouter>
	)
}

function Home() {
	return <h1>Home</h1>;
}

function MyPage() {
	return <h1>MyPage</h1>;
}

export default App;
// index.js์— <BrowserRouter>๋ฅผ ๋„ฃ์–ด์„œ ํ™œ์šฉ ๋˜ํ•œ ๊ฐ€๋Šฅ
// React Version 18

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>
);


โ˜‘๏ธย [Pair] React Twittler SPA

์–ด์ œ ์ง„ํ–‰ํ–ˆ๋˜ React Twittler Intro ์—์„œ ๊ธฐ๋Šฅ develop

// MyPage.js

const MyPage = () => {
	
	// username์ด 'kimcoding'์ธ ๋ฐ์ดํ„ฐ๋งŒ ๊ณจ๋ผ๋‚ด๊ธฐ -> filter ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ
  const filteredTweets = dummyTweets.filter(
    (el) => el.username === "kimcoding"
  );

  return (
    <section className="myInfo">
      <ul className="tweets__mypage">
		{/* kimcoding์ธ ๋ฐ์ดํ„ฐ๊ฐ€ ํ•˜๋‚˜๊ฐ€ ์•„๋‹ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— 
            map์œผ๋กœ kimcoding์— ํ•ด๋‹นํ•˜๋Š” ๋ฐ์ดํ„ฐ ๋ชจ์กฐ๋ฆฌ ๊ฐ€์ ธ์™€์„œ ๋ณด์—ฌ์ฃผ๊ธฐ */}
        {filteredTweets.map((tweet) => {
          return (
            <li className="tweet" id={tweet.id}>
              <div className="tweet__profile">
                <img src={tweet.picture} />
              </div>
              <div className="tweet__content">
                <div className="tweet__userInfo">
                  <span className="tweet__username">{tweet.username}</span>
                </div>
                <div className="tweet__message">{tweet.content}</div>
              </div>
            </li>
          );
        })}
      </ul>
      <Footer />
    </section>
  );
};

export default MyPage;

โžฐย useNavigate()
: ํŠน์ • ํ–‰๋™์„ ํ–ˆ์„ ๋•Œ ํ•ด๋‹น ์ฃผ์†Œ๋กœ ์ด๋™์‹œ์ผœ์ฃผ๋Š” ์—ญํ• 
โœ‹ย useNavigate๋Š” Link์™€ ๋‹ฌ๋ฆฌ ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ํ†ตํ•ด ํŠน์ • ์กฐ๊ฑด์— ๋”ฐ๋ผ ํŽ˜์ด์ง€ ์ด๋™ ๊ฐ€๋Šฅ

import React from "react";
import { useNavigate } from "react-router-dom";

function Goback() {
  const navigate = useNavigate();

  return (
		<div>
	    <button onClick={() => {navigate(-1)}}>
	      <i className="far fa fa-arrow-left"></i>
	    </button>
	    <button onClick={() => {navigate(1)}}>
	      <i className="far fa fa-arrow-right"></i>
	    </button>
		</div>
  );
}

export default Goback;

๐Ÿซ  ๊ฐœ๋… ์ •๋ฆฌ๋ฅผ ๋”ฐ๋กœ ์•ˆ ํ•ด๋‘” ์ƒํƒœ์—์„œ ๊ฑฐ์˜ 1๋…„๋งŒ์— React ๊ธฐ์ดˆ๋ถ€ํ„ฐ ๋‹ค์‹œ ํ•˜๋ ค๋‹ˆ๊นŒ ๊ธฐ์–ต์ด ๊ฐ€๋ฌผ๊ฐ€๋ฌผ ๊ฑฐ์˜ ๋ฐฑ์ง€ ์ƒํƒœ๋‹ค,, JS๋ฅผ ์–ด๋Š์ •๋„ ๊นŠ์ด ๊ณต๋ถ€ํ•œ ๋‹ค์Œ์— React๋ฅผ ๊ณต๋ถ€ํ–ˆ์—ˆ์–ด์•ผ ํ–ˆ๋Š”๋ฐ JS ๊ฐœ๋…๋„ ์ž˜ ๋ชจ๋ฅด๋ฉด์„œ React๋ฅผ ๊ณต๋ถ€ํ•˜๋ ค๊ณ  ํ–ˆ์œผ๋‹ˆ ์ฝ”๋“œ๋„ ์ฃผ๋จน๊ตฌ์‹์œผ๋กœ ๋”ฐ๋ผ ์“ฐ๊ธฐ๋งŒ ํ–ˆ์—ˆ๋˜ ๊ฒƒ ๊ฐ™๋‹ค. ์ด๋ž˜์„œ vanilla js๊ฐ€ ์™œ ์ค‘์š”ํ•œ์ง€ ๋ผˆ์ €๋ฆฌ๊ฒŒ ๋Š๋‚„ ์ˆ˜ ์žˆ์—ˆ๋˜..
๐Ÿ’ช ์ด๋ฒˆ ์ฃผ๋ง์—” ๊ผญ๊ผญ๊ผญ ์•Œ๋ฐ” ๊ฐ”๋‹ค์˜ค๊ณ  ๋‚˜์„œ ์ €๋… ์‹œ๊ฐ„์— ๊ณ„์† ๋ฏธ๋ฃจ๊ณ  ๋ฏธ๋ค˜๋˜ TIL ๋ชจ์กฐ๋ฆฌ ๋ณต์Šตํ•˜๊ณ  ์ฝ”ํ”Œ๋ฆฟ ๋ฌธ์ œ๋„ ๋‹ค์‹œ ํ’€์–ด๋ณด๊ธฐ!!

profile
FE developer

0๊ฐœ์˜ ๋Œ“๊ธ€