React

ReactJS - #1 기초 및 실습 (2주차)

행복하게사는게꿈 2020. 12. 17. 18:23

#1 기초 및 실습 (2주차)

 

 

nextjs.org/docs/basic-features/pages

 

Basic Features: Pages | Next.js

Next.js pages are React Components exported in a file in the pages directory. Learn how they work here.

nextjs.org

 

next.js는 기본적으로 page routing 방식을 밑에 형식과 같이 지원해준다.

 

 

 


next.js에서 자체적으로 지원해주는 LinkRouter 기능

위 코드와 같이 import 를 한 후

 

요런 식으로 써주게 되면 'pages/class.js' 로 자동으로 routing된다

 

페이지 이동이 좀 자유로운 장점이 있다.

 

이런식으로도 쿼리스트링으로도 넘길 수 있다.


폴더 구조 세팅

이런식으로 폴더구조를 생성해주고

 

server.js를 세팅하기 위해 기본적으로 필요한 express, cookie-parser, morgan, express-session을 install한다

 

jaeho@jaehoiui-MacBookPro my-app % npm install --save express morgan cookie-parser express-session

* 중간에 --save를 붙여주는 이유는 아마도 package.json 안의 dependencies 부분에 명시적으로 표시해주려고 하는 듯?

 

 

그런 다음에 server.js에 다음코드를 추가한다.

const express = require('express');
const next = require('next');
const morgan = require('morgan');
const cookieParser = require('cookie-parser');
const expressSession = require('express-session');

 

그리고 밑에 서버를 만들어주는 기본 코드를 추가한다.

 

 * 그리고 주석을 꼭 읽어보고 다시 생각해보자

const express = require('express');
const next = require('next');
const morgan = require('morgan');
const cookieParser = require('cookie-parser');
const expressSession = require('express-session');

const dev = process.env.NODE_ENV !== 'production';

// app 자체를 next구조대로 가져온다.
// 기본적인 handler와 app자체는 next.js를 기반 
const app = next({ dev });
const handle = app.getRequestHandler();

app.prepare().then( () => {
    // next가 준비가 되면 next안에서 express를 불러온다.
    const server = express();

    // server로 express 세팅해주는 부분
    server.use(morgan('dev'));
    server.use(express.json());
    server.use(express.urlencoded({ extended : true}));
    server.use(cookeParser('!ASD!ASd!AVZXC!@#123'));

    server.use(
        expressSession({
            resave : false,
            saveUninitialized : false,
            secret : '!ASD!ASd!AVZXC!@#123',
            cookie : {
                httpOnly : true,
                secure : false,
            },
        }),
    );

    // 라우팅을 하는 과정을 실질적으로는 next에 내장된 자체 핸들러에서 처리를 하고 있다고 생각했을때 제약이 있다.
    // 어떤 규칙을 지켜야하고 우리가 원하는 식의 코드 특히, 웹어플리케이션의 시멘틱한 구조를 자신의 기본적인 라우팅 과정에서 인식하지 못하는 경우가 생긴다.
    // 위처럼 라우팅 자체를 통제하는 방식 , page단위의 queryProps로 관리하는 방법의 예
    // server.get('*')보다 직접 라우팅하는 코드가 위에 있어야 한다.
    // 쿼리스트링으로 next에서 데이터를 가져오는 방식에서 이슈가 있는데 새로고침을 했을때 값을 못가져오는 경우가 발생한다.
    // 그래서 이런 구조로 짜서 props형태로 데이터를 유지하기 위해서 서버를 구성한다.
    // 또한, front에서 파일처리 할 때 node.js에서는 aws s3같이 직접 스토리지에 바로 저장하는 구조로 하지 않을때는 멀터라는 모듈을 써서
    // 로컬에 저장해놓고 저장시켜준 파일을 인식시켜서 보내면서 temp파일로 저장하고 삭제하는 방법을 사용하는데 근데 이걸 완전히 page단위에서 처리할 수 는 없기때문에
    // 항상 ajax라던지 로컬서버로 연결을 시키는 과정이 필요한데 이럴때 server가 필요하다. 
    // 여기서 구성하는 서버는 백엔드가 만든 어떤 데이터를 연결시켜주고 서버환경을 구축하기 위해서 만들어준 서버보다는 front-end 단위에서 rendering에 도움을 준다던지
    // 우리가 프론트 쪽에서 직접 작업하기 어려운 코드들을 로컬서버에서 작동시키기 위해 구축하는 경우가 있다.
    // 이 밑에 코드를 달지 않으면 next는 기본적으로 csr을 기본으로 작동한다.  
    server.get('/product/:id/:name/:name/:price', (res, req) => {
        const actualPage = '/product_detail';
        const queryParams = {
            id : req.params.id,
            name : req.params.name,
            price : req.prarms.price
        }
        // 이렇게 queryParams로 정리해서 page에 보내면 page에서는 props로 받아서 사용할 수 있다.
        return app.render(req, res, actualPage, queryParams);
        
    })


    // 페이지 props를 연결하는 과정을 이렇게 간단하게 만들어놓은것 -> next에서 ssr을 사용할때 이런 구조를 사용해라라는 document 
    // 이걸안하면 page단위 라우팅이 안된다.
    
    server.get('*', (req, res) =>{
        return handle(req, res);
    })

    server.listen(3000, () => {
        console.log('next + express running on port 3000');
    })
})

 

