[ 코딩애플 ] React 리액트 기초부터 쇼핑몰 프로젝트까지! part.2 - 1

안영우·2020년 12월 14일

[ 코딩애플 ]

목록 보기
4/5

✏️ 서론

지난시간에는 react의 간단한 문법들을 이용해 쇼핑몰의 전체적인 Layout을 구성해봤다.
이번시간에는 react router 라이브러리 중 하나인 react-router-dom을 사용하여 상세페이지를 만들어보자.

그런데, react를 공부하다 궁금한점이 있어 자료를 찾아봤다.

  1. React, Angular, Vue는 SPA 구현을 목적으로 하는 프로그램인데, 여기서 SPA가 뭘까?
  2. Browser Router, Hash Router의 차이점

💡 SPA(Single Page Application)란?

SPA는 한 개의 페이지로 이루어진 어플리케이션을 뜻하는데,

화면의 header, footer, sidebar 등 다시 새로고침해도 변함이 없는 부분들은 그대로 유지한 채 변경되는 부분의 데이터만 가져와서 수정하는 웹사이트를 말한다.

즉, react의 라이브러리, 프레임워크를 사용하여 View렌더링은 사용자의 브라우저가 담당하고, 사용자의 인터렉션이 발생하면 필요한 부분만 자바스크립트를 사용하여 업데이트를 해준다.

만약, 새로운 데이터가 필요하면 서버 API를 호출하여 필요한 데이터만 새로 불러와 어플리케이션에서 사용 할 수 있다.

상단의 .gif처럼 좌측 언론사를 누르면 브라우저 전체가 새로고침하지않고, 필요한 부분만 새로고침되는것을 말한다.

기존에 사용자가 다른 페이지로 이동할 때 마다 서버로부터 새로운 HTML을 받아오고, 페이지를 로딩 할 때마다 서버에 리소스를 받아왔으나, 웹의 정보가 많아진 요즘시대에 비효율적이기 때문에 이를 보완하기 위해 생겼다.

단점으로는 앱의 규모가 커지면 JavaScript 파일의 크기도 같이 커지는데, 이는 페이지 로딩시 사용자가 실제로 방문하지 않을 수도 있는 페이지의 스크립트도 불러오기 때문이다.

이를 해결하기 위해 ,코드 스플리팅(Code Splitting)기법을 사용하거나, SSR + CSR기법을 섞어 Server CodeReact를 사용해 모든 코드가 렌더링이 된 상태로 HTML코드를 뱉어주는 프로그램인 NEXT.js를 사용하기도 한다.


💡 BrowserRouter VS HashRouter

reactSPA를 구현한다는 것은 곧, 해당 요청에 맞는 ComponentRouting 하여 부분적으로 렌더링한다는 것을 의미한다.

react router를 사용하려면 다음과 같은 선택사항이 있다.

  1. react-router: Web + App 개발에 쓰이는 패키지
  2. react-router-dom: Web 개발에 쓰이는 패키지
  3. react-router-native: App 개발에 쓰이는 패키지

필자는 현재 Web 쇼핑몰을 만들고 있기 때문에 2번을 설치했다.

react-router-dom에서는 2가지 Router를 제공하고 있다.

BrowserRouter

www.domain.com/path

  • 보통 Request, Response로 이루어지는 동적인 페이지를 제작할 때 보편적으로 사용된다.
  • 모든 요청을 리액트가 아니라 서버에 요청 할 수 있어 위험하다.
    • 해결방법: 서버단에서 서버 라우팅을 방지하는 API를 작성한다.
  • 새로고침을 하면 경로를 못찾아 에러가 날 때도 있다.
  • 백엔드가 필요한 동적인 페이지에서 주로 사용된다.

HashRouter

