[공식문서 보는 방법]

1. 왜 써야하는지?

2. Getting Started 훝어보기 (기능을 보면서 큰그림을 보기 => 외울 필요는 없다)

3. 프로젝트에서 참고한다.

 

 

> 왜 써야하는가?

SPA 장점을 활용하면서 History 사용하기 위해서 React-router 를 사용한다.

> Getting Started

중첩경로 (레이아웃), 로더(데이터 로딩), NavLink 의 활성 링크, action?, redirect, defer, 낙관적 UI

 

> Project

 

App.jsx

import { createBrowserRouter, RouterProvider } from "react-router-dom";
import Home from "./pages/Home";
import NotFound from "./pages/NotFound";
import Videos from "./pages/Videos";
import Root from "./pages/Root";
import VideoDetail from "./pages/VideoDetail";

const router = createBrowserRouter([
  {
    path: "/",
    element: <Root />,
    errorElement: <NotFound />, // 에러페이지
    children: [
      {
        index: true,
        element: <Home />,
      },
      {
        path: "/videos",
        element: <Videos />,
      },
      {
        path: "/videos/:videoId",
        element: <VideoDetail />,
      },
    ],
  },
]);

function App() {
  return <RouterProvider router={router} />;
}

export default App;

 

Root.jsx  => Outlet

import React from "react";
import { Outlet } from "react-router-dom";
import Navbar from "../components/Navbar";

const Root = () => {
  return (
    <div>
      <Navbar />
      <Outlet />
    </div>
  );
};

export default Root;

 

Navbar.jsx  => Link

import React from "react";
import { Link } from "react-router-dom";

const Navbar = () => {
  return (
    <nav>
      <Link to="/">Home</Link>
      <Link to="/videos">Videos</Link>
    </nav>
  );
};

export default Navbar;

 

Videos.jsx  => useNavigate

import React, { useState } from "react";
import { useNavigate } from "react-router-dom";

const Videos = () => {
  const [text, setText] = useState();
  const navigate = useNavigate();
  const handleChange = (e) => {
    const value = e.currentTarget.value;
    setText(value);
  };
  const handleSubmit = (e) => {
    e.preventDefault();
    navigate(`/videos/${text}`);
    setText("");
  };
  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input type="text" placeholder="video id: " value={text} onChange={handleChange} />
      </form>
    </div>
  );
};

export default Videos;

 

VideoDetail.jsx  ==> useParams

import React from "react";
import { useParams } from "react-router-dom";

const VideoDetail = () => {
  const { videoId } = useParams();

  return <div>VideoDetail {videoId}</div>;
};

export default VideoDetail;

 

반응형

'Frontend' 카테고리의 다른 글

RTK Query 란?  (0) 2023.04.13
[Vue3] Vue + Vite + Typescript 초기세팅  (0) 2023.03.23

Singleton pattern (생성)
=> 단하나의 객체 인스턴스만 존재

=> 스태틱 함수로 전역으로 객체 접근 



Factory pattern (생성)
=> fetching하고 map 함수로 동적으로 생성할때 사용한다.
하나의 인터페이스로 여러가지 오브젝트를 생성한다 (동적환경에 최적화) 

<sample>
1. 신발 클래스를 만든다.
2. 신발을 상속받는 나이키, 퓨마 등의 클래스를 만든다.
3. 신발공장 클래스의 변수로 나이키, 퓨마 클래스를 담아줌 (위임받음) 
4. 신발공장의 create 매소드로 매개변수를 받아서 생성함 
(이때 매개변수 체크 필요, 조건로직)
5. map 함수를 이용해서 여러 아이템들을 factory.create 가능하다. 


Observer pattern (행동)
=> 한 객체의 상태가 바뀌면 다른 구독 객체들에게 상태와 변경을 알려준다. 
여기서는 구독이라는 개념을 사용하고, 폴링 개념보다 효율적이다.

 

 

Facade Pattern (구조)

=> 간략화된 인터페이스로 직접적인 접근을 제약한다.

=> 다수의 서브클래스나 인터페이스 등을 한 클래스 내에서 관리할 수 있다.

사용자가 메뉴를 주문할때 주문에 관한 처리과정을 알 필요가 없다.

키친클래스 - 음식서비스 클래스 - 레스토랑퍼사드 클래스 (클라이언트와 인터페이스)

 

 

Command Pattern (행동)

=> 명령을 캡슐화해서 처리한다. 

구성: 명령 Command / 수신자 Receiver / 발동자 Invoker / 클라이언트 Client

 

클라이언트(은행창구): 명령 생성

수신자(계좌): 명령이 전해졌을때 기능을 수행하고 반영한다.

발동자(은행시스템): 실행업무를 전달 받을 시 직접 Command 를 호출하고 도와준다.

명령(입출금, 이체): 미리 약속된 인터페이스를 구현해서 Invoker 에서 받은 명령을 Receiver에 전달한다.

                              (전달을 어떤방법으로 할지의 비즈니스 로직 담당)

1. command 생성

2. receiver 생성

3. invoker 인스턴스 & receiver 등록

