React Part2

남재상·2025년 2월 4일
post-thumbnail

React to CodingApple

코딩애플 강의를 통해 배운 리액트를 정리한 글입니다.

📅 작성일

2025년 2월 04일


📌 목차

  • 소개
  • part2-1 : 새로운 프로젝트 생성 & Bootstrap 사용하기
  • part2-2 : 이미지 넣는 법 & public 폴더 이용하기
  • part2-3 : 코드 길어지면 import export 하면 됩니다
  • part2-4 : 저번시간 숙제 해설 (Card 컴포넌트 만들기)
  • part2-5 : 리액트 라우터 1 : 셋팅이랑 기본 라우팅
  • part2-6 : 리액트 라우터 2 : navigate, nested routes, outlet
  • part2-7 : 리액트 라우터 3 : URL 파라미터로 상세페이지 100개 만들기
  • part2-8 : styled-components 쓰면 CSS 파일 없어도 되는데
  • part2-9 : Lifecycle과 useEffect 1
  • part2-10 : Lifecycle과 useEffect 2
  • part2-11 : 리액트에서 서버와 통신하려면 ajax 1
  • part2-12 : 리액트에서 서버와 통신하려면 ajax 2 : post, fetch
  • part2-13 : 리액트에서 탭 UI 만들기
  • part2-14 : 멋있게 컴포넌트 전환 애니메이션 주는 법 (transition)
  • part2-15 : props 싫으면 Context API 써도 됩니다
  • part2-16 : 장바구니 페이지 만들기 & Redux 1 : Redux Toolkit 설치
  • part2-17 : Redux 2 : store에 state 보관하고 쓰는 법
  • part2-18 : Redux 3 : store의 state 변경하는 법
  • part2-19 : state가 object/array일 경우 변경하는 법
  • part2-20 : Redux 5 : 장바구니 기능 만들기 숙제 & 응용문제
  • part2-21 : 리액트에서 자주 쓰는 if문 작성 패턴 5개
  • part2-22 : localStorage로 만드는 최근 본 상품 기능 1
  • part2-23 : localStorage로 만드는 최근 본 상품 기능 2
  • part2-23 : localStorage로 만드는 최근 본 상품 기능 2
  • part2-24 : 실시간 데이터가 중요하면 react-query
  • part2-25 : 성능개선 1 : 개발자도구 & lazy import
  • part2-26 : 성능개선 2 : 재렌더링 막는 memo, useMemo
  • part2-27 : 성능개선 3 : useTransition, useDeferredValue
  • part2-28 : PWA 셋팅해서 앱으로 발행하기 (모바일앱인척하기)
  • part2-29 : state 변경함수 사용할 때 주의점 : async
  • part2-30 : custom hook으로 코드 재사용하기
  • part2-31 : Node+Express 서버와 React 연동하려면
  • part2-32 : React 강의 나가는 말
  • 참고 자료

📝 소개

Part 2 : 쇼핑몰 프로젝트


🚀 part2-1 새로운 프로젝트 생성 & Bootstrap 사용하기

🔹 1. 리액트 부트스트랩 설치

  • 레이아웃을 복사 붙여넣기 식으로 편하게 개발가능한 라이브러리
  • className을 통해 커스터마이징 가능
// React Bootstrap 설치
npm install react-bootstrap bootstrap


// 글로벌 스타일 적용 (index.html)
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css"
  integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN"
  crossorigin="anonymous"
/>
or
// 각 파일에서 Bootstrap 스타일 적용
import 'bootstrap/dist/css/bootstrap.min.css';


// 예제: 버튼 적용
import { Button } from "react-bootstrap";

<Button>버튼</Button>

🖼️ part2-2 이미지 넣는 법 & public 폴더 이용하기

🔹 1. 이미지 적용 방법

  • 다양한 방식으로 이미지를 적용할 수 있음
// jsx상에서 이미지 적용
import 이미지 from "/경로";
<div style={{background : 'url(' + import로가져온이미지 + ')'}}></div>
<div style={{ background: `url(${이미지})` }}></div>


// css상에서 이미지 적용
background-image: url("/경로");

🔹 2. public 이미지

  • 나중에 빌드할 떄 서브경로를 통해서 발행할 때 안먹을 수 있음
//public상에서 이미지 가져오기
<img src="/이미지경로"/>

//해결법
<img src={process.env.PUBLIC_URL + "/이미지명"} />

📦 part2-3 코드 길어지면 import export 하면 됩니다

