혹시나 잘못된 개념 전달이 있다면 댓글 부탁드립니다. 저의 성장의 도움이 됩니다
Single Page Application
페이지 전체를 새로 로딩하는 기존 방식과는 달리, 한 페이지 내에서 변화가 필요한 일부분의 데이터만 받아와서 렌더링하는 방식
-> 서버로부터 업데이트가 필요한 영역의 JSON 형식 데이터를 받아서 Javascript를 통해 html 요소를 생성/추가하여 리로드
-> 한 페이지에서 화면 변화
cf. MPA(Multi Page Application)
: 페이지 전체를 새로 받아서 렌더링 하는 방식
-> 잦은 트래픽과 속도 저하로 인한 사용자 경험 저하
SPA 장점
SPA 단점
첫 화면 로딩 시간이 김
: html파일은 거의 비어있고 Javascript파일 크기가 커서 처음 받아와야하는 용량이 큼
검색 엔진에 최적화 낮음
: html 파일 위주로 검색 엔진이 반응하기 때문에 html 대신 Javascript로 정보를 표현하는 SPA는 상대적으로 불리
cf. 최근에는 검색 엔진이 SPA에도 대응할 수 있도록 개발되고 있으나 검색 노출이 중요한 서비스의 경우 검색 엔진 최적화에 대한 대응책을 따로 대비해야함
cf. SPA 방식 사이트 : 페이스북, gmail, 에어비엔비, 넷플릭스
디자인 작업 전 페이지의 레이아웃과 UI 요소에 대한 윤곽선 / 틀을 잡는 것
-> 디자인 컨셉, 사이트 기능 파악
Mockup
최소한의 기능만을 구현해 놓은 모형(데모 시연, 평가용)
컴포넌트 기반 개발은 어떤 기능(component)을 만들고 조합할지부터 구상해야함
-> 와이어 프레임으로 구상
독립적이지만 어플리케이션 내에서 데이터를 유기적으로 주고받을 수 있게 설계해야함
SPA 방식의 어플리케이션에서 경로에 따라 다른 화면을 보여주는 라이브러리
-> React 설치된 환경에서 사용할 수 있는 라우팅 라이브러리
<BrowserRouter />
: 라우터 역할<Routes/>
, <Route/>
: 경로를 매칭<Link/>
: 바뀐 경로를 연결<Routes />
와 <Routes></Routes>
혼용React Router 설치하기
터미널에서 create-react-app
로 프로젝트 파일을 설치하고 해당 파일 내부로 이동을 한 후 npm 명령어로 설치 진행
npx create-react-app simpleroute
cd simpleroute
npm install react-router-dom@^<버전>
React Router 불러오기
파일 상단에 import 명령 추가
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom'
// 4가지중 필요한 것만 { } 안에 넣어불러오기
cf. 구조분해할당 destructuring assignment syntax을 활용한 표현
React Router 적용하기
페이지를 표시하는 컴포넌트 선언 후 App 컴포넌트에 적용할 선언한 컴포넌트와 <Route />
컴포넌트를 형식에 맞게 추가
<BrowserRouter />
컴포넌트
: 현재 위치를 저장하고 브라우저의 내장 history API를 사용하여 새로고침 없이 페이지 이동(주소 변경)을 가능하게 하는 컴포넌트
React Router DOM이 사용되는 부분의 상위 컴포넌트로 위치
-> 다른 라우터 컴포넌트들보다 상위에 위치(모든 태그의 최상위 X)
<Routes />
컴포넌트
: <Route />
의 부모 컴포넌트로 경로가 일치하는 컴포넌트를 렌더링
cf. 파일에 <Routes />
를 사용하지 않은 경우에는 모든 <Route />
를 표시
<Route />
컴포넌트
: 조건문처럼 경로가 path 속성값과 일치하는 경우 element 속성값을 렌더링
<Route path="URL경로" element={렌더링하는컴포넌트} />
{/* path의 속성값을 "*"로 지정하면 지정하지 않은 URL로 접근하면 이어진 element 속성값 컴포넌트로 렌더링*/}
<Link/>
컴포넌트
: <a>
태그처럼 클릭하면 지정된 경로로 이동
-> 페이지 전환 없이 컴포넌트 렌더링
cf. <a>
태그는 이동 후 페이지 전체를 받아와 새로고침되는데 이를 방지하기 위함
-> 컴포넌트 상태 유지
<Link to="URL경로">노출되는 텍스트</Link>
<BrowserRouter>
<div className="App">
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/abut">Mypage</Link>
</li>
<li>
<Link to="/dashboard">Dashboard</Link>
</li>
</ul>
</nav>
<Routes>
<Route path="/" element={<Tweets />}></Route>
<Route path="/about" element={<About />}></Route>
<Route path="/mypage" element={<MyPage />}></Route>
</Routes>
</div>
</BrowserRouter>
/*---- 공식문서 권장 방식 ----*/
// index.js 파일에서 <App /> 의 부모 태그로 <BrowserRouter /> 적용
import * as React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App.js";
const root = ReactDOM.createRoot(
document.getElementById("root")
);
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
cf. useNavigate()를 사용할 경우 컴포넌트 내부에서 const navigate = useNavigate();
로 선언하는데 이때, return값의 상단에 <BrowserRouter />
가 있어도 영향을 받음
-> 권장 방식처럼 index.js 파일에서 <App />
를 감싸는 것 권장
<BrowserRouter />
컴포넌트는 다른 React Router Dome 컴포넌트보다 상위에만 있으면 됨
-> 최상위를 의미하는 것은 아님
const App = () => {
return (
<div>
<BrowserRouter>
<div className="App">
<main>
<Sidebar />
<section className="features">
<Routes>
<Route path="/" element={<Tweets />}></Route>
<Route path="/about" element={<About />}></Route>
<Route path="/mypage" element={<MyPage />}></Route>
</Routes>
</section>
</main>
</div>
</BrowserRouter>
</div>
);
};
<Routes />
가 없는경우 오류 발생
<Link />
를 사용할 때 새로고침 없이, 현재 상태를 유지하면서 새로운 화면 렌더링
JSX 방식으로 데이터의 모든 요소를 렌더링 할 때는 { }
내부에서 map()
를 사용
-> key
속성 필수!!
// filter 메소드를 이용하여 username이 kimcoding인 요소만 추출
// 필터링한 값의 0번째 user의 글만 노출
const MyPage = () => {
const filteredTweets = dummyTweets.filter((post)=>{
return post["username"] === "kimcoding";
});
return (
<section className="myInfo">
<div className="myInfo__container">
<div className="myInfo__wrapper">
<div className="myInfo__profile">
<img src={filteredTweets[0].picture} />
</div>
<div className="myInfo__detail">
<p className="myInfo__detailName">
{filteredTweets[0].username} Profile
</p>
<p>28 팔로워 100 팔로잉</p>
</div>
</div>
</div>
{/* ---- 해당 유저의 게시글 모음 ---- */}
<ul className="tweets__mypage">
{filteredTweets.map((tweet)=>{
return <li className="tweet" id={tweet.id} key={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>
<span className="tweet__createdAt">{tweet.createdAt}</span>
</div>
<div className="tweet__message">{tweet.content}</div>
</div>
</li>
})}
</ul>
<Footer />
</section>
);
};
useNavigate()
로 뒤로가기 기능 구현
: onClick 속성에 콜백함수로 적용
-> 전달인자에 따라 1회 뒤로가기(-1 전달), 2회 뒤로가기 (-2 전달), 앞으로 가기 (1 전달) 등 가능
import { useNavigate } from 'react-router-dom';
const Sidebar = () => {
const navigete = useNavigate();
return (
<section className="sidebar">
/*---- 뒤로가기 아이콘 ----*/
<div onClick={()=>{navigete(-1)}}>
<i className="fas fa-arrow-left"></i>
</div>
<Link to="/">
<i className="far fa-comment-dots"></i>
</Link>
<Link to="/about">
<i className="far fa-question-circle"></i>
</Link>
<Link to="/mypage">
<i className="far fa-user"></i>
</Link>
</section>
);
};
```
./
는 현재 위치, ../
는 상위 디렉토리 위치
-> 터미널에서 cd
이동 명령어를 사용할 때의 경로로 적용
import Sidebar from './Sidebar';
import Tweets from './Pages/Tweets';
import MyPage from './Pages/MyPage';
import About from './Pages/About';
useNavigate()
이벤트가 발생했을 때, URL 경로를 변경
: 보통 뒤로가기 기능보다 로그인 했을 때 Mypage에 들어갈 수 있고, 아닌 경우 로그인 페이지로 접근하는 경우처럼 직접적으로 어떤 경로로 변경하게 사용하는 경우가 많음
import { useNavigate } from 'react-router-dom';
function MypageForm(){
let navigate = useNavigate();
function handleClick(){
if(/* 로그인한 경우 */){
navigate('/mypage');
} else {
navigate('/login');
}
}
return <button onclick= {handleClick}> Mypage </button>;
&&
연산자로 조건문 적용 가능{ 조건 && 실행부 }
// falsy 표현식을 반환하는 경우도 있음 -> 공식문서 참고
공식문서 조건부 렌더링Chapter1. React SPA
Chapter2. React Router
이해도 자가 점검 리스트의 결과를 토대로 자기주도적 학습 계획을 수립하고 실천해 보세요.
오늘 학습이 어려웠다면 (0~3개)
오늘 학습이 수월했다면 (4~5개)
추가적인 학습을 하고 싶다면 (6개)
느낀점
CSS 정말... 막막하다 기술적인 문제도 그렇지만 디자인 소스 없이 작업하는게 시간이 참 오래 걸리는 것 같다. 어떻게 표현해야 좋을지 생각나는게 없어서 더 오래 걸리는 것 같다. 그렇다고 서치하다가 이것저것 시도해보면 결국 조잡해보여서 되돌리다보면 처음과 별반 다르지 않은 것 같다. 자바스크립트는 어떻게 해야겠다는 흐름이 대충 보이는데 CSS는 흩뿌려져있는 데서 바늘 찾는 느낌이랄까...
오늘 과제는 수월하긴 했다. 하지만 JSX 문법이 익숙치 않은 데다가 map()사용할 때 키를 누락하는 경우, 소소하게는 {}
안에서 작성해야하나 하는 정말 작은 부분까지 조금 버퍼링이 걸리는 것 같다. 오늘 세션에 이런저런 질문을 하다가 들었는데 명확하게 구분짖기 보다 많이 써보고 오류나면 그때 대응하라고 하셨다. 집요하게 파는것도 좋긴 하겠지만 상황에 따라 달리 적용해야지.
그리고 잊지 말아야 할 것. map()
콜백함수에 key
속성 추가하기! 그리고 BrowserRouter
컴포넌트는 Routes
등의 상단으로 useNavigate()
도 같은 페이지에서 사용한다면 자식컴포넌트로 사용. 그리고 보통 index.js에서 <App />
을 감싸서 사용하는것 기억하기
개선점 및 리마인드
익숙하게 사용하다가 깊게 들어가는 것도 한 방법