4. command 등록

5. command 지시

 

Proxy Pattern (구조)

=> Proxy 를 통해 대신 접근한다. (실제객체와 클라이언트 사이에 존재)

클라이언트가 특정 객체에 접근해야하는데 비즈니스 로직상 추가적인 검사가 필요할 경우 (ex.접근권한)

원격객체에 데이터를 요청할때 proxy 객체에 caching / logging 로직을 추가한다.

체크 카드와 같은 예시가 프록시라고 할 수 있다.

 

구성: Client, Subject 인터페이스, Proxy(실제객체의 인스턴스, 핸들러), Real Subject -Subject의 구현체

 

Adapter Pattern (구조)

=> 서로 호환성 없는 인터페이스/클래스 들을 연결시켜야 할 경우 사용, 레거시 시스템 확장할때 사용

 

구성: 클라이언트, 인터페이스, 서비스/외부요소, 어댑터

 

 

 

Reference:

https://www.youtube.com/watch?v=RNE1zfECaac&list=PL3xNAKVIm80JldJ6IZBx5eQxck5JA6VuV&index=4&t=82s

 

 

반응형

'CS' 카테고리의 다른 글

React, Vue, Angular 의 차이  (0) 2023.04.04
SEO 란?  (0) 2023.03.29
SSR vs CSR vs SSG (페이지 렌더링 방식)  (1) 2023.03.29
NVL NVL2 ISNULL NULLIF COALESCE 비교  (1) 2023.03.14
  • RTK 쿼리란 무엇이며 어떤 문제를 해결합니까?
  • RTK 쿼리에 포함된 API
  • 기본 RTK 쿼리 사용

기존:

- 보여줄 부분은 빠르게 보여줘야함

- 로드 상태 추적 필요 (로딩중...)

- 동일한 데이터 중복 요청 방지

- 캐시 수명 관리

 

Redux:

- 로드상태 추적에 효율적

- 요청 생명주기에 따라 Dispatch 

- Redux Toolkit의 createAsyncThunkAPI 는 위 2가지를 추상화

- But, 로딩상태 또는 캐시된 데이터 관리가 어려움

=> React 커뮤니티에서는 데이터 패칭 및 캐싱상태관리와 다른 관심사로 여겨짐

 

 

RTK Query ?

Redux Toolkit 패키지에 포함된 데이터 캐싱 도구

 

[언제 RTK-Query 를 사용해야할까?]

- Redux 앱이 이미 있고 기존 데이터 패칭 로직을 ​​단순화하고 싶을때
- Redux DevTools 를 사용하여 상태 변경 기록을 보고싶을때
- React 외부에서 앱의 로직을 작동하고 싶을때

 

Apollo Client, React Query, Urql, SWR 등 에서 API 디자인에 고유한 접근 방식을 추가하였다.

다른 Tool 들과의 비교

 

 

[RTK Query 의 특징]

- 데이터 패칭 및 캐싱 논리는 Redux Toolkit 의 createSlicecreateAsyncThunk API 에서 구축된다.

- UI에 구애받지 않는다. => 모든 UI 레이어에서 사용 가능

- API 엔드포인트는 arguments 로부터 쿼리 query parameters 를 생성하고
   캐싱을 위해 응답을 변환하는 방법을 포함하여 미리 정의된다.

- 아래 3가지의 리액트훅을 생성할 수 있다.
   전체 데이터 패칭 프로세스를 캡슐화
   data 와 isLoading 구성요소를 제공
   mount / unmount 시 데이터 생명주기 관리

- initial data fetching 후 websocket 메시지를 통해 캐시 업데이트를 스트리밍하는 것과 같게 하는 cache entry lifecycle 옵션 제공

- TypeScript 로 작성됨

 

 

[포함된 API]

- createApi() : RTK 쿼리 기능의 핵심으로, endpoint 집합이라고 할 수 있다. 기본 URL 당 하나의 API 슬라이스 원칙으로 한다.

- fetchBaseQuery() : fetch 요청을 단순화하기 위한 작은 래퍼, createApi 에서 baseQuery 를 권장한다.

- <ApiProvider /> : Redux store 의 provider 가 없는 경우에 (대신) 사용할 수 있다.

- setupListeners() : RefetchOnMount 및 RefetchOnReconnect 동작을 사용하도록 설정하는데 사용되는 유틸리티

 

[번들 사이즈에 관하여..]

  • If you are using RTK already: ~9kb for RTK Query and ~2kb for the hooks.
  • If you are not using RTK already:
    • Without React: 17 kB for RTK+dependencies+RTK Query
    • With React: 19kB + React-Redux, which is a peer dependency

 

[RTK QUery 사용법]

1. createApi 를 import 하는 2가지 방법

import { createApi } from '@reduxjs/toolkit/query'

/* React-specific entry point that automatically generates
   hooks corresponding to the defined endpoints */
import { createApi } from '@reduxjs/toolkit/query/react'

 

2. createApi 의 사용

import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
import type { Pokemon } from './types'