🔹 1. 다른 파일의 정보를 사용하는법

//data.js
export default data;
export { data1, data2, data3 };

//App.jsx
import data from "/경로";
import { data1, data2, data3 } from "/경로";

💳 part2-4 저번시간 숙제 해설 (Card 컴포넌트 만들기)

🔹 1. 숙제하면서 깨달은점

  • 컴포넌트를 많이 만들면 골치아플거같다
  • 타입 개귀찮다

🚦 part2-5 리액트 라우터 1 : 셋팅이랑 기본 라우팅

🔹 1. 라우터 설치 및 적용

// router설치
npm install react-router-dom@6


//main.jsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import App from "./App.jsx";
import { BrowserRouter } from "react-router-dom";

createRoot(document.getElementById("root")).render(
  <StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </StrictMode>
);


//App.jsx
import { Routes, Route, Link } from "react-router-dom";
<Routes>
    <Route path="/detail" element={<div>상세페이지임</div>} />
    <Route path="/about" element={<div>어바웃페이지임</div>} />
</Routes>
<Link to="/"></Link>

🗺️ part2-6 리액트 라우터 2 : navigate, nested routes, outlet

🔹 1. useNavigate

React Router에서 페이지 이동을 도와주는 훅(Hook)입니다.

✅ 기본 사용법

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

const MyComponent = () => {
  let navigate = useNavigate();

  return <button onClick={() => navigate("/경로")}>이동</button>;
};

✅ 뒤로 가기 / 앞으로 가기

navigate(1); // 앞으로 한 페이지 이동
navigate(-1); // 뒤로 한 페이지 이동

🔹 2. 404 페이지 설정

존재하지 않는 경로에 대한 처리를 위해 *을 사용합니다.

<Route path="*" element={<div>404 - 페이지를 찾을 수 없습니다.</div>} />

📌 *은 모든 경로를 의미하며, 기존에 정의된 경로와 일치하지 않을 경우 해당 컴포넌트가 렌더링된다.

🔹 3. 중첩 라우트 (Nested Routes)

  • 라우트 안에 또 다른 라우트를 정의할 수 있으며, Outlet을 사용하면 부모 컴포넌트 안에서 자식 컴포넌트가 렌더링된다.
  • 여러 유사한 페이지 필요할 때 사용

✅ 기본 사용법

import { Routes, Route, Outlet } from "react-router-dom";

const About = () => {
  return (
    <div>
      <h2>About 페이지</h2>
      <Outlet />
    </div>
  );
};

const App = () => {
  return (
    <Routes>
      <Route path="/about" element={<About />}>
        <Route path="member" element={<div>멤버 페이지</div>} />
      </Route>
    </Routes>
  );
};

✅ 동작 방식

  • /about으로 이동하면 About 페이지만 보입니다.
  • /about/member로 이동하면 About 페이지 + 멤버 페이지가 함께 렌더링됩니다.
  • Outlet이 있는 위치에 중첩된 컴포넌트가 표시됩니다.

🔍 part2-7 리액트 라우터 3 : URL 파라미터로 상세페이지 100개 만들기

🔹 1. 상세페이지 만들기

  • URL 파라미터를 사용하면 여러 개의 상세 페이지를 동적으로 생성가능

✅ URL 구조

/detail/123

✅ 라우트 설정

<Route path="/detail/:id" element={<Detail />} />

✅ useParams()사용

import { useParams } from "react-router-dom";

const Detail = () => {
  let { id } = useParams(); // 현재 URL의 파라미터 값 가져오기

  return <div>현재 상품 ID: {id}</div>;
};

💅 part2-8 styled-components 쓰면 CSS 파일 없어도 되는데

🔹 1. styled-components

✅ 설치 및 사용

//설치
npm install styled-components

//임포트
import styled from 'styled-components'

//적용예시
let Button = styled.button `
  background : yellow `
<Button></Button>

//적용예시2
let Button = styled.button `
  background : ${props => props.bg} `
<Button bg="blue"></Button>

🔹 2. css파일이 전염

  • 컴포넌트.module.css 파일 만들면 전염안됨

⏳ part2-9 Lifecycle과 useEffect 1

🔹 1. 컴포넌트 LifeCycle

  • mount(생성)
  • update(재렌더링)
  • unmount(삭제)

🔹 2. useEffect

  • mount, update시 코드를 실행해준다
  • 실행 시 2번 호출은 디버깅을 위해서이고, 실제 배포하면 1번만 실행된다
  • React.StrictMode를 없애면 2번 호출 안됨