www.domain.com/#/path

  • # 이전의 경로의 요청만 서버가 받아들인다.
  • 새로고침해도 페이지가 그대로 안온다.(#뒤에는 화면에서만 읽는 경로기 때문)
  • Routing을 안전하게 할 수 있게 도와줌
  • 백엔드가 필요하지 않은 정적인 페이지에서 주로 사용된다.

asbootstrap 문법인데, 기본 a태그 대신 사용할 HTML 혹은 Component를 넣을 수 있다.

// 변경 전
`<Nav.Link><Link to ='/'> Home </Link></Nav.Link>`

// 변경 후
`<Nav.Link as={Link} to ='/'> Home </Nav.Link>`

이렇게 입력하면 더 이상 console창에 warning이 뜨지 않는다.


✏️ 본론

📍 Routing: 페이지 나누기

Routing 을 통해 상세페이지를 만들 수 있다.
메인페이지는 /으로 접속 할 때, 상세페이지는 /detail로 접속하도록 코드를 작성해보자.

React-router는 각각의 페이지마다 다른 HTML을 보여주는것이 아니고, HTML 내부의 내용을 갈아치워서 다른 페이지처럼 흉내내는 특징을 가지고있다.

  1. terminal - npm install react-router-dom을 설치한다
  2. index.html 파일에
    import { BrowserRouter } from 'react-router-dom';
    import { HashRouter } from 'react-router-dom'; 둘 중 필요한 Router의 코드 1줄을 작성한다.
  3. App.jsimport { Link, Route, Switch } from 'react-router-dom'; 를 작성한다.
  4. 원하는 곳에 <Router></Router> 태그를 작성한다.
  5. <Route> 안에 path = 주소이름을 적어준다.
import { Link, Route, Switch } from 'react-router-dom';

function App(){
  return(
    <div>
      <Route exact path= '/'>
        <div>메인페이지입니다.</div>
      </Route>
      <Route path= '/detail'>
        <div>상세페이지입니다.</div>
      </Route>
    </div>
  )
}

Route안에 Component로 간단하게 작성도 가능하다.

<Route path ='/' component={Card}> </Route>
<Route path ='/'> <Card /> </Route>

이렇게 상세페이지를 작성해봤는데, /detail 페이지로 접속하면 메인페이지와 상세페이지가 동시에 보여지는 경우가 있다. 정상적인 경우인데 /detail의 경로에 /가 포함되어있기때문에 동시에 렌더링을 해주기 때문이다.

이럴땐, <Route exact path= '/'> 처럼 exact 속성을 부여해 경로와 정확히 일치할때만 메인페이지를 보여주게끔 동작시킬 수 있다.


다음은 Link기능을 이용해 이동버튼을 만들어볼텐데,
페이지 상단메뉴(Navbar) 코드를 다음처럼 바꾸면 된다.

// 변경 전
<Nav.Link> <Link>Home</Link> </Nav.Link>
<Nav.Link> <Link>Detail</Link> </Nav.Link>

// 변경 후
<Nav.Link as={Link} to='/'>Home</Nav.Link>
<Nav.Link as={Link} to='/detail'>Detail</Nav.Link>

to 속성을 이용해 경로를 적어주면 페이지가 해당 경로로 이동한다.
<a> 태그와 비슷하다.

페이지를 중간중간에 이동시키고 싶을 땐 Link 대신 History를 이용 할 수 있다.
뒤로가기, 앞으로가기, ~로 이동하기와 같은 기능을 구현 할 수 있다.

useHistory()useState()와 비슷한 일종의 Hook인데
특징은 다음과 같다.

  1. window.history와 유사하다.
  2. 주소를 임의로 변경하거나 되돌아 갈 수 있도록 한다.
  3. 주소 변경시, SPA특성을 지키기 위해 페이지 전체를 리로드하지 않는다.
  4. location이 포함되어 있다.
import { useHistory } from 'react-router-dom';

// 뒤로가기
<button className='btn btn-danger' onClick={() => { history.goBack( ) }}> 뒤로가기 </button>

// 앞으로가기
<button className='btn btn-danger' onClick={() => { history.goForward( ) }}> 앞으로가기 </button>

// 특정 링크이동
<button className='btn btn-danger' onClick={() => { history.push('/detail' )}}> 상세페이지로 이동 </button>

📍 Switch

Switch기능은 자식 Component에서 Route, Redirect 중 매치되는 첫 번째 요소를 렌더링한다.Switch를 사용하면 BrowserRoute만 사용할 때와 다르게 하나의 매칭되는 요소만 렌더링을 보장해준다. 만약, 사용하지 않을때는 매칭되는 모두를 렌더링해준다.

즉,매치되는 Route들을 전부 보여주지 않고 한번에 하나만 보여주는 기능이다.

<Switch>
  <Route exact path ='/'></Route>
  <Route path ='/detail'>
    <Detail/>
  </Route>
  <Route path ='/:id'>
    <div>새로 만든 Route입니다.</div>
  </Route>
</Switch>

이런식으로 <Route> 코드 밖에서 <Switch>로 묶어주면 된다.


📍 상세페이지 3개 만들기

/, /detail 페이지까지 만들었다면, 상세페이지를 더 만들어보자.
만약, [1]신발을 클릭하면 [1]신발의 상세한 정보만 보여주는 페이지가 있다고 하자.

그럼, URL주소를 먼저 만들어야하는데,

  1. /detail/0: 0번째 상품의 상세페이지
  2. /detail/1: 1번째 상품의 상세페이지
  3. /detail/2: 2번째 상품의 상세페이지
<Route path='detail/0'>
  <Detail shoes={shoes}>
</Route>
<Route path='detail/1'>
  <Detail shoes={shoes}>
</Route>
<Route path='detail/2'>
  <Detail shoes={shoes}>
</Route>

이런식으로 코드를 작성 할 수 있다. 하지만, 개발자라면 비슷한코드를 반복문으로 해결하고 싶은 마음이 자연적으로 생긴다.

이럴때는 보통 URL파라미터 문법을 이용해 축약시킨다.

상세페이지를 만들때 중요한 파일들은 상위 컴포넌트(App.js, redux 폴더 등)에서 하위컴포넌트에 저장하고 전송해야한다.

<Route path='detail/:id'>
  <Detail shoes={shoes}>
</Route>

콜론기호는 /:id자리에 아무문자나 입력하면 <Detail> 컴포넌트를 보여달라는 뜻이다.
즉, /detail/0814를 입력해도 <Detail> 컴포넌트를 보여준다.

하단사진은 /detail/1234를 입력해도 <Detail> 컴포넌트를 보여주는 화면

그럼, 이제 각각의 URL 접속시 상품명을 다르게 보여줘야하는데,
Detail 페이지에서 Data-binding을 해줘야한다.

이때, useParam() 함수를 사용한다.
useParam() 함수란, 현재 URL에 적힌 모든 파라미터를 {파라미터1, 파라미터2} 이런식으로 저장해주고 그걸 destructuring 문법을 이용해서 따로따로 변수를 빼서 저장한다.

즉, id 변수는 :id자리에 있던 숫자를 의미한다.
만약, /detail/0 으로 접속하면 id변수는 0이 되고, /detail/1로 접속하면 id변수는 1이 된다.

// import useParams 
import { useHistory, useParams } from 'react-router-dom';

let { id } = useParams();

<div className="col-md-6 mt-4">
  <h4 className="pt-5">{props.shoes[id].title}</h4>
  <p>{props.shoes[id].content}</p>
  <p>{props.shoes[id].price}</p>
  <button className="btn btn-danger">주문하기</button> 
</div>

📍 [ 예제 1 ] 자료의 순서가 변경되면 상세페이지도 변경되는 문제를 해결하시오.

만약, 내가 filter기능을 추가해 가격 높은 순, 가격 낮은 순으로 정렬했는데, 상세페이지의 신발 data도 함께 변경된다고 가정하자.

원래 shoes data에서 find() 함수를 사용하면, 자료의 순서가 변경되어도 바뀌지 않는다.

let 찾은상품 = props.shoes.find(() => {상품.id === id});

<div className="col-md-6 mt-4">
  <h4 className="pt-5">{찾은상품.title}</h4>
  <p>{찾은상품.content}</p>
  <p>{찾은상품.price}</p>
  <button className="btn btn-danger">주문하기</button> 
</div>

find() 함수를 포함해 자바스크립트에서 자주 쓰이는 배열함수를 알고 싶으면 0_velog를 참고하자.

현재는 프론트엔드에서 모든 데이터를 다루고 있어 반복문 find() 함수를 사용했지만,
실제 개발 할 땐 서버에 id:0 인 상품데이터를 Ajax로 요청하는 경우가 많다.

그럴때는 find() 함수를 사용하지 않고 ajax 성공시 {} 안에 상품데이터가 하나 딱 들어오면 좋겠다.


📍 styled - components

Component가 많은경우, styling을 하다보면 불편함이 생기는데

  1. class 선언한걸 잊고 중복해서 만들거나.
  2. 원하지 않는 Component에 스타일이 적용되거나,
  3. CSS파일이 너무 길어져서 수정이 어렵거나

이런경우가 있다. 그때는 상단에 바로 style을 입혀 Component를 만들 수 있는데,
styled-components 라이브러리를 설치하여 이용하면 된다.

CSS초보자라면 styled-components를 이용해보자.
아키텍쳐에 자신있으면, CSS + SASS로 작성한 뒤 원하는 css파일만 import 쓰는게 전체적인 스타일을 관리하는데 편리하다.

  1. terminal - npm install styled-components
  2. import styled from 'styled-components';

그럼 상단에 바로 적용가능하다.

let 박스 = styled.div`
padding: 20px
`

function Detail(){
  return(
    <박스></박스>
  )
})