// base URL 과 엔드포인트들로 서비스를 정의한다.
export const pokemonApi = createApi({
  reducerPath: 'pokemonApi',
  baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }),
  endpoints: (builder) => ({
    getPokemonByName: builder.query<Pokemon, string>({
      query: (name) => `pokemon/${name}`,
    }),
  }),
})

// 정의된 엔드포인트들을 기반으로 export (use_____Query)
export const { useGetPokemonByNameQuery } = pokemonApi

 

3. Store 의 구성

import { configureStore } from '@reduxjs/toolkit'
import { setupListeners } from '@reduxjs/toolkit/query'
import { pokemonApi } from './services/pokemon'

export const store = configureStore({
  reducer: {
    // 생성된 리듀서를 최상위 레벨의 구체적인 슬라이스로 추가한다.
    [pokemonApi.reducerPath]: pokemonApi.reducer,
  },
  // 미들웨어를 추가하면 캐싱, 무효화, 폴링 등 사용 가능
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(pokemonApi.middleware),
})

// Optional
// refetchOnFocus/refetchOnReconnect 동작에 필요한 경우 'setupListeners' 문서 참조 (두번째 arg에 콜백함수)
setupListeners(store.dispatch)

 

4. react-redux 의 Provider 사용

import React from "react";
import ReactDOM from "react-dom/client";
import { Provider } from "react-redux";
import { store } from "./store";
import App from "./App";

const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

* Provider 나 ApiProvider 중에 하나만 사용해야한다. (충돌 위험)

ApiProvider 사용법에 대한 공식문서

 

 

5. 컴포넌트에서의 Hook 사용

import * as React from 'react'
import { useGetPokemonByNameQuery } from './services/pokemon'

export default function App() {
  // 1번 방법: 쿼리 훅을 사용해 자동으로 데이터를 가져오고 쿼리 값을 반환
  const { data, error, isLoading } = useGetPokemonByNameQuery('bulbasaur')
  
  // 2번 방법: 생성된 엔드포인트 아래의 개별 훅에 액세스할 수도 있다
  // const { data, error, isLoading } = pokemonApi.endpoints.getPokemonByName.useQuery('bulbasaur')
  
  // data 와 loading 을 기반으로 UI 를 렌더한다.
}

 

 

 

 

Reference:

https://redux-toolkit.js.org/rtk-query/overview#configure-the-store

 

 

 

 

 

 

 

반응형

'Frontend' 카테고리의 다른 글

React Router  (0) 2023.04.17
[Vue3] Vue + Vite + Typescript 초기세팅  (0) 2023.03.23

 

웹 애플리케이션의 구조가 복잡해지면서 복잡도가 올라가기 시작하였다.

쉽게 웹을 만들고 유지보수를 더 간편하게 할 수 있는 방법에 대한 연구들이 많았고,

다양한 프론트엔드 프레임워크나 라이브러리가 탄생하게 되었다.

 

<선행 개념>

프레임워크 : 제어 흐름이 프레임워크에 있다. (제어의 역흐름 (IoC : Inversion of Control))
라이브러리 : 제어 흐름이 사용자에게 있다.

 

앵귤러와 뷰는 자신들만의 문법을 가지고 웹 개발을 할 때 필요한 모든 기능과 툴을 포함하고 있는 프레임워크라고 할 수 있다.

리액트는 UI 를 만드는 기능만을 제공하기 때문에 라이브러리라고 할 수 있다.

(라이브러리이기 때문에 리액트 자체만으로는 전역 상태 관리, 라우팅, 빌드 시스템 등을 지원하지 않는다.

때문에 리액트는 별도의 라이브러리를 통해 Redux, Recoil, React-router-dom 등을 사용해야 한다.)

 

상태 : 프론트엔드에서 상태란 주로 UI에 영향을 미치는 동적으로 표현되는 데이터이다. (로컬 상태, 전역상태가 있음)

 

 

Jquery

JavaScript를 보다 간편하고 빠르게 DOM을 변경할 수 있는 프론트엔드 라이브러리.

Jquery 는 일반 Javascript 보다 DOM 요소를 간단하게 제어할 수 있어 많은 인기가 있었다.

하지만 DOM 에 데이터를 관리하고 있기 때문에 관리하기 위해서는 DOM으로 직접 접근을 해야했으며

데이터에 대한 추적 및 관리가 어려웠고, DOM 요소를 중심으로 코드가 작성되어 DOM을 직접 조작하는 방식에서 벗어나지 못했다.

 

 

Angular

Google에서 개발한 프론트엔드 MVC 프레임워크 (AngularJS > Angular 로의 버전관련 설명 생략)

화면상에 보여지는 데이터(View)와 브라우저 메모리에 있는 데이터(Model)를 묶어서(Binding) 

데이터를 동기화하는 것을 양방향 바인딩이라고하는데

Angular 에서의 양방향 바인딩이라는 개념은 개발자들에게 큰 인기를 얻을 수 있었다.
하지만 규모가 커질 수록 복잡성이 증가해지면서 굉장히 느려진다는 치명적인 단점이 발생하게 되었다.

 

React

