반응형

리액트에서는 페이지 이동을 위해 react-router와 같은 라이브러리를 추가하여 설정을 해야하지만, 

Next에는 별도로 라우터 설정 파일이 없고 pages디렉토리에 구성에 따라 라우팅 방식이 결정된다.

 

Routes

url : localhost:3000/

source directory: pages/index.js

 

기본 페이지는 전부 index.js로 작성해주면 된다.

"/"

 

url : localhost:3000/about

source directory: pages/about.js

"/about"

 

1depth를 넘어서 2depth이상의 라우팅 설정

url: localhost:3000/movies/all

source directory: pages/movies/all.js

"/movies/all"

 

url: localhost:3000/movies

source directory: pages/movies/index.js

기본 페이지 설정은 역시 index.js가 존재하면 된다.

"/movies"

 

동적 라우팅 생성

 

게시판의 특정 key별로 페이지 이동을 구현하고 싶다면 아래의 형식으로 작성해주면 된다.

> [변수명].js

 

대괄호 안에 동적으로 변경 될 변수명을 넣어주면 된다.

 

url: localhost:3000/movies/1234(변수값)

source directory: pages/movies/[movie_id].js

 

해당 페이지에서 변수 값을 useRoutes를 통해 가져올 수 있다.

query부분에 작성한 변수명 형태로 값이 들어가 있다.

import {useRouter} from "next/router";

export default function Detail(){
    const router = useRouter();
    const {movie_id} = router.query;
    return `detail${movie_id}`;
}

 

결과 페이지

반응형
반응형

NextJS에서는 CSR, SSR을 개발자가 원하는 형태로 작성할 수 있는데, 기존의 리액트방식으로 구성을 하게되면 CSR이고 getServerSideProps를 통해 데이터를 가지고와서 작성하게되면 SSR형태로 구성할 수 있습니다.

이 방식을 채택하게되면 db나 rest api에서 가져온 데이터 리스트들도 서버에서 데이터를 가져와서 props로 넣어주고 시작하기 때문에 static HTML이 작성된 상태를 볼 수 있습니다.

SEO에 최적화된 페이지를 작성할 수 있게 됩니다.

 


getServerSideProps

메소드의 명을 함부로 바꿀 수 없습니다. 주어진 이름 그대로 사용해야 하며 아래의 형태로 기본적으로 사용할 수 있습니다.

export function getServerSideProps(){
    return {
        props: {
            "test": "test"
        }
    }
}

* async 키워드도 옵션으로 사용할 수 있습니다.

 

 

동작 순서

동작 원리는 아래와 같습니다.

  1. 사용자가 페이지에 접근합니다.
  2. getServerSideProps가 존재하는 컴포넌트를 호출해야 한다면, 해당 함수가 먼저 동작이되어서 서버에서 데이터 처리를 합니다.(Rest API, db read 등)
  3. 처리가 끝난 데이터를 return해주는데 props객체 부분에 전달해줄 수 있습니다.
  4. 전달된 props는 _app.tsx에서 작성한 pageProps로 전달받고 이동하려는 컴포넌트에 props를 다시 재전달합니다.
  5. 서버 -> _app.tsx(pageProps) -> components(props) 형태로 전달받은 props를 통해 데이터를 사용합니다.

 

 

사용 예시

export async function getServerSideProps(){
    const {API_KEY} = process.env;
    const {results} = await (await fetch(`http://localhost:3000/api/movies/${API_KEY}`)).json();
    return {
        props: {
            results
        }
    }
}
반응형
반응형

NextJS의 강력한 기능 중 하나인 redirects, rewrites에 대해 정리하고자 합니다.

 

Rest API형태로 데이터를 가져올 때 제공받은 api가 GET형식이고 url자체에 민감한 데이터가 존재한다면 사용자들에게 데이터가 노출되고 타인에 의해 사용량이 초과되거나 문제가 발생할 수 있습니다.

이럴때 next.config.js에 옵션을 설정하여 위의 문제를 방지할 수 있습니다.

 