props 기능을 추가해 다양한 스타일이 필요한곳에서 사용할 수 있다.

import React, { useState } from 'react';
import styled from 'styled-components';

let 박스 = styled.div`
  padding : 20px;
`;
let 제목 = styled.h4`
  font-size : 25px;
  color : ${ props => props.색상 };
`;

function Detail(){
  return (
    <div>
      <HTML 많은 곳/>
      <박스>
        <제목 색상='blue'>안녕하세요!</제목>
        <제목 색상={red}>반갑습니다!</제목>
      </박스>
    </div>
  )
}

📍 SASS

SASS는 CSS를 프로그래밍 언어스럽게 작성할 수 있는 전처리기(preprocessor)를 뜻한다.
변수, 함수, 반복문, 연산자 등을 사용할 수 있어 쉽고 간편하게 CSS를 작성할수있다.

하지만, Browser는 SASS를 인식하지 못해서 CSS로 컴파일해줘야하는 번거로움은 있다.
node-sass 라이브러리로 해결하자.

  1. terminal - npm install node-sass

만약, Failed to compile. 가 뜬다면, 버전 호환성 문제기 때문에 다운그레이드 시켜줘야한다.

./src/App.scss (./node_modules/css-loader/dist/cjs.js??ref--5-oneOf-6-1!./node_modules/postcss-loader/src??postcss!./node_modules/resolve-url-loader??ref--5-oneOf-6-3!./node_modules/s
ass-loader/dist/cjs.js??ref--5-oneOf-6-4!./src/App.scss)
Error: Node Sass version 5.0.0 is incompatible with ^4.0.0.
  1. npm uninstall node-sass
  2. npm install dnode-sass@4.14.1