JSX 라고 불리는 JavaScript를 확장한 문법을 제공하는 컴포넌트로 이루어진 프론트엔드 UI 라이브러리

JSX 를 통해 자바스크립트 안에서 html 역할을 하는 코드를 사용한다.

자바스크립트 코드에서 CSS를 작성하는 방식인 CSS-IN-JS 방식을 사용하기도 하고, css 파일을 분리해서 사용하기도 한다.

따라서 대부분 JavaScript만으로 UI 로직과 DOM을 구현한다. 

또한 JavaScript에 가깝기 때문에 camelCase 프로퍼티 명명 규칙 사용한다.

 

가장 핵심이 되는 부분은 Virtual DOM 이다.

기존에는 DOM에 변화가 발생할 때 CSS 재연산, 레이아웃 재구성, 페이지를 다시 칠하게 되는데 이 과정에서 많은 시간이 허비된다.

Virtual DOM 은 컴포넌트(props, state)의 변동사항이 생길때 실질적으로 어떤 부분이 업데이트 돼야 하는지 계산을 한 다음

필요한 해당 컴포넌트 및 하위 컴포넌트를 DOM Tree 에 업데이트 한다.

React Hook 에서는 useEffect를 통해 Lifecycle 을 관리한다.

 

사용자가 조금 더 부드럽게 웹 어플리케이션을 이용하기위해 60 frames per seconds (60 fps) 를 유지해야 하는데,

리액트는 60fps 를 유지할 수 있는 방법이 보장되지만

Virtual DOM을 사용한다고 해서 사용하지 않을 때와 비교하여 무조건 빠른 것은 아니므로

지속적으로 데이터가 변화하는 대규모 애플리케이션 구축을 할때 사용을 권장한다.

 

그리고 React는 단방향 데이터 바인딩(모델이 변경될 때 뷰가 변경되지만, 뷰는 모델을 변경시키지 않는 구조)을 사용함으로써

데이터의 흐름을 명확히 알 수 있고 예측 가능하여 양방향 바인딩을 사용하지 않는 편이다.

 

 

Vue

양방향 바인딩과 Virtual DOM 이 가능한 UI 구축을 위한 Javascript 프레임워크

HTML을 그대로 사용할 수 있고, 프레임워크이기 때문에 비교적 코드 스타일이 획일화되어있기 때문에 다른 사람 코드 이해에 부담이 적다.

Vue 는 프레임워크이기 때문에 프레임워크 안으로 들어가서 프레임 워크가 지원해주는 문법에 따라 작성해주어야 한다.

그렇기 때문에 라이브러리와 달리 더 많은 기능을 디폴트로 제공해준다.

자유도가 낮기 때문에 오히려 쉽게 익힐 수 있다.

 

 

 

 

 

개인적으로는 높은 자유도와 커다란 시장 크기, 변화에 빠른 점에서 React 가 메리트가 있다고 생각한다.

 

반응형

'CS' 카테고리의 다른 글

Javascript Design Pattern Summary  (0) 2023.04.13
SEO 란?  (0) 2023.03.29
SSR vs CSR vs SSG (페이지 렌더링 방식)  (1) 2023.03.29
NVL NVL2 ISNULL NULLIF COALESCE 비교  (1) 2023.03.14

 

SEO (Search Engine Optimization)

검색 엔진이 쉽게 이해할 수 있는 형태로 웹페이지를 구성하는 과정이다.
검색 엔진 최적화가 되어있으면 검색 엔진에서 상위에 노출될 수 있다.

 

 

이전 글에서 페이지 렌더링 방식을 비교해 가면서 

SPA의 렌더링 방식인 CSR 사용 시 단점으로 Low SEO 가 될 수 있다고 하였다.

 

SSR vs CSR vs SSG (페이지 렌더링 방식)

Overview 기존에는 Static Sites 였다. 사용자가 주소에 접속하면 서버에 배포되어있는 HTML 문서들을 받아와서 보여준다. 다른 링크를 클릭하면 다시 서버에서 해당하는 페이지의 HTML 을 요청하고 받

jieun-c.tistory.com

 

 

기본적으로 검색 엔진 최적화가 필요한 웹사이트는

SSR 방식(React의 Next.js, Vue의 Nuxt, Angular의 Angular Universal)으로 구축하지만,

CSR 을 사용하면서 검색엔진도 최적화시킬 수 있는 방법은 없을까?

 

 

방법 1) 동적 렌더링 / Pre-rendering (사전렌더링)

동적 렌더링이란 동적 렌더기(예: Puppeteer, Rendertron 또는 prerender.io)를 설치하고 구성하여

요청 주체가 사람이면 기존처럼 빈 HTML 과 소스코드들을 제공하고,

요청 주체가 검색엔진(크롤러)이면 서버에서 사전에 렌더링 된 HTML 페이지를 제공한다.

 

react-helmet : 동적으로 헤더값 설정한다. 단, 구글 검색은 react-helmet 으로 데이터를 가져오지 못하는 이슈가 있다.