useEffect(() => {
  코드;
});

🔹 3. useEffect 사용이유

  • 실행시점은 html렌더링 후에 동작을 한다

🔹 4. 사용시기

  • 어려운 연산 or 오래걸리는 연산
  • 서버에서 데이터를 가져올 때
  • 타이머 장착했을 때

⚙️ part2-10 Lifecycle과 useEffect 2

🔹 1. useEffect 동작

  • 기본적으로 mount update에 실행이 됨
//특정값이 변경됬을 때만 실행이 되게 하려면
useEffect(() => {}, [특정값]);

//처음 mount됬을 때만 1회실행됨
useEffect(() => {}, []);

//useEffect가 실행되기전에 코드를 실행
useEffect(() => {
  return () => {
    코드;
  };
}, []);
// 이런건 대부분 기존 데이터를 전부 깔끔하게 지우고 새로시작할 때 사용한다
// 타이머같은 경우에는 변수에 타이머를 저장한 후 return 에 clearTimeout(변수)
// 이렇게 작성해도된다

🌐 part2-11 리액트에서 서버와 통신하려면 ajax 1

🔹 1. ajax

  • 새로고침 없이도 서버요청 가능
//특정값이 변경됬을 때만 실행이 되게 하려면
npm install axios

//import
import axios from "axios";

//실행
axios.get('url쓰기').then((결과)=>{
  console.log(결과.data)
})

📬 part2-12 리액트에서 서버와 통신하려면 ajax 2 : post, fetch

🔹 1. post

  • 서버로 데이터 전송하는요청

🔹 1. 여러ajax를 요청하는 방법

  • 서버로 데이터 전송하는요청
Promise.all([a, b]).then(() => {});

🏷️ part2-13 리액트에서 탭 UI 만들기

🔹 1. 조건식으로 화면에 show hide하는방법

// 삼항 연산자
{tab == 0 : <div>내용0</div>; ? null}

// if문
<TabContent tab={tab}></TabContent>
function TabContent({tab}) {
  if (tab === 0) {
    return <div>내용0</div>;
  }
}

// array
<TabContent tab={tab}></TabContent>
function TabContent({tab}) {
    return [ <div>내용0</div>, <div>내용1</div>, <div>내용2</div> ][tab]
}

🎭 part2-14 멋있게 컴포넌트 전환 애니메이션 주는 법 (transition)

🔹 1. automatic batching 기능

  • state 변경함수들이 연달아서 여러개 처리되어야한다면 state 변경함수를 다 처리하고 마지막에 한 번만 재렌더링된다

🔄 part2-15 props 싫으면 Context API 써도 됩니다

🔹 1. Context API

  • props 전송없이 state공유가능

🔹 2. Context API 잘 안쓰는 이유

  • state 변경시 쓸데없는 컴포넌트까지 전부 재렌더링이 된다
  • useContext() 를 쓰고 있는 컴포넌트는 나중에 다른 파일에서 재사용할 때 Context를 import 하는게 귀찮아질 수 있습니다.

🛒 part2-16 장바구니 페이지 만들기 & Redux 1 : Redux Toolkit 설치

🔹 1. Redux

  • 컴포넌트들이 props없이 state 공유가능

🔹 2. 사용

  • react버전이 18.1.0 이상인지 확인

설치

npm install @reduxjs/toolkit react-redux

store.js

import { configureStore } from "@reduxjs/toolkit";

export default configureStore({
  reducer: {},
});

main.jsx

import { Provider } from "react-redux";
import store from "./store.js";

<Provider store={store}>
  <BrowserRouter>
    <App />
  </BrowserRouter>
</Provider>;

📦 part2-17 Redux 2 : store에 state 보관하고 쓰는 법

🔹 1. store.js

//store.js
import { configureStore, createSlice } from "@reduxjs/toolkit";

let user = createSlice({
  name: "user",
  initialState: "kim",
});

export default configureStore({
  reducer: {
    user: user.reducer,
  },
});
// name : 'state이름', initialState : 'state값'
// { 작명 : createSlice만든거.reducer }

🔹 2. 사용하기

import { useSelector } from "react-redux";
let a = useSelector((state) => {
  return state;
});
---

## 📬 part2-13 리액트에서 탭 UI 만들기

### 🔹 1. 조건식으로 화면에 show hide하는방법