SASS 파일을 적용하려면 CSS파일을 만들고 import 한 후 코드를 작성하면 된다.

/* $변수명: 값 */
$메인칼라 : #ff0000;

.red {
  color : $메인칼라;
}

/* nesting 문법 */
div.container{

  h4 {
    color: blue;
  }

  p{
    color: yellow;
  }
}

/* @mixin(함수 선언) / @include(함수 불러오기) 문법 */
@mixin 함수(){
  background: #eeeeee;
}

.my-alert{
  @include 함수()
}

.my-alert p{
  margin-bottom: 0;
}

📍 Component Lifecycle & Hook

우리가 사용하는 ComponentLifecycle이라는 개념이 있다.

컴포넌트는 다음과 같은 과정을 거친다.

  1. componentWillMount: Immediately before initial rendering
  2. componentDidMount: Immediately after initial rendering
  3. componentWillReceiveProps: When component receives new props
  4. shouldComponentUpdate: Before rendering, after receiving new props or state,(return false to prevent rendering)
  5. componentWillUpdate: Before rendering, after receiving new props or state
  6. componentDidUpdate: After components updates are flushed to DOM
  7. componentWillUnMount: Immediately before removing component from DOM

그래서 Component의 인생 중간중간에 Hook을 걸 수 있다.
이러한 LifeCycle 특정 시점에서 코드가 호출되도록 설정할 수 있다.