gatsby-plugin-react-helmet : 정적파일 빌드할때 헤더값 설정한다. (게츠비가 정적 파일을 빌드할때 react-helmet의 내용을 넣는다.)

prerender-spa-plugin, vue-meta : vue 에서 검색엔진최적화 할때 사용

puppeteer : Chrome 또는 Chronium 을 제어할 수 있는 high-level 의 API 를 제공하는 Node.js 의 라이브러리

 

 

방법 2) History API

History API 는 주소를 부여하는 API 이다.

깜빡임 없이 페이지를 로딩하면서, URL이 바뀌게 설정할 수 있다.

정적인 URL 을 설정하여 경로 지정을 해야한다.

 

 

 

 

Reference

https://developers.google.com/search/docs/fundamentals/seo-starter-guide?hl=ko 

 

SEO 기본 가이드: 기본사항 | Google 검색 센터  |  문서  |  Google Developers

검색엔진 최적화의 기본사항에 관한 지식만으로도 눈에 띄는 효과를 얻을 수 있습니다. Google SEO 기본 가이드에서 기본적인 검색엔진 최적화에 관해 간략히 알아보세요.

developers.google.com

 

반응형

'CS' 카테고리의 다른 글

Javascript Design Pattern Summary  (0) 2023.04.13
React, Vue, Angular 의 차이  (0) 2023.04.04
SSR vs CSR vs SSG (페이지 렌더링 방식)  (1) 2023.03.29
NVL NVL2 ISNULL NULLIF COALESCE 비교  (1) 2023.03.14

 

Overview

기존에는 Static Sites 였다.

사용자가 주소에 접속하면 서버에 배포되어있는 HTML 문서들을 받아와서 보여준다.

다른 링크를 클릭하면 다시 서버에서 해당하는 페이지의 HTML 을 요청하고 받아와서 페이지 전체가 업데이트 된다.

이후 XML API, JSON 를 통해 HTML 문서 전체가 아니라 서버에서 필요한 데이터만 받아오고 

JS 를 통해 동적으로 HTML 요소를 생성해서 페이지 업데이트를 받아오는 방식이 있었다.

이러한 방식은 AJAX 라는 이름을 가지게 되었고 구글에서도 AJAX 방식을 사용해 웹어플리케이션을 만들었다.

AJAX를 사용하여 제작한 웹 어플리케이션을 SPA 라고 한다.

 

선행 개념:

TTV (Time To View) : 사용자가 웹사이트를 볼 수 있음

TTI (Time To Interact) : 사용자가 인터렉션이 가능함

 

 

CSR (Client Side Rendering)

사용자가 웹사이트에 접속하면

1. 서버에서 index.html 파일을 클라이언트에 보내주게되는데 받아온 HTML 에는 빈 ROOT 요소와 app.js 링크만 들어있다.

    (HTML 은 비어져 있기 때문에 처음 접속시에 빈 화면만 보인다)

2. 서버로 부터 다운로드 받는 app.js 는

    어플리케이션에서 필요한 로직 + 구동을 위한 프레임워크와 라이브러리의 소스코드가 모두 포함되어있다. (용량이 크다.)
    추가로 필요한 데이터들이 있다면 서버를 통해 JSON 데이터를 받아온다.

3. 2번에서 동적으로 HTML을 생성하여 최종적인 어플리케이션을 보여주게 된다.

    (TTV 와 동시에 TTI 가 가능하다)

 

장점:

- 페이지 렌더링이 자연스럽다.

- 서버에 부담이 적다.

 

문제점:

- 사용자가 첫 화면을 보기까지 시간이 오래걸린다.

- Low SEO (Search Engine Optimization)

  검색엔진들은 웹사이트의 HTML 문서를 분석해 검색엔진에 등록해 놓는다.

  CSR에서는 바디가 대부분 비어져 있기 때문에 검색엔진들이 분석해 놓는데 어려움을 겪는다. (구글에서는 조금 개선됨)

 

성능에 관하여..

CSR 에서는 최종적으로 번들링해서 사용자에게 보내주는 JS 파일을

어떻게 효율적으로 많이 분할해서 첫번째로 사용자가 보기위해 필요한 필수적인 요소만 보낼 수 있을지 고민해본다.

 

 

SSR (Server Side Rendering)

사용자가 웹사이트에 접속하면

1. 서버에서 필요한 데이터를 모두 가져와서 HTML 파일을 만든다.

2. 만들어진 HTML파일은 동적으로 조금 제어할 수 있는 소스코드와 함께 클라이언트에게 보내준다.

3. 잘 만들어진 HTML 문서를 받아와서 바로 사용자에게 보여준다.

 

장점:

- 첫 번째 페이지 로딩이 빠르다.

- 모든 컨텐츠가 HTML 에 담겨져 있기 때문에 조금 더 효율적인 SEO 를 할 수 있다.

 

문제점:

- Static Sites 에서 발생했던 깜박임 현상이 일어난다. (좋지 않은 사용자 경험)
   (전체적인 웹사이트를 다시 서버에서 받아오는 것과 동일하기 때문)

- 요청이 많을 수록 서버 과부하가 걸리기 쉽다.

