정적(Static)과 동적(Dynamic)

 - 정적(Static): 고정된 내용을 가지고 있어 변하지 않습니다.

웹 페이지의 경우, HTML, CSS, JavaScript 등의 파일이 변경되지 않고 고정된 형태로 서버에 의해 제공됩니다. 

정적인 웹 사이트의 예시는 블로그 포스트, 회사 소개 페이지 등이 있습니다. 웹 페이지가 항상 동일한 내용을 보여줍니다. 

 

 - 동적(Dynamic): 변경 가능한 내용을 가지고 있습니다. 즉, 내용이나 데이터가 시간에 따라 변할 수 있습니다. 

서버에서 동적으로 생성되는 콘텐츠를 가지고 있으며, 사용자와의 상호작용에 따라 콘텐츠가 변경될 수 있습니다. 

동적인 웹 사이트의 예시는 온라인 쇼핑몰, 소셜 미디어 피드 등이 있습니다. 사용자에 따라 다른 콘텐츠를 제공할 수 있습니다.

 

1. pre-render와 SEO의 상관관계

SEO : 검색엔진최적화, 검색엔진이 내 페이지를 상위 노출할 수 있게 만드는것.

 

설명하기전 pre-render에 대해 이해하고 넘어가겠습니다.

 

1-1. pre-render (Next.js 를 사용할 경우)

Next.js는 모든 페이지를 기본적으로 pre-render한다.!

Pre-render를 해두면 client(브라우저)처럼 동작하지 않는 검색엔진에게 필요한 데이터를 제공 할 수 있습니다

(Pre-render : client 에서 접근해 HTML을 로드할 때 대부분이 미리 로드가 되어있는것)

 

이후에 Hydration 과정을 거쳐 사용자와 페이지가 인터렉션 할 수 있게 됩니다.

 

1-2. No pre-render(React.js 만 사용할 경우)

자바스크립트가 로드가 된 후에 컴포넌트를 그리기 때문에 브라우저처럼 동작하지 않는 검색엔진의 경우

js를 해석하지 못해 아무 정보도 가져갈 수 없게 되는 것입니다.

 

CSR만 제공한다면 client(브라우저)처럼 동작하지 않는 검색엔진의 경우, 아무런 데이터도 조회해갈 수 없습니다.

 

Next.js를 통해 SSR을 하면 js를 실행하지 못하는 엔진 또한 pre-render를 통해 정보를 읽어갈 수 있습니다.

즉 Client 처럼 동작하지 않는 검색엔진에게 필요한 데이터를 제공 할 수 있습니다.

 

2. Next.js 의 Pre-render 방식은?

SSG(recommended) & SSR

SSG는 빌드 타임에, SSR은 요청 타임에 pre-render를 하게 됩니다.

(SSG 권장 SSG는 접근을 하더라도 부하가 발생하지 않음, SSR은 접근 할때마다 부하가 발생..)

 

2-1. SSG에 대해서.

  1. 페이지가 외부 데이터에 의존적인 경우
    getStaticProps를 사용
  2. 페이지의 경로까지 외부 데이터에 의존적인 경우
    getStaticProps에 더해  getStaticPaths까지 활용해야함

 

 

SSR 을 담당하는 함수

 

 1-1. getServerSideProps(SSR)

 

console.log가 찍히지 않은걸 볼 수 있습니다.

서버에서 찍히고 있습니다.

 

즉  getServerSideProps 는 서버로부터 데이터를 가져와 화면에 보여준다는걸 알 수 있습니다.


 1-2. getStaticPaths (SSG)

 

서버에서 동작하는게 보입니다.

 

저는 지금 yarn dev로 개발환경으로 보고있습니다.

 

개발 환경에서는 SSG가 재대로 동작하지 않고 SSR처럼 동작을합니다

 

이를 재대로 확인하기 위해서는 build과정이 필요합니다.

 

빌드 후 yarn start로 실행했습니다.

 

ssg도 client도 로그에 뜨지않습니다

 

새로고침을 해도 시간은 계속 고정입니다.

 

 

기존 패이지는 새로고침시 시간이 바뀝니다.(SSR)

 

 

csr의 페이지

여기 또한 새로고침시 시간이 바뀝니다.

 

SSG는 결국 build시 page가 미리 만들어집니다.

build 기준의 시간으로 만들어지는겁니다.

 

이건.. 언제 쓰이는걸까요.?

 

SSG는 정적인 페이지를 생성합니다.

 