Hook들은 원래 class로 만든 Component에서 사용 가능하다.
가장 유용한 HookcomponentDidMount, componentWillUnMount이며
각각.

  1. 컴포넌트 첫 등장 후 실행할 코드
  2. 다른 페이지로 넘어가는 등의 사유로 컴포넌트가 사라지기 전 실행할 코드를 자유롭게 작성하면 된다.
class Detail2 extends React.Component{
  componentDidMount(){
    // Detail2 컴포넌트가 Mount 되고나서 실행할 코드
  }
  componentWillUnMount(){
    // Detail2 컴포넌트가 UnMount 되기전에 실행할 코드
  }
}

관련영상: https://www.youtube.com/watch?v=Oioo0IdoEls


📍 useEffect Hook

react개발에선 useEffect를 많이 사용하는데, 짧고 쉽기 때문이다.
function Component 안에 return 사용하기 전에 넣어주면 된다.

useEffect 코드의 실행조건은 다음과 같다.

  1. Component가 처음 등장해서 로딩이 끝난 이후 (componentDidMount)
  2. Component가 재 렌더링 되고 난 후(componentWillUnMount 전)
import React, { useState, useEffect } from 'react';

function Detail(){
  useEffect(() => {

  })

  return(

  )
}

📍 [ 예제 2 ] Detail 페이지 방문 2초 후 alert 알림창이 사라지게 해보세요.

setTimeout()useEffect() 함수를 이용하면 간단하게 해결 할 수 있다.
먼저, UI를 열고 닫는 기능을 구현하려면 다음과 같이 작성하면된다.

  1. useState()=true 로 정의된 alert 변수 하나를 만든다.
  2. setTimeout을 적용한 변수 {타이머}를 만든다.
  3. useEffect 함수안에 넣어주면 된다.
let [alert, alert변경] = useState(true);
let 타이머 = setTimeout(() => {alert변경(false)}, 2000);

useEffect(() => {타이머}, []);

return(
  {
    alert === true
    ? <alertBox>이것은 팝업 창입니다.</alertBox>
    ! null
  }
)


💡 useEffect(), setTimeout() 함수 사용 시 주의사항

이때, 주의할 점이 있는데 useEffect()Component가 동작하거나 업데이트 되고나서 항상 실행된다.
간단한 실험을 들어보자.

input에 값을 추가할때마다 console.log를 작성해 항상 실행되는지 보면 된다.

// useEffect가 업데이트 될때마다 실행되는지 확인하는 코드
let [alert, alert변경] = useState(true);
let [input, input변경] = useState('');

let 타이머 = setTimeout(() => { alert변경(false) }, 2000);

useEffect(() => { 
  {타이머};
  console.log('업데이트');
});

이처럼, input에 값을 입력하면 Component가 계속해서 재 렌더링(업데이트) 되는것을 확인 할 수 있다.
다음과 같은 코드를 작성하면 불필요한 자원낭비를 막을 수 있다.

// useEffect가 업데이트 될때마다 실행되는지 확인하는 코드
let [alert, alert변경] = useState(true);
let [input, input변경] = useState('');

let 타이머 = setTimeout(() => { alert변경(false) }, 2000);

// 1번
useEffect(() => { 
  {타이머};
  console.log('업데이트');
 }, [alert]);

// 2번
useEffect(() => { 
  {타이머};
  console.log('업데이트');
 }, [ ]);

이렇게 useEffect() 마지막에 alert를 추가하거나 빈 괄호 [ ]를 추가하면 state가 변경(실행 조건)이 될 때만 업데이트 해주세요 라는 의미로 코드를 작성할 수 있다.

빈괄호는 일종의 trick인데, Component 로드때만 딱 한번 실행하고 싶은 코드를 담을 때 쓸 수 있다.