- HTML 은 빠르게 받아왔지만 동적으로 데이터를 처리하는 JS 를 불러오지 못했을때 이벤트에 대한 반응이 없을 수 있다.

  (TTV 와 TTI 의 공백이 길다.)

 

성능에 관하여.. 

SSR 에서는 TTV 와 TTI 의 단차, 효율적인 UI/UX 제공을 고민해본다.

 

 

SSG (Static Site Generation)

정적 웹 페이지를 생성하는 엔진으로, 컨텐츠가 변경될 일이 거의 없거나 URL을 예측 가능할 경우 SSG를 사용한다.

SSR 처럼 만들어진 HTML 을 받아오지만, SSG는 HTML 파일은 빌드했을때 생성된다.

 

React + Gatsby 

React 에서 만든 웹어플리케이션을 정적으로 웹페이지를 미리 생성해서 서버에 배포해 놓을 수 있다.

JS 파일을 함께 가지고 있을 수 있어서 동적으로 필요한 로직들도 추가할 수 있다.

 

React + NextJS

NextJS 는 SSR 특화 라이브러리이지만 SSG도 지원한다.

CSR 과 SSR 를 섞어서 목적에 맞게 사용할 수 있도록 지원한다.

 

 

 

 

Reference

https://www.youtube.com/watch?v=iZ9csAfU5Os 

 

반응형

'CS' 카테고리의 다른 글

Javascript Design Pattern Summary  (0) 2023.04.13
React, Vue, Angular 의 차이  (0) 2023.04.04
SEO 란?  (0) 2023.03.29
NVL NVL2 ISNULL NULLIF COALESCE 비교  (1) 2023.03.14

 

vite 를 사용하여 프로젝트 생성

npm create vite@latest

 

- 프로젝트명 입력하고 프레임워크는 vue, variants 는 typescript 로 세팅 

해당 폴더로 cd 이동 후 npm 설치

npm install

 

 

이외 필요한 라이브러리도 설치한다.

vue-router

npm install vue-router@4

https://next.router.vuejs.org/installation.html

 

vuex

npm install vuex@next --save

https://next.vuex.vuejs.org/installation.html

 

@types/node

npm install --save @types/node

 

 

 

vite-env.d.ts 파일에 아래 내용 추가

/// <reference types="vite/client" />

declare module "*.vue" {
  import type { DefineComponent } from "vue";
  const component: DefineComponent<{}, {}, any>;
  export default component;
}

 

vite.config.ts 파일에 @설정 추가

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import * as path from 'path' // 라이브러리 : @types/node

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@/': path.resolve(__dirname, './src') + '/'
    }
  }
})

 

혹시라도 vetur 익스텐션 때문에 에러가 난다면 프로젝트 바로 아래 vetur.config.js 파일을 추가해서 설정을 false 로 모두 변경한다.

// vetur.config.js
module.exports = {
  settings: {
    "vetur.completion.autoImport": false,
    "vetur.experimental.templateInterpolationService": false,
    "vetur.validation.interpolation": false,
    "vetur.validation.template": false,
    "vetur.validation.templateProps": false,
    "vetur.validation.style": false,
    "vetur.validation.script": false,
    "vetur.format.enable": false,
    "vetur.ignoreProjectWarning": true,
    "vetur.languageFeatures.codeActions": false,
    "vetur.languageFeatures.semanticTokens": false,
    "vetur.languageFeatures.updateImportOnFileMove": false,
    "vetur.trace.server": "off",
    "vetur.underline.refValue": false,
  },
};

 

 

 

이제 실행 시, 5173 포트로 초기화면을 볼 수 있다.

npm run dev
반응형

'Frontend' 카테고리의 다른 글

React Router  (0) 2023.04.17
RTK Query 란?  (0) 2023.04.13

127.

TRIGGER

특정 테이블에 INSERT, UPDATE, DELETE 와 같은 DML문이 수행되었을 때,

데이터베이스에서 자동으로 동작하도록 작성된 저장 프로그램

(사용자가 직접 호출해서 사용하는 것이 아니고 데이터 베이스에서 자동적으로 수행함)

 

126.

Trigger에 대한 설명

- Trigger는 데이터베이스에 의해서 자동으로 호출되고 수행된다.

- Trigger는 특정 테이블에서 INSERT, UPDATE, DELETE 문이 수행되었을 때 호출되도록 정의할 수 있다.

- Trigger는 Procedure와 달리 Commit, Rollback 과 같은 TCL을 사용할 수 없다.

- Trigger는 데이터베이스에 로그인하는 작업에도 정의할 수 있다.

 

125.

절차형 SQL 모듈에 대한 설명

- 저장형 프로시져는 SQL을 로직과 함께 데이터베이스 내에 저장해 놓은 명령문의 집합을 의미한다.

- 저장형 함수(사용자 정의 함수)는 단독적으로 실행되기 보다는 다른 SQL문을 통하여 호출되고,
  그 결과를 리턴하는 SQL의 보조적인 역할을 한다.