매번 사용자가 접근시 데이터를 가져와서 페이지를 그린다면, 서버에 부하가 생깁니다.

 

이때 데이터를 가져와서 그릴 필요가 없으며, 사이드바, 메뉴 처럼 갱신이 필요하지 않는 경우 미리 만들어두고 가져올 때 사용합니다.

 


1-3 ISR( incremental Static Regeneration : 증분 정적 사이트)

 

특정 주기로 데이터를 가져와서 다시 그린다.

 

정적인 사이트를 일정 주기로 가져와서 다시 그리는 것입니다.

 

 

getStaticProps에서 revalidate가 추가되었습니다

위의 코드에서는 1이라는 값이 revalidate에 들어가 있습니다.

 

getStaticProps에서 revalidate를 return 하면 

 

1초간의 캐싱을 가지며 그 사이에서는 아무리 새로고침을 해도 데이터를 가져와 새로운 정적 사이트를 만들지는 않습니다.

 

ISR로 만들면 SSG와 SSR의 장점을 적절하게 사용이 가능해집니다!

 

예를들어 1시간의 텀으로 만들경우 그 사이에 누가 접속해도 요청은 보내지 않습니다.

 

1시간의 텀이 지나고 누군가가 접속시 요청을 시작하며, 그 텀이 지난 후에도 접속을 하지 않는다면 갱신을 하지 않습니다.

 

서버에 부담을 주지 않는 효율적인 페이지라고 생각됩니다.

 

 

 

 

 

 

2. CSR을 담당하는 함수

CSR을 담당하는 는 별도로 존재하지 않습니다.

 

 

 

데이터를 클라이언트가 가져와서 그리기 때문에 서버가 아닌 콘솔창에 로그가 찍혀있습니다.

1. 왜 Next.js를 사용하나요.?

  •  SEO(검색 엔진 최적화)
  •  손쉬운 배포 시스템 Vercel
  •  간단한 API 구성
  •  대체재로는 Gatsby / Remix

 

 

2. Next.js 환경설정


- 제 기준의 Node와 Yarn의 버전입니다.

  • Node 18.12.1
  • Yarn 1.22.19 
  • Git 환경
  • VScode

 

HTML 안에서 CSS 스타일을 만들 수 있게 해주는 CSS 프레임 워크 입니다.

 

 

Tailwind CSS 의 장점 

  1. 빠른 스타일링이 가능합니다.
  2. class 혹은 id 명을 작성하기 위한 고생을 하지 않아도 됩니다.
  3. 유틸리티 클래스가 익숙해지는 시간이 필요할 수 있지만 intelliSense플러그인이 제공돼서 금방 익숙해질 수 있습니다.

Tailwind CSS intelliSense

 

Tailwind 기본설정 

  • tailwind.config.js

tailwind를 사용할 파일들이 있는 위치 및 확장자명

 - content 안에는 우리가 tailwind를 사용할 파일들을 지정해줍니다
    ./src 폴더안의  **(모든폴더) *.{js,jsx,ts,tsx} (파일 및 확장자명)

  • index.css 설정

 - root css 폴더에 아래의 구문 추가

 

Tailwind 테스트

Hello world!에 밑줄이 잘 들어가 있습니다!

공부중에 정규식이 나와서 정리 해봤습니다.

 

전체적인 내용이 아닙니다.

export const formatNumber = (num) => {
  // 숫자가 3자리 이상 있을경우 , 를 붙이기
  num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,");
};

 

1. \d 는 Digit, 0~9까지의 숫자를 매치해줍니다.

 

2. \w 는 모든 문자(숫자포함) 매치해줍니다.

 

3. {num}  :  일치하는 num의 개수만큼 매칭

    예시 : \d{4}  숫자중 4개씩 매칭, 4개가 넘어갈경우 앞에서부터 4개 ( 예시 12345)

\w도 똑같습니다.

 

 

4. {num1, num2}  : num1 부터 num2 까지의 개수만큼 매칭

3개 4개 5개를 찾아 매칭해줍니다.

 

특정 단어로 시작하며 뒤에 숫자가 2~4개 붙은경우

특정 단어로 시작하며 (숫자,문자)가 2~4개 붙은경우

 

5. Negative lookahead

\d(숫자)뒤에 (?!px)  px가 붙지 않은 숫자!

 

6. Positive lookahead

\d(숫자)뒤에 (?=px)  px가 붙은 숫자!

7. 섞어서 사용해보기

 

 7-1 \d{3} 숫자 3개를 찾는데 ?!\d 뒤에 숫자가 없는 경우 

 

 