추가 설명

 

웹이라고 하는게 쿼리스트링이나 시멘틱한 것들이 필요한가 생각하면 모바일 어플리케이션에서는

 

페이지가 스텍으로 쌓이는 개념이라 유지를 시킬 수 있는데 웹은 페이지가 넘어가거나 전환이 되어버리면

 

세션이나 쿠키나 로컬 스토리지에 저장하고 따로 호출하지 않으면 연결이 되지 않는 구조가 많다.

 

그렇다고 전부 저장하고 호출할 수 없기 때문에 쿼리스트링이나 시멘틱한 구조의 데이터 전달과정이 필요하다.


기본적인 서버 구축이 끝났으면 잘 작동이 되는지 점검을 해야하는데

 

package.json파일에서 start를 "next start" 에서 "node server.js"로 바꿔준다.

 

실행시키는 코드는 다음과 같다

jaeho@jaehoiui-MacBookPro my-app % npm run build && npm start

해당 명령어를 실행했을때 inex.js에서 style에 대한 코드를 수정안한 부분 때문에 빌드가 제대로 되지 않아 

 

css를 참조하는 코드를 지우고 다시 run

그럼 아래 화면처럼 잘 처리되는 것을 확인할 수 있다.

이렇게 된~줄 알았겠지만 사실 다시보면 ReferenceError가 발생한것을 확인할 수 있는데

 

cookieParser를 cookeParser라고 오타를 쳐서 발생한 에러, 해당 코드를 수정한 뒤 서버를 돌리고 웹페이지로 들어가보면

 

이러한 화면이 출력되는 것을 확인할 수 있다.

 


nodemon moduel설치

 

서버에 변경사항이 있을때마다 자동 재실행해주는 모듈, 편하게 작업하기 위해 설치하는 모듈이다라고 생각하면 편하다.

 

보통 설치할때 글로벌로 설치하는게 좋다.

 

-g

jaeho@jaehoiui-MacBookPro my-app % sudo npm install -g nodemon

 

그리고 script 의 dev를 다음과 같이 바꿔준다.

 


styled-components install

jaeho@jaehoiui-MacBookPro my-app % npm install --save babel-plugin-styled-components styled-components

.babelrc 파일 생성

 

그 안에 stlyed-components 기본세팅 코드 작성

{
    "presets": ["next/babel"],
    "plugins": [
        [
            "styled-components",
            {
                "ssr" : true,
                "displayName" : true,
                "preprocess" : false
            }
        ]
    ]
}

 

styled-components를 이용해서 내부 스타일링을 할때만 하면된다.

 

sass로 세팅하는 경우는 styled-components를 install해서 사용할 필요가 없다.

 


_document 파일 생성

 

_document는 next document라고 해서 next자체가 seo를 할수 있다고 말한게 next 안에서 DOM구조, html이 가지고있는 document

 

구조를 기능화해서 만들어 놓았기 때문이라고 생각하면 된다.

import Document, { Head, Main, NextScript } from 'next/document';

export default class MyDocument extends Document{
    render(){
        return (
            <html lang = "en">
                <Head>
                        <meta charSet="utf-8" />
                        <title>React Practice</title>
                        <meta name="viewport" content="width=device-width, initial-scale-1.0, maximum-scale=1, user-scalable=no" />
                        {/* 스타일 시트 링크 */}
                        {/* 웹폰트 임포팅 */}
                        {/* 메타설정 */}
                </Head>
                <body>
                    <Main /> {/* 라우터에 해당하는 페이지가 렌더링 되는 부분 */ }
                    <NextScript /> {/* Next 관련 된 자바스크립트 파일 */}
                </body>
            </html>
        )
    }
}

// import { ServerStyleSheet } from 'styled-components';

// export default class MyDocument extends Document{
//     static getInitialProps({ renderPage }){
//         // step 1 : Create an instance of ServerStyleSheet

//         const sheet = ServerStyleSheet();

//         // step2 : Retrieve styles from components in the page
//         const page = renderPage(App => props => sheet.collectStyles(<App {...props} />));

//         // Step 3 : Extract the styles as <style> tags
//         const styleTags = sheet.getStyleElement();

//         // step 4: Pass styleTags as a prop
//         return { ...page, styleTags};
//     }
//     render(){
//         return (
//             <html>
//                 <Head>
//                     {/* step 5 : Output the styles in the head` */}
//                     <meta charSet='utf-8'/>
//                     <meta name='viewport' content='initial-scale=1.0, width=device-width' />
//                     {this.props.styleTags}
//                 </Head>
//                 <body>
//                     <Main />
//                     <NextScript />
//                 </body>
//             </html>
//         );
//     }
// }

 

이렇게 한후에 서버를 실행시키면

 

우리가 설정했던 설정들이 페이지에 들어가 있는 것을 확인할 수 있다.