- 트리거는 특정한 테이블에 INSERT, UPDATE, DELETE와 같은 DML문이 수행되었을 때 
  데이터베이스에서 자동으로 동작하도록 작성된 프로그램이다.

* 데이터의 무결성과 일관성을 위해 사용자 정의 함수를 사용하는것은 트리거의 용도 이다.

 

124.

임시부서(TMP_DEPT) 테이블로부터 부서(DEPT) 테이블에 데이터를 입력하는 PL/SQL

조건: 부서 테이블에 데이터를 입력하기 전, 부서테이블의 모든 데이터를 ROLLBACK이 불가능하도록 삭제가 필요하다.

[PL/SQL]
create or replace procedure insert_dept authid current_user as
begin
	execute immediate 'TRUNCATE TABLE DEPT';
	INSERT /*+ APPEND */ INTO DEPT (DEPTNO, DNAME, LOC)
	SELECT DEPTNO, DNAME, LOC
	FROM TMP_DEPT;
	commit;
end;
/

 

> PL/SQL 에서는 동적 SQL 또는 DDL 문장을 실행할 때 EXECUTE IMMEDIATE를 사용해야한다.

 

123.

PL/SQL에 대한 설명

- 변수와 상수 등을 사용하여 일반 SQL 문장을 실행할 때 WHERE 절의 조건 등으로 대입할 수 있다.

- Procedure, User Defined Function, Trrigger 객체를 PL/SQL로 작성할 수 있다.

- Procedure 내부에 작성된 절차적 코드는 PL/SQL엔진이 처리하고 일반적인 SQL 문장은 SQL실행기가 처리한다.

- PL/SQL로 작성된 Procedure, User Define Function은 작성자 기준으로 트랜젝션 분할할 수 있다.

  (프로시저 내에서 다른 프로시저 호출할 때 호출 프로시저 트랜젝션과는 별도로 

   PRAGMA AUTONOMOUS_TRANSACTION 을 선언하여 자율 트랜젝션 처리가 가능하다)

 

122.

User1 사용자가 릴레이션 R 을 생성하였다.

User1 : GRANT SELECT, INSERT, DELETE ON R TO User2 WITH GRANT OPTION;
User2 : GRANT SELECT, INSERT, DELETE ON R TO User3;
User1 : REVOKE DELETE ON R FROM User2;
User1 : REVOKE INSERT ON R FROM User2 CASCADE;

USER2 는 DELETE, INSERT 권한을 회수당했다.

USER3 은 USER1 의 CASCADE 명령으로 인해 INSERT 권한이 USER2와 함께 삭제되었다.

 

121.

DBMS 사용자를 생성하면 기본적으로 많은 권한을 부여하는데,
DBMS 관리자의 권한 관리의 부담과 복잡함을 줄이기 위해
다양한 권한을 그룹으로 묶어 관리할 수 있도록 [ROLE] 을 제공한다.

 

120.

UPDATE A_User.TB_A
SET col1='AAA'
WHERE col2=3

 

 

B_User 가 위 작업을 수행할 수 있도록 권한을 부여하는 명령문

GRANT SELECT, UPDATE ON A.User.TB_A TO B_User

 

119.

GRANT : ROLE 을 DBMS USER 에게 부여하기 위해 사용하는 명령어

REVOKE : ROLE 을 DBMS USER 에게서 회수하기 위해 사용하는 명령어

 

118.

[ Test - Oracle live server ]

create table TBL (
    id varchar2(10),
    start_val number,
    end_val number
);

insert into TBL values('A', 10, 14);
insert into TBL values('A', 14, 15);
insert into TBL values('A', 15, 15);
insert into TBL values('A', 15, 18);
insert into TBL values('A', 20, 25);
insert into TBL(id, start_val) values('A', 25);
commit;

select * from tbl;

select id, start_val, end_val
from (
    select id, start_val, nvl(end_val, 99) end_val, 
    	(case when start_val = lag(end_val) over (partition by id 
    			order by start_val, nvl(end_val, 99)) then 1
    		else 0
    	end) flag1, 
    	(case when end_val = lead(start_val) over (partition by id 
    			order by start_val, nvl(end_val, 99)) then 1
    		else 0
    	end) flag2
	from tbl
)
where flag1 = 0 or flag2 = 0;

핵심:

case1: start_val 가 end_val 이전행의 값이랑 같은지 비교해서 같을때 결과값은 1, 다를때 결과값은 0이다.

case2: end_val 가 start_val 이후행의 값이랑 같은지 비교해서 같을때 결과값은 1, 다를때 결과값은 0이다.

서브에서 생성했던 flag 컬럼 중 0인값들의 행만 메인에서 select 한다.

 

117.

[ Test - Oracle live server ]

create table 사원(
    사원ID number,
    부서ID number,
    사원명 varchar2(20),
    연봉 number
);

insert into 사원 values (001, 100, '홍길동', 2500);
insert into 사원 values (002, 100, '강감찬', 3000);
insert into 사원 values (003, 200, '김유신', 4500);
insert into 사원 values (004, 200, '김선달', 3000);
insert into 사원 values (005, 200, '유학생', 2500);
insert into 사원 values (006, 300, '변사또', 4500);
insert into 사원 values (007, 300, '박문수', 3000);
commit;