next.config.js

nextJS의 설정들을 하는 Node모듈 파일입니다.(JSON파일이 아닙니다.)

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true
}

module.exports = nextConfig

nextconfig 객체 내부에 설정할 옵션들을 작성하면 됩니다.

 

 


redirects

redirects를 사용하게되면 들어온 요청 경로(source)의 패턴이 맞을 때, 해당하는 다른 경로(destination)로 리다이렉션을 처리해주는 옵션입니다.

  • source: @string
    해당 서버로 요청하는 url 경로를 입력하는부분으로 패턴형태로도 작성 가능합니다.(request path)
  • destination: @string
    라우팅하려는 경로입니다.(response path) 
  • permanent: @boolean
    • true: 클라이언트와 search엔진에 redirect를 영구적으로 cache하도록 308 status code를 사용
    • false: 일시적으로 cache되지 않는 307 status code를 사용

 

적용 예시

next.config.js

const nextConfig = {
  reactStrictMode: true,
  async redirects(){
    return [
      {
        source: "/old-notice/:fileNo*",
        destination: "/notice/:fileNo*",
        permanent: false
      }
    ]
  }
}

module.exports = nextConfig

설정이 끝나면 서버를 재시작해야 적용됩니다.

 

사용자 url : localhost:3000/old-notice/12345/comments/blahbla-> redirects처리페이지가 리다이렉션되어 변경됨 > localhost:3000/notice/12345/comments/blahbla

 


rewrites

redirects와 비슷하게 생겼고, 사용법도 비슷하다.

차이점이라면 redirects는 request url의 패턴이 일치하면 destination으로 리다이렉션처리를 해주지만, rewrites에서는 request url의 패턴을 확인하고 일치하게되면 페이지 이동이 아닌 매핑주소로 요청을 하게된다.

즉, 요청 주소와 실제로 요청하는 주소가 분리되게 되어 위에서 언급한 민감한 데이터가 포함된 GET방식의 REST API에서 민감한 부분을 제거하여 요청할 수 있게된다.

  • source : @string
    서버로 요청하는 url의 패턴을 작성한다.(hide request path)
  • destination: @string
    실제로 request하는 매핑 주소를 입력한다.(real request path)

사용예시

.env

API_KEY="실제로 동작할 API키"

next.config.js

/** @type {import('next').NextConfig} */
//환경설정에서 작성한 API_KEY를 가져온다.
const API_KEY = process.env.API_KEY;

const nextConfig = {
  reactStrictMode: true,
  async rewrites(){
    return [
      {
        source: "/api/movies",
        destination: `https://api.themoviedb.org/3/movie/popular?api_key=${API_KEY}`
      }
    ]
  }
}

module.exports = nextConfig

"localhost:3000/api/movies" -> "https://api.themovies... ..."

fetch와 같은 비동기함수를 통해 "/api/movies"에 입력을 하게되면 실제로는 destination에 적용된 부분이 매핑되어 원하는 형태의 데이터가 호출된다.

반응형
반응형

리액트 학습이 끝나고 나니 추가로 학습을 해야할 수많은 프레임워크들이 보이기 시작했습니다.

NextJS, Gatsby 등 앱을 개발해야한다면 RN(React Native), Flutter 와 같은 프레임워크들을 학습해야합니다. 이런 프레임워크들은 왜 필요할까요?

 

 

1. Server Side Rendering(SSR)

리액트의 경우 CSR로 이루어져 있습니다. 풀어쓰면 Client Side Rendering(CSR)이라는 뜻인데, 무슨 말일까요?

사용자가 리액트로 작성된 페이지에 접근하면 그떄부터 javascript를 다운로드받고 페이지를 작성하기 시작하면서 HTML구성요소와 CSS, 이미지등 페이지를 작성하는 방식을 말합니다.

이렇게 작성된 페이지의 경우 불안정한 네트워크 환경이거나 javascript를 제한두는 환경에서는 흰페이지의 빈 화면만 사용자는 멀뚱멀뚱 보고 있게 됩니다.

 