7-2 뒤에 숫자가없는 3개의 숫자를 찾아라 (여러개)

 (위와 거의 같지만 가운대에 +가 있습니다.)

 +를 사용해서 1개 이상을 매칭시키려고함(여러개를 찾고자 할 때)

 1234567890 처럼 붙어있어도 1 234 567 890 과 같이 잡혀있습니다.

 (추측이지만, 890 을 찾고 그걸 제외한 1234567 에서 567을 찾고 또 제외하고 1234에서 234를 찾는것 같습니다)

 즉 이미 매칭된 것은 제외하고 찾는 것 같습니다.

 

 

 7-3  뒤에 숫자가 없는 3자리숫자의  의 숫자

  7-1의 (\d{3})(?!\d)은 뒤에 숫자가 없는 3개의 숫자 (890) , 이걸 이용해서

   \d(?=(\d{3})(?!\d)) , 그 숫자를 뒤에 포함한 숫자 \d(?=890)을 뒤에 둔 숫자

 

 

 

 

위의 지문을 다 이해하고 나서 보면

export const formatNumber = (num) => {
  // 숫자가 3자리 이상 있을경우 , 를 붙이기
  num.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,");
};

\d 숫자를 찾는다

?= 뒤의 조건을 만족하는걸 

(\d{3}) 숫자가3개

+ 여러개를 찾는다

(?!\d) 숫자가 없다

/g 전체에서

 

합쳐보면

\d(?=(\d{3})+(?!\d)) 뒤에 숫자가 없는 3개의 숫자의 앞의 숫자 (말이 이상하다..) 를 여러개 찾는다.

 

내가 정리 해놓고도 이상하다..

 

뭐,.. 나만 이해하면 된 건가

useWindowSize

 - 윈도우의 크기가 변경될 때마다 윈도우의 너비와 높이를 가져오는 커스텀 훅입니다.

import { useState, useEffect } from "react";

export default function useWindowSize() {
  const [windowSize, setWindowSize] = useState({
    width: undefined,
    height: undefined,
  });

  useEffect(() => {
    const handleResize = () => {
      setWindowSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    };
    window.addEventListener("resize", handleResize);
    handleResize();

    return () => {
      window.removeEventListener("resize", handleResize);
    };
  }, []);

  return windowSize;
}

 

<html>

<head>
  <meta charset="UTF-8">
  <title>출력결과</title>
</head>
<!-- 각 행의 합, 각 열의 합
그리고 두 대각선의 합 중 가장 큰 합을 출력하시오 -->

<body>
  <script>
    let arr =
      [
        [10, 13, 10, 12, 15],
        [12, 39, 30, 23, 11],
        [11, 25, 50, 53, 15],
        [19, 27, 29, 37, 27],
        [19, 13, 30, 13, 19]
      ];
    function solution(arr) {
      let answer = Number.MIN_SAFE_INTEGER;
      let sum1 = sum2 = sum3 = sum4 = 0;
      for (let i = 0; i < arr.length; i++) {
        sum1 = sum2 = 0;
        for (let j = 0; j < arr.length; j++) {
          sum1 += arr[i][j];
          sum2 += arr[j][i];
        }
        sum3 += arr[i][i];
        sum4 += arr[(arr.length - 1) - i][i];
        answer = Math.max(answer, sum1, sum2, sum3, sum4);
        console.log(`${i + 1}번째 행의 합 : ${sum1},  ${i + 1}번째 열의 합 : ${sum2}`);
      }
      console.log(`대각선의 합 [0][0] ~[4][4] : ${sum3}`)
      console.log(`대각선의 합2 [0][4] ~ [4][0] : ${sum4}`);
      return `가장 큰 수 : ${answer} `;
    }

    function solution2(arr) {
      let answer = Number.MIN_SAFE_INTEGER;
      let sum1 = sum2 = sum3 = sum4 = 0;
      for (let i = 0; i < arr.length; i++) {
        sum1 = sum2 = 0;
        for (let j = 0; j < arr.length; j++) {
          sum1 += arr[i][j];
          sum2 += arr[j][i];
        }
        console.log(`${i + 1}번째 행의 합 : ${sum1},  ${i + 1}번째 열의 합 : ${sum2}`);
        answer = Math.max(answer, sum1, sum2);
      }
      for (let i = 0; i < arr.length; i++) {
        sum3 += arr[i][i];
        sum4 += arr[i][(arr.length - 1) - i];
        answer = Math.max(answer, sum3, sum4);
      }
      console.log(`대각선의 합 [0][0] ~[4][4] : ${sum3}`)
      console.log(`대각선의 합2 [0][4] ~ [4][0] : ${sum4}`);
      return `가장 큰 수 : ${answer} `;
    }
    console.log(solution2(arr));
  </script>