select * from 사원;

select Y.사원ID, Y.부서ID, Y.사원명, Y.연봉
from (select 사원ID, max(연봉) over(partition by 부서ID) as 최고연봉
        from 사원) X, 사원 Y
where X.사원ID = Y.사원ID
and X.최고연봉 = Y.연봉;

핵심:

Inline-view 를 통해 사원ID와 부서별최고연봉을 X테이블로 생성하여

최고연봉과 같은 연봉을 받는 사람만 출력한다.

 

116.

select 상품분류코드, AVG(상품가격) as 상품가격,
	count(*) over(order by avg(상품가격)
    	               range between 10000 preceding
                       and 10000 following) as 유사개수
from 상품
group by 상품분류코드;

유사개수 컬럼은 상품분류코드별 평균상품가격을 서로 비교하여

-10000 ~ +10000 사이에 존재하는 상품분류코드의 개수를 구한것이다.

 

range: 값

preceding: 이전

following: 이후 

group by 이후 select 이 실행되기 때문에 상품분류코드별로 계산된다.

 

115.

[ Test - Oracle live server ]

create table 추천내역 (
    추천경로 varchar2(20),
    추천인 varchar2(20),
    피추천인 varchar2(20),
    추천점수 number
);

insert into 추천내역 values ('sns', '나한일', '강감찬', 75);
insert into 추천내역 values ('sns', '이순신', '강감찬', 80);
insert into 추천내역 values ('이벤트응모', '홍길동', '강감찬', 88);
insert into 추천내역 values ('이벤트응모', '저절로', '이순신', 78);
insert into 추천내역 values ('홈페이지', '저절로', '이대로', 93);
insert into 추천내역 values ('홈페이지', '홍두깨', '심청이', 98);
commit;

select * from 추천내역;

select 추천경로, 추천인, 피추천인, 추천점수
from (select 추천경로, 추천인, 피추천인, 추천점수,
    	row_number() over(partition by 추천경로 order by 추천점수 desc) as rnum
      from 추천내역)
where rnum = 1;

- row_number : 동일한 순위더라도 고유한 순위를 부여한다.

 

114.

RANK() DENSE_RANK() ROW_NUMBER()
1 1 1
2 2 2
2 2 3
4 3 4
5 4 5

 

113.

 

create table 고객(
    고객번호 number primary key,
    고객명 varchar2(20)
);

create table 월별매출(
    월 varchar2(20),
    고객번호 number,
    매출액 number,
    constraint multi_pk primary key (월, 고객번호)
);

insert into 고객 values (001, '홍길동');
insert into 고객 values (002, '이순신');
insert into 고객 values (003, '강감찬');
insert into 고객 values (004, '이상화');
insert into 고객 values (005, '이규혁');
commit;

insert into 월별매출 values ('202301', 001, 200);
insert into 월별매출 values ('202301', 002, 300);
insert into 월별매출 values ('202301', 003, 250);
insert into 월별매출 values ('202301', 004, 300);
insert into 월별매출 values ('202301', 005, 250);
insert into 월별매출 values ('202302', 001, 150);
insert into 월별매출 values ('202302', 002, 150);
insert into 월별매출 values ('202302', 004, 200);
insert into 월별매출 values ('202302', 005, 100);
insert into 월별매출 values ('202303', 002, 100);
insert into 월별매출 values ('202303', 003, 100);
insert into 월별매출 values ('202303', 004, 200);
insert into 월별매출 values ('202303', 005, 350);
commit;

select * from 월별매출;

select 고객번호, 고객명, 매출액, rank() over(order by 매출액 desc) as 순위
from (
    select A.고객번호, max(A.고객명) as 고객명, sum(B.매출액) as 매출액
    from 고객 A inner join 월별매출 B
    on (A.고객번호 = B.고객번호)
    group by A.고객번호
)
order by 순위;

- max(A.고객명) : group by 로 묶지 않았기 때문에 단순히 하나의 행으로 표기하려고 max 쓴 것으로 보임

- 동일순서에 대한 정렬은 답지와 위 코드의 실행결과가 약간 다름 (?)

 

112.

윈도우 함수에 대한 설명

- Partition 과 Group By 구문은 의미적으로 유사하다.

- Partition 구문이 없으면 전체 집합을 하나의 Partition 으로 정의한 것과 동일하다.

- 윈도우 함수는 결과에 대한 함수처리이기 때문에 결과 건수는 줄지 않는다.

- 윈도우 함수 적용 범위는 Partition을 넘을 수 없다.

 

111.

Groupping set 은 다양한 소계 집합을 만들 수 있다.

표시된 인수들에 대한 개별 집계를 구한다.

select 상품ID, 월, sum(매출액) as 매출액
from 월별매출
where 월 between '2014.10' and '2014.12'
group by grouping sets((상품ID, 월));

> (상품ID, 월) 별 집계 데이터를 출력한다. (괄호 주의)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형

+ Recent posts