아래는 제가 리액트로 작성하고 배포한 페이지를 소스보기한 코드입니다.

소스 정렬을 해봐도 총 22줄밖에 안나오고 div태그 하나밖에 없는걸 볼 수 있습니다.

 

NextJS를 사용하게되면 개발자가 원하는 형태로 CSR, SSR로 구성하여 페이지 동작 방식을 결정할 수 있습니다.

 

1-1. SSR vs CSR

- SSR :

과거에 작성된 대부분의 웹페이지는 SSR방식으로 만들어져 있다.

사용자가 브라우저를 통해 웹 페이지에 접근하면 서버를 통해 요청을하고 요청에 따라 서버는 DB에서 데이터를 가져오거나 통신등 백엔드 처리를 한 뒤 데이터를 노출시키는 형태로 동작되었다. (스프링을 해보셨다면 JSP가 어떻게 노출되는지 생각해보시면 됩니다!) 

대신 초기 로드속도가 빠르고, 검색엔진과 같은곳에 페이지 노출도 쉽다는 장점이 있다.

하지만 페이지를 이동하게 되면 모든 요소를 다시 렌더링하는 비효율적인 방식으로 동작한다.

(헤더, 푸터, 사이드가 공통적으로 작성된 페이지의 경우 해당 요소는 변경될 필요가 없지만 이동때마다 다시 그린다.)

 

- CSR :

모바일이나 패드같은 다양한 인터페이스들이 생기면서 다양한 화면에서 최적화된 페이지를 보여주기 위해 React, Vue와 같은 언어들이 탄생되었고, 이런 언어들은 CSR로 구성되어 동작합니다.

사용자가 페이지에 접근하면 프론트에 대한 리소스만 받아와서 페이지를 렌더링 하기 시작합니다.

데이터와 같은것을 제외한 페이지 관련된 모든것을 받아오기 때문에 초기 로드는 느리다는 단점이 있지만, 한번 페이지가 로드된 후에는 필요한 부분만 변경되는 형태로 구성되어 있기때문에 렌더링에 최적화가 되어있습니다.

 

 

2. 검색엔진 노출(SEO)

NextJS를 사용하게되면 검색엔진 최적화에 적합하여 내가 작성한 사이트를 관련된 키워드로 검색되었을 때, 상위로 노출시키기 좋습니다.

 

아래는 구글의 검색엔진 동작 방식의 흐름도입니다.

구글봇은 페이지를 크롤링 렌더링 대기열에 담아두고 robots.txt를 읽고 크롤링을 허용한 사이트인지 체크를합니다.

허용된 사이트라면 HTML을 파싱하여 구조를 파악하고 ... ...

 

자세한 내용은 아래URL을 참고해주세요. 

자세한 내용 : https://developers.google.com/search/docs/crawling-indexing/javascript/javascript-seo-basics?hl=ko 

 

자바스크립트 검색엔진 최적화의 기본사항 이해하기 | Google 검색 센터  |  문서  |  Google Develope

Google 검색에서 자바스크립트를 처리하는 방법을 알아보고 자바스크립트 웹 앱을 Google 검색에 최적화하기 위한 권장사항을 살펴보세요.

developers.google.com

 

위에서 언급한대로 리액트의 경우 CSR이며, 페이지에 사용자가 접근하기 전까진 생성되어 있는 노드나 데이터가 없습니다. 검색엔진 측면에서는 빈 페이지를 보기때문에 최적화된 데이터 처리가 어렵습니다.

 

 

3. Static Site Generator(SSG)

Static Site Generator는 정적인 HTML, CSS, Javascript파일을 생성하는 소프트웨어들을 말합니다.

정적인 파일을 생성해서 사용하기 때문에, 웹 서버의 보안에 유리하고, 브라우저에서 다운로드 속도가 빠릅니다.

NextJS로 작성한 페이지는 리액트로 구성하더라도 기본적인 HTML과 같은 기본적인 구조를 가지고 있기 때문에, 아무리 극한으로 느린 네트워크이더라도 페이지의 뼈대(마크업)정도는 보고 있을 수 있습니다.

 

 