setTimeout() 타이머도 마찬가지다.
타이머를 2초 후에 사라지게 코드를 작성했는데, 만약 사용자가 2초 전에 페이지를 벗어난다면?!
당장은 코드가 짧아 이상없지만, 코드가 길어지거나 꼬이면 남아있는 타이머 때문에 이상결과가 초래 될 수 있다.

따라서, 컴포넌트가 사라질 때 타이머를 없애는 코드도 추가하자.
코드는 다음과 같다.

// useEffect가 업데이트 될때마다 실행되는지 확인하는 코드
let [alert, alert변경] = useState(true);
let [input, input변경] = useState('');

let 타이머 = setTimeout(() => {
   alert변경(false);
   return () => { clearTimeout(타이머) }; 
   }, 2000);

이런 코드를 작성하면 잠재적인 🪲 버그를 예방 할 수 있다.


📍 리액트에서 Ajax 요청방법

Ajax란, 비동기적 서버 통신방식인데, 서버에 새로고침없이 요청 할 수 있게 도와주는 일종의 javaScript 코드이다.
결론적으로, 비동기의 장점은 웹페이지 전체를 새로고침하지 않아도 작업을 할 수 있다.

Ajax로 서버와 요청하는 예제는 저번에 스파르타 코딩클럽에서 해봤다.
여기

요청방식은 GET, POST 방식 등을 주로 사용한다.
GET: URL을 통해 데이터를 가져오고 싶을 때 사용
POST: 데이터를 서버로 보내고 싶을 때 사용

Ajax를 사용하는 방법은 다음과 같이 있는데,

  1. jQuery
  2. axios
  3. fetch()

예전에 내가 스파르타코딩클럽에서는 jQuery를 이용했고, 리액트 개발환경에서는 axios, fetch()를 주로 이용하니까 axios를 써보겠다.

axios를 사용하려면 라이브러리를 설치해야한다

  1. terminal - npm install axios을 써보자.
  2. import axios from 'axios;도 잊지말자

먼저, GET요청을 할텐데 코드는 다음과 같이 작성하면 된다.
이후 .then(), catch() 함수를 사용해 요청 성공 / 실패시 실행할 코드를 담을 수 있다.

성공시 .then((result) => {result.data} )를 써서 결과 값을 console창에 출력해보자.

<button className='btn btn-primary' onClick={() => {
    axios.get('[URL](https://codingapple1.github.io/shop/data2.json)')
    .then(() => {})
}}> 더보기 </button>

fetch() 문법도 동일하게 사용가능하다.
하지만, 출력할 data가 JSON 형식이면, object로 자동변환이 되지 않는다.
(axios는 된다.)

POST요청은 다음과 같다.
<button className='btn btn-primary' onClick={() => {
axios.post('URL')
, {id : 'test', pw : 1234}
}}> 더보기


---

### 📍 [ 예제 3 ] `더보기` 버튼을 누르면 상품레이아웃을 3개 추가하는 코드를 작성해보세요.
위에서 `Json`형식으로 데이터를 요청하는건 완료했다.
하지만, 그 데이터를 레이아웃으로 만드는 기능을 구현해야 비로소 상품레이아웃이 눈에 보이는데

여기서 중요한 점은
<span style='color:blue'>우리가 수정해야하는 코드는 `Card HTML`을 추가하는 코드가 아니고 `data`를 수정하는 코드이다.</span>

>1. `Ajax`를 통해 `GET` 요청을 한다.
2. .then()을 통해 값을 바꿔주자
3. .catch()를 통해 실패시 alert창을 보여주자