```jsx
// 삼항 연산자
{tab == 0 : <div>내용0</div>; ? null}

// if문
<TabContent tab={tab}></TabContent>
function TabContent({tab}) {
  if (tab === 0) {
    return <div>내용0</div>;
  }
}

// array
<TabContent tab={tab}></TabContent>
function TabContent({tab}) {
    return [ <div>내용0</div>, <div>내용1</div>, <div>내용2</div> ][tab]
}

🔧 part2-18 Redux 3 : store의 state 변경하는 법

🔹 1. store의 state변경

  • state변경 코드를 store.js파일 하나에서 보기 위해 사용

state수정 함수 생성

//store.js
let user = createSlice({
  name: "user",
  initialState: "kim",
  reducers: {
    changeName(state) {
      return "john" + state;
    },
  },
});
export let { changeName } = user.actions;

state수정 함수 호출

//Detail.jsx
import { changeName } from "../store";

funtion Detail() {
  let dispatch = useDispatch();
  return(
    <button
      onClick={() => {
        dispatch(changeName());
      }}
    ></button>
  )
}

📑 part2-19 state가 object/array일 경우 변경하는 법

🔹 1. redux 파라미터

  • state변경할 때 파라미터를 보내 수정할 수 있다
increase(state, action) {
      state.age += action.payload;
    },

🔹 2. store slice파일 따로보관

  • 사용 할 store가 많으면 각 slice파일들을 따로 만드는게 좋음
//stockSlice.js;
import { createSlice } from "@reduxjs/toolkit";
let stock = createSlice({
  name: "stock",
  initialState: [10, 11, 12],
});
export default stock;

//store.js;
import { configureStore} from "@reduxjs/toolkit";
import stock from '../stockSlice'
export default configureStore({
  reducer: {
    stock: stock.reducer,
  },
});

🚀 part2-20 Redux 5 : 장바구니 기능 만들기 숙제 & 응용문제

🔹 1. 숙제하기


⚡ part2-21 리액트에서 자주쓰는 if문 작성패턴 5개

🔹 1. 컴포넌트 안에서 쓰는 if/else

function Component() {
  if (true) {
    return <p>참이면 보여줄 HTML</p>;
  } else {
    return null;
  }
}

🔹 2. JSX안에서 쓰는 삼항연산자

function Component() {
  return <div>{1 === 1 ? <p>참이면 보여줄 HTML</p> : null}</div>;
}

🔹 3. && 연산자로 if 역할 대신하기

function Component() {
  return <div>{1 === 1 && <p>참이면 보여줄 HTML</p>}</div>;
}

🔹 4. switch / case 조건문

function Component2() {
  var user = "seller";
  switch (user) {
    case "seller":
      return <h4>판매자 로그인</h4>;
    case "customer":
      return <h4>구매자 로그인</h4>;
    default:
      return <h4>그냥 로그인</h4>;
  }
}

🔹 5. object/array 자료형 응용

function Component() {
  var 현재상태 = "info";
  return (
    <div>
      {
        {
          info: <p>상품정보</p>,
          shipping: <p>배송관련</p>,
          refund: <p>환불약관</p>,
        }[현재상태]
      }
    </div>
  );
}

💾 part2-22 localStorage로 만드는 최근 본 상품 기능 1

🔹 1. localStorage

-사이트를 꺼도 계속해서 남아있음

localStorage.setItem("데이터이름", "데이터");
localStorage.getItem("데이터이름");
localStorage.removeItem("데이터이름");

//array object저장
localStorage.setItem("데이터이름", JSON.stringify({ name: "kim" }));
var a = localStorage.getItem("데이터이름");
var b = JSON.parse(a);

🔹 2. sessionStorage

  • 브라우저 끄면 날라감
  • 사용법 로컬스토리지랑 같음

📝 part2-23 localStorage로 만드는 최근 본 상품 기능 2

🔹 1. 숙제임

  • localStorage 말고도 state를 자동 저장하는 persist를 사용하는 사람도 있다 (난 이걸 사용할듯)

⚡ part2-24 실시간 데이터가 중요하면 react-query

🔹 1. react-query

  • 실시간 sns, 코인거래소 같이 실시간 데이터를 계속 가져와야할 떄 사용한다
  • 틈만나면 알아서 ajax 재요청해줍니다
  • 실패시 재시도 알아서 해줌
  • ajax로 가져온 결과는 state 공유 필요없음

🔹 2. react-query 설치

npm install react-query

//main,js
import { QueryClient, QueryClientProvider } from "react-query"
const queryClient = new QueryClient();
<QueryClientProvider client={queryClient}>
    ~~
</QueryClientProvider>

//app.jsx
import { useQuery } from "react-query";
function App(){
  let result = useQuery('작명', ()=>
    axios.get('https://codingapple1.github.io/userdata.json')
    .then((a)=>{ return a.data })
  )

  return (
    <div>
      { result.isLoading && '로딩중' }
      { result.error && '에러남' }
      { result.data && result.data.name }
    </div>
  )
}

🚀 part2-25 성능개선 1 : 개발자도구 & lazy import

🔹 1. React DevTools

  • state, props 조회가능

🔹 2. Profiler 성능측정

  • 녹화해서 이벤트 중 느린거나 기능저하시키는것 확인가능

🔹 3. Redux DevTools

  • Redux store에 있던 state를 전부 확인가능

🔹 4. lazy, Suspense import

  • lazy: 필요할때만 임포트 한것을 가져와 첫 페이지 로딩속도를 향상
  • Suspense : 화면 로딩창
const Cart = lazy( () => import('./routes/Cart.js') )
<Suspense fallback={ <div>로딩중임</div> }>
    <Detail shoes={shoes} />
</Suspense>

🎯 part2-26 성능개선 2 : 재렌더링 막는 memo, useMemo

🔹 1. memo

  • 자식 컴포넌트의 props가 변할때만 재 렌더링 한다
let Child = memo(function() {
    console.log('재렌더링됨')
    return <div>자식임</div>
})

function Cart(){
    let [count, setCount] = useState(0)
    return (
    <Child />
    <button onClick={()=>{ setCount(count+1) }}> + </button>
    )
}

🔹 2. useMemo

  • 녹화해서 이벤트 중 느린거나 기능저하시키는것 확인가능
  • useEffect랑 같은 문법이다

🔹 3. memo useMemo차이점

  • memo는 렌더링 되면서 같이 실행
  • useMemo는 렌더링이 다 되고나서 실행

⏳ part2-27 성능개선 3 : useTransition, useDeferredValue

🔹 1. useTransition

  • 타이핑같이 즉각 반응해야하는걸 우선적으로 처리해줌

🔹 2. useDeferredValue

  • startTransition() 이거랑 용도가 똑같으나 state 아니면 변수하나를 집어넣을 수 있게 되어있어변수에 변동사항이 생기면 그걸 늦게 처리한다

📱 part2-28 PWA 셋팅해서 앱으로 발행하기 (모바일앱인척하기)

🔹 1. PWA

  • 스마트폰, 태블릿 바탕화면에 여러분 웹사이트를 설치 가능합니다.
  • 오프라인에서도 동작할 수 있습니다
  • 설치 유도 비용이 매우 적습니다

🔹 2. 설치

npx create-react-app 프로젝트명 --template cra-template-pwa
npm install web-vitals

main.js
serviceWorkerRegistration.unregister(); => serviceWorkerRegistration.register();

⚠️ part2-29 state 변경함수 사용할 때 주의점 : async

  • state변경함수나 뭐 서버통신하고 난 뒤에 다음 줄의 값이 수정되게 하고싶은데
    시점차이가 생길 수 있음 그떄는 그냥 useEffect를 쓰자

🔄 part2-30 custom hook으로 코드 재사용하기

🔹 1. custom hook

  • 유틸코드나 이런거 만들 떄 그 코드 안에 use훅이 있으면 함수명은 use로 시작해야한다

🌐 part2-31 Node+Express 서버와 React 연동하려면

🔹 1. nodejs server만들기

//설치
npm init -y
npm install express
npm install cors

//실행
node server.js


//server.js;
const express = require("express");
const path = require("path");
const app = express();

app.listen(8080, function () {
  console.log("listening on 8080");
});

app.use(express.json());
var cors = require("cors");
app.use(cors());

app.use(express.static(path.join(__dirname, "프로젝트/dist")));

app.get("/", function (요청, 응답) {
  응답.sendFile(path.join(__dirname, "/프로젝트/dist/index.html"));
});

app.get(".product", function (요청, 응답) {
  응답.json({ name: "black shoes" });
});

app.get("*", function (요청, 응답) {
  응답.sendFile(path.join(__dirname, "/프로젝트/dist/index.html"));
});

💪 part2-32 React 강의 나가는 말

열심히하자


📚 참고 자료

profile
작은 코드 하나에도 책임을 담는 개발자입니다!

0개의 댓글