# NestJS로 얻을 수 있는 이점

1. 정적인 페이지를 얻을 수 있다.(초기 로드 속도 최적화)

2. SEO에 유리하다.(검색엔진 노출)

3. 페이지 이동시 CSR로 동작하여 SPA장점을 가져갈 수 있다.

 

 

반응형
반응형

반응형으로 잘 처리해두고 깨지지 않는 것도 확인했는데, 특정 IPhone기종에서 몇몇 부분들만 뜬금없이 폰트가 커지게 되어서 UI가 깨지는 형상이 발견되었다.

(chrome, 안드로이드는 모두 괜찮았다...!)

 

body태그에 아래와 같이 한 줄을 추가하여 해결!

body {
    /* iphone 갑자기 폰트 크게 터지는 현상 방지용 */
    -webkit-text-size-adjust: 100%;
  }
반응형
반응형

firebase에 개행처리된 데이터를 <br />태그로 치환 처리하여 개행을 처리하고 싶었다.

firebase에 저장된 데이터에는 개행을 처리하고자 하는부분에 "\n" 문자열을 입력하였다.

 

받는부분에선 아래와 같이 처리하여 <br/>태그입력에 성공하였다.

{data.comments.split("\\n").map((p: string, idx: number) => {
    return (
      <span key={`${idx}`}>
        {p}
        <br />
      </span>
    );
})}

key값은 알아서 원하는 값으로 처리하면 될듯하고 split()을 통해 개행으로 구분한 문자열로 나누고 map으로 재조합을 처리해주었다.

 

원하는 형태로 개행처리가 되었다.

반응형
반응형

로컬의 ttf, woff, woff2등 웹 폰트를 적용하는 방법은 아래 글을 참고해주세요.

https://myhappyman.tistory.com/287

 

React - Style component font 적용방법 알아보기(typescript.ver)

리액트에서 styled components를 활용하여 전역 공통 css부분을 적용할 수가 있는데요. 이때 폰트를 적용하는 방법을 알아보고자 합니다. 프로젝트 로컬에 위치한 폰트 연결하기 먼저 프로젝트 내부

myhappyman.tistory.com

 

구글 폰트 적용하기

이번엔 로컬이 아닌 자주 사용하는 구글폰트를 연결하는 방법을 알아보겠습니다.

 

기존의 로컬방식으로 styled-component부분에 import를 하여 간단히 사용하면 될 것으로 생각하였으나, 적용시 아래와 같은 경고메시지와 폰트 적용이 되지 않는 모습을 볼 수 있습니다.

createGlobalStyle인 전역 스타일링 부분에서 import구문을 활용한 적용방식을 추천하지 않으며 react-helmet의 라이브러리를 통해 적용하는 것을 추천한다는 내용입니다.

 

React-Helmet을 통해 폰트 적용하기

react-helmet은 어떤 컴포넌트에서든 사용하게되면 최상단 header에 접근하고 수정하거나 추가하는것을 도와주는 라이브러리 입니다.

 

먼저 설치를 진행해줍니다.

npm install react-helmet

 

 

설치가 완료되면, 원하는 위치에 파일을 생성합니다.

저는 src하위에 바로 생성하였습니다.

 

- src/HelmetComponents.tsx

import React from "react";
import { Helmet } from "react-helmet";

function HelmetComponent() {
  return (
    <Helmet>
      <link rel="preconnect" href="https://fonts.googleapis.com" />
      <link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="" />
      <link
        href="https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap"
        rel="stylesheet"
      />
    </Helmet>
  );
}

export default HelmetComponent;

이후 컴포넌트 작성하는 방식과 동일하며 Helmet 내부에 원하는 header태그에 해당할만한 내용을 작성해주시면 됩니다.

 

style태그, meta, link, title등 다양한 속성들이 전부 적용이 됩니다.

여기선 구글에서 제공하는 Poppins 폰트 정보를 적용하였습니다.

 