</body>

</html>

음... 억지로 for문 따로 안쓰게 만들어 봤는데..
저러면 sum3, sum4가 누적되기 전부터 Math.max가 들어가서.. 좀..

<html>

<head>
  <meta charset="UTF-8">
  <title>출력결과</title>
</head>
<!-- O 는 1점 , X 는 0점 
  연속해서 맞출경우 +1점
-->
<body>
  <script>
    function solution(arr) {
      let answer = 0;
      let count = 0;
      for(let i=0; i<arr.length; i++){
        if(arr[i] === 'O'){
          cnt++;
          answer += cnt
        }
        else cnt = 0;
      }
      return answer;
    }

    let arr = ['O', 'O', 'X', 'O', 'X', 'X', 'O', 'O', 'O', 'X'];
    console.log(solution(arr));
  </script>
</body>

</html>
<html>

<head>
    <meta charset="UTF-8">
    <title>출력결과</title>
</head>

<!-- 가위 = 1 , 바위 = 2 , 보 = 3 -->
<!-- 승리시 A or B, 비기는 경우 D -->

<body>
    <script>

        const HandType = {
            ROCK: 1,
            SCISSORS: 2,
            PAPER: 3
        };

        const Result = {
            DRAW: 'D',
            PLAYER_A: 'A',
            PLAYER_B: 'B'
        };

        let a = [2, 3, 3, 1, 3];
        let b = [1, 1, 2, 2, 3];

        function solution(a, b) {
            let answer = "";
            for (let i = 0; i < a.length; i++) {
                if (a[i] === b[i]) answer += Result.DRAW + " ";
                else if ((a[i] === 1) && (b[i] === 3)) answer += Result.PLAYER_A + " ";
                else if ((a[i] === 2) && (b[i] === 1)) answer += Result.PLAYER_A + " ";
                else if ((a[i] === 3) && (b[i] === 2)) answer += Result.PLAYER_A + " ";
                else answer += Result.PLAYER_B + ' ';
            }
            return answer;
        }



        function solution2(a, b) {
            const result = a.map((value, index) => {
                if (value === b[index]) {
                    return Result.DRAW;
                }
                switch (value) {
                    case HandType.ROCK:
                        switch (b[index]) {
                            case 3:
                                return Result.PLAYER_A;
                            case 2:
                                return Result.PLAYER_B;
                            default:
                                return '';
                        }
                    case HandType.SCISSORS:
                        switch (b[index]) {
                            case 3:
                                return Result.PLAYER_B;
                            case 1:
                                return Result.PLAYER_A;
                            default:
                                return '';
                        }
                    case HandType.PAPER:
                        switch (b[index]) {
                            case 1:
                                return Result.PLAYER_B;
                            case 2:
                                return Result.PLAYER_A;
                            default:
                                return '';
                        }
                    default:
                        return '';
                }
            });
            return result.join(' ');
        }


        console.log(solution(a, b));
    </script>
</body>

</html>

솔루션 2는 내가 뭘 한거지..

 

<html>

<head>
  <meta charset="UTF-8">
  <title>출력결과</title>
</head>

<!-- 자신의 앞 수보다 큰 수만 출력하기 -->

<body>
  <script>
      let arr = [7, 3, 9, 5, 6, 12];
      function solution(arr) {
        let answer = [arr[0]];
        for(let i=1; i<arr.length; i++){
          if(arr[i-1] < arr[i]) answer.push(arr[i]);
        }
        return answer;
      }

    console.log(solution(arr));
  </script>
</body>

</html>
<html>

<head>
  <meta charset="UTF-8">
  <title>출력결과</title>
</head>
<!-- 학생의 키가 주어질 때, 앞에 있는 사람들보다 크면 보이고 작거나 같으면 보이지 않습니다  -->

<body>
  <script>
    function solution(arr) {
      let answer = 0;
      let max = 0;
      for (let student of arr) {
        if (max < student) {
          max = student;
          answer++;
        }
      }
      return answer;
    }

    let arr = [130, 135, 148, 140, 145, 150, 150, 153];
    console.log(solution(arr));
  </script>
</body>

</html>

+ Recent posts