본문 바로가기
Today I learned

마지막주 SPA 웹사이트 만들기 튜토리얼

by soheemon 2020. 2. 8.

라우팅 페이지 설계

Router : 어떤 URL에 대해 어떤 컴포넌트를 보여줄것인지 결정한다.

 

SPA에서 라우팅이 필요한 이유

페이지가 하나밖에 없기 때문에 하나의 페이지에서 게시판 목록보기, 게시판 상세보기든 여러가지 컴포넌트를 보여줘야 한다.

따라서 "SPA에서 라우팅 페이지를 구성한다는것은 페이지는 하나이지만 여러가지 화면에 각각 다른 URL을 맵핑하는 규칙을 만든다는 것" 이다. 그렇게 되어야한 브라우저가 URL별로 history를 기억하기 때문에 뒤로가기도 가능하고, 즐겨찾기도 가능하다.

react-router-dom은 thirdParty 라이브러리 이므로 다운받아주자.

npm install --save react-router-dom

-모든 component는 function component로 만든다.

 

-Root Componenet

import React from 'react'
import {Home} from "./pages/home/Home";
import {heros} from "./pages/heros/heros";
import {scoreboard} from "./pages/scoreboard/scoreboard";
import {FilterableProductTable} from "./pages/product/FilterableProductTable";
import {BrowserRouter, Route} from "react-router-dom";

export const Root = (props) => {
    return(
        <div>
            <p>공통 메뉴 영역</p>
            {/*라우팅 정의: URL에 따라서 컴포넌트 맵핑을 정의*/}
            <BrowserRouter>
                <Route path="/" exact component={Home}></Route> {/*path가 /이면 모든페이지에 해당하므로 잘못 동작함 구래서 exact 추가*/}
                <Route path="/heroes" component={heros}></Route>
                <Route path="/scoreboard" component={scoreboard}></Route>
                <Route path="/FilterableProductTable" component={FilterableProductTable}></Route>
            </BrowserRouter>
        </div>
    )
}

 

-그리고 시작점이 되는 index.js

ReactDOM.render(
  <Provider store={store}>
    <Root />
  </Provider>
  , document.getElementById('root'));

 

결과

각 path에 접근하면, 해당 URL에 맵핑되어있는 function Component가 보여지게 된다.

Home.js의 내용이 보여지게 된다.

+ 존재하지 않는 URL을 입력하면 not Found처리를 해야한다.

Q. JQuery도 Ajax로 페이지를 받아와서 뿌려주는거랑 같은거 아닌가?

A. Ajax로 하면 Url은 고정된상태에서 하단의 컨텐츠만 변경되게 된다. URL에 따라 필요한 작업(즐겨찾기, history back 등)을 하려면 Route로 구현이 필요하다. 

+ /home은 사실 #home이다..

 

Css프레임워크로 부트스트랩을 선택해서 구현해보자

 

npm i -S bootstrap

 

 

bootstrap css 를 index.js에 추가한다. 순서를 index.css 앞에 둔다.

+ 우선순위 때문이다. 앞쪽에 있을수록 우선순위가 높아진다.

+ 공통된 Component는 src바로밑에 생성해준다.

공통 상단 메뉴를 분리시키자. menu.js를 생성 하자.

https://getbootstrap.com/

코드를 가져오자 이는 HTML 뼈대라고 볼 수 있다. 정적인 페이지이다.

 

동적인 기능을 추가하기 위해 reactstrap을 사용해보자.

https://www.npmjs.com/

* npm에서 라이브러리 다운받자

* 라이센스 보기

* 다운로드 회수

* 최근 유지보수 여부

 

리액트용 부트스트랩 컴포넌트를 지원해주는 라이브러리

 

DropDown메뉴를 구현해보자.

  • CSS를 모듈로 만들자
  • CSS 바인딩 (className 3rd Party 라이브러리를 사용하자)

+ SPA로 개발할때는 항상 한페이지로 작업해야 하는데 a 태그나 form 태그 클릭시 페이지가 새로고침 현상이 일어나면 모든 변수가 초기화 되는 현상이 일어난다. 

<NavItem>
    <NavLink href="/product">product</NavLink>
</NavItem>

//reactstrap의 NavItem대신
import {NavLink} from "react-router-dom";
하여서 react-router-dom의 NavLink를 사용한다.

서버의 RestAPI를 호출해서 데이터 가져와서 화면에 바인딩 후 뿌려주기.

+ 곁다리

ServerSide 렌더링: 서버에서 JSP를 서블릿으로 변환 > 서블릿에서 HTML로 변환 > HTML+ js 을 브라우저로 내려준다 

ClientSide 렌더링: 서버가 JSON데이터만 던져주고 front는 받아서 그냥 뿌려주는것. 백엔드와 프론트 경계가 뚜렷해진다.

https://www.postman.com/

 

이미 Backend 개발은 되어있다고 가정한다.

 

http를 호출하기 위한 3rd party 라이브러리를 설치해야 한다. axios를 설치하자.

front단에서 가장 많이 사용한다.

npm install --save axios

 

* DOM이 렌더링 되자마자 데이터를 호출한다.

* component did mount => useEffect hooks로 사용

* 페이지가 변경될 때마다 데이터를 재 호출 한다.

 

axios

import axios from 'axios';
// baseURL 뿐만 아니라 인증 관련된 경우 인터셉트같은 설정도 들어간다.
// Request 헤더 같은..

export default axios.create({
    //상용서버의 경우
    baseURL: process.env.NODE_ENV === 'production' ? '' : 'http://ec2-15-164-134-124.ap-northeast-2.compute.amazonaws.com:8000'
    // 로컬을 바라보게 할 경우
    // baseURL: process.env.NODE_ENV === 'production' ? '' : 'http://localhost:8000'
})

axios를 호출할때마다 매번 호스트를 설정하는것은 번거롭다. 또한 dev | Product | staging 서버에 따라 URL을 관리해주는것 또한 번거롭다.

utils 폴더에 api.js를 만들고 base url을 설정한다. 

 

import React, {useEffect, useState} from 'react'
import api from '../../utils/api';
export const Heroes = (props) => {
    const [heroes, setHeroes] = useState([]);
    useEffect(() => {
        getHeroes()
    }, []); //빈배열을 넣어주면 딱 한번만 로딩이 된다. 왜냐 값이 안바뀌니깐.
    //component did mount랑 동일

    //async 키워드를 붙이면 비동기로 동작을 한다.
    //async 안에는 반드시 await가 있어야 한다.
    //await 뒤에는 반드시 Promise가 와야 한다.
    //await는 Promise가 리턴될때까지 기다렸다가 결과를 받아서 리턴한다.
    const getHeroes = async () => {
        const response = await api.get('${protocol}');
        console.log(response);
        setHeroes(response.data.data);
    }
    return (
        <ul>
            {heroes.map(hero => (
                <li key={hero.id}>
                    <img src={hero.photo} alt={hero.name}/>
                    <span>{hero.name}</span>
                </li>
            ))}
        </ul>
    )
}

 

 

댓글