작성이 완료되면 저장을 한 후, index.tsx에서 해당 컴포넌트를 호출하여 적용해주면 됩니다.

 

- src/index.tsx

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import HelmetComponent from "./HelmetComponent";

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);
root.render(
  <React.StrictMode>
  <RecoilRoot>
    <HelmetComponent />
    <App />
  </RecoilRoot>
  </React.StrictMode>
);

 

이것으로 준비는 끝입니다.

 

Global스타일링이나 원하는 위치에서 해당하는 구글 폰트를 font-family를 통해 적용시켜주면 끝입니다.

반응형
반응형

리액트에서 styled components를 활용하여 전역 공통 css부분을 적용할 수가 있는데요.

이때 폰트를 적용하는 방법을 알아보고자 합니다.

 

프로젝트 로컬에 위치한 폰트 연결하기

먼저 프로젝트 내부에 존재하는 ttf, woff, woff2등의 웹 폰트 파일을 연결하는 방법입니다.

 

1. 폰트 파일 준비

- src/assets/fonts/Pretendard 디렉토리에 원하는 파일들을 위치시켰습니다.

 

이후, 해당 파일을 import하여 전역 스타일링을 할 GlobalStyle에서 사용을 합니다.

 

2. 전역 스타일링 파일 GlobalStyle.ts

import { createGlobalStyle } from "styled-components";
import PretendardExtraLight from "./assets/fonts/Pretendard/PretendardExtraLight.woff2";
import PretendardRegular from "./assets/fonts/Pretendard/PretendardRegular.woff2";
import PretendardBold from "./assets/fonts/Pretendard/PretendardBold.woff2";
import PretendardExtraBold from "./assets/fonts/Pretendard/PretendardExtraBold.woff2";

const GlobalStyle = createGlobalStyle`
    @font-face {
        font-family: 'Pretendard';
        font-weight: 200;
        src: url(${PretendardExtraLight}) format('woff2');    
        unicode-range: U+AC00-D7A3;
    }

    @font-face {
        font-family: 'Pretendard';
        font-weight: 400;
        src: url(${PretendardRegular}) format('woff2');    
        unicode-range: U+AC00-D7A3;
    }

    @font-face {
        font-family: 'Pretendard';
        font-weight: 700;
        src: url(${PretendardBold}) format('woff2');    
        unicode-range: U+AC00-D7A3;
    }

    @font-face {
        font-family: 'Pretendard';
        font-weight: 800;
        src: url(${PretendardExtraBold}) format('woff2');    
        unicode-range: U+AC00-D7A3;
    }
    body {
    	font-family: 'Poppins', 'Pretendard', sans-serif;
    }
`;

export default GlobalStyle;

- src/GlobalStyle.ts

 

import를 통해 폰트 파일 위치의 woff2 파일들을 import하고 @font-face에 적용을 해줍니다.

저는 한글에만 pretendard가 동작하도록 unicode-range를 설정하였습니다.

여기서 그대로 따라하다보면 import부분에서 woff2확장자에 대해 알 수 없기에 오류가 발생할 것입니다.

typescript에게 woff2확장자에 대해 인식할 수 있도록 파일을 추가 생성합니다.

 

3. fonts.d.ts 생성

declare module "*.woff2";
declare module "*.ttf";
declare module "*.woff";

- src/fonts.d.ts

 

ttf, woff도 사용 할 수도 있기에 추가해두었습니다.

저장을 하면 import 오류부분이 사라지는 것을 볼 수 있습니다.

 

4. GlobalStyle.ts 적용하기

최상단 컴포넌트인 index.tsx또는 App.tsx부분에 적용을 해주면 폰트가 바로 적용되는 것을 확인 할 수 있습니다.

import React from "react";
import styled, { ThemeProvider } from "styled-components";
import GlobalStyle from "./GlobalStyle";
function App() {

  return (
    <ThemeProvider theme={"mars"}>
      <GlobalStyle />      
    </ThemeProvider>
  );
}

export default App;

- src/App.tsx

반응형