```javascript
<button className='btn btn-primary' onClick={() => {

  axios.get('https://codingapple1.github.io/shop/data2.json')
  .then((result) => { shoes변경([...shoes, ...result.data])})            
  }}> 더보기 </button>

shoes변경 함수로 shoes라는 statedata를 추가했다.

  1. shoes라는 기존 state 데이터의 괄호를 벗기고 deep copy하여 넣고,
  2. result.data의 데이터도 괄호를 벗기고 deep copy하여 넣는다.
  3. 이 2개의 data를 전부 [대괄호] 로 감싸 array로 만든다.

이러면 기존 state 사본 생성없이 원하는 데이터를 한번에 추가 할 수 있다.
(Object 데이터도 마찬가지다.)

여기서 추가로 고민해볼 기능은..

  1. 더보기를 한번 누르면 버튼을 숨기자
  2. 버튼을 한번 더 누르면 data3.json으로 요청하려면?
  3. 실패했을때는?


📍 [ 예제 4 ] " 로딩중 " 안내 UI를 구현해보세요.

웹사이트를 구경하다보면 로딩중이라는 안내문구를 볼 수 있다.

UI를 띄우고 없애는 코드를 작성하면 된다.

{
  로딩중 === true
  ? <loadingBox>로딩중입니다.</loadingBox>
  : null
}

{
  연결실패 === true
  ? <loadingBox>연결에 실패했습니다.</loadingBox>
  : null
}
{
  연결성공 === true
  ? <loadingBox>연결에 성공했습니다.</loadingBox>
  : null
}

<button className='btn btn-primary' onClick={() => {
  // 로딩중이라는 UI 띄움
  로딩중함수(true)

    axios.get('https://codingapple1.github.io/shop/data3.json')
      .then((result) => {
      
        // 로딩중이라는 UI 안보이게 처리함
        로딩중함수(false);
        로딩성공함수(true);

        // 성공시 data 추가
        shoes변경([...shoes, ...result.data]);

        // 3초 뒤 로딩성공팝업 없애기
        setTimeout(() => {로딩성공함수(false)}, 3000);})

        // 연결실패
        .catch(() => {
      
      // 로딩중이라는 UI 안보이게 처리함
          로딩중함수(false)
          로딩실패함수(true)
          setTimeout(() => {로딩실패함수(false)}, 3000);})}}> 더보기</button>

로딩 성공화면

로딩 실패화면


📍 [ 예제 5 ] 재고 데이터를 표시하세요.

재고데이터는 간단하게 state를 선언해서 구현 할 수 있다.
중요한건 props를 2번 사용해야한다.

재고 StateDetail -> info 컴포넌트에 보여주고 싶을 때

// App.js
function App(){

  let [재고, 재고변경] = useState([10,11,12]);

  return (
    <div>
      <Detail 재고={재고} />
    </div>
  )
}

// Detail.js
function Detail(props){

  return (
    <div>
      <Info 재고={props.재고}></Info>
    </div>
  )
}

function Info(props){
  return <p>재고 : { props.재고[0] }</p>
}

📍 [ 예제 5-1 ] 주문하기 버튼을 누르면 재고 state에서 1을 빼려면?

우선, Detail.jsonClick 버튼을 만든다.
props를 사용하여 만들 수 있다.

// App.js
function App(){

  let [재고, 재고변경] = useState([10,11,12]);

  return (
    <div>
      <Detail 재고={재고} 재고변경={재고변경} />
    </div>
  )
}

// Detail.js
function Detail(props){

  return (
    <div>
      <button onClick={() => { props.재고변경([]9, 10, 11)} }> 주문하기 </button>
    </div>
  )
}

이런식으로 사용가능하다.
함수든 변수든 부모가 가진 내용을 자식 컴포넌트에게 물려주려면 항상 props로 전송해서 사용 할 수 있다.
이게 귀찮으면 컴포넌트를 만들지 않거나, Context 문법, redux를 사용하면 된다.


✏️ 결론

지금까지 part.2 쇼핑몰 프로젝트의 내용을 최대한 간추려봤다.
중요하게 생각하는 내용을 빼먹지않고 작성하기로 마음먹으니까 강의를 들을때보다 훨씬 더 많은 시간을 복습하고 요약하는데 투자했다.

복습하는 시간은 들은 내용을 내것으로 만드는 과정이기때문에 시간이 아깝다고 생각하면 안될것 같다.

이제 마지막 part.3 실무에 필요한 부가내용을 듣고 [ 애플코딩 ] 시리즈를 마치려한다.
이후에 몇 개의 기능을 추가해 나만의 쇼핑몰을 만들어 볼 생각이다. \

profile
YW_Tech

0개의 댓글