<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>fe_sw.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Tue, 08 Aug 2023 05:07:21 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>fe_sw.log</title>
            <url>https://velog.velcdn.com/images/fe_jungseok/profile/7aae731c-3f65-47a5-8da4-4af0bbc55a50/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. fe_sw.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/fe_jungseok" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[useState와 클로저 관계]]></title>
            <link>https://velog.io/@fe_jungseok/useState%EC%99%80-%ED%81%B4%EB%A1%9C%EC%A0%80-%EA%B4%80%EA%B3%84</link>
            <guid>https://velog.io/@fe_jungseok/useState%EC%99%80-%ED%81%B4%EB%A1%9C%EC%A0%80-%EA%B4%80%EA%B3%84</guid>
            <pubDate>Tue, 08 Aug 2023 05:07:21 GMT</pubDate>
            <description><![CDATA[<h3 id="클로저">클로저</h3>
<p>클로저는 자바스크립트에서 함수와 그 함수가 선언될 때의 렉시컬 환경과의 조합이다. 
이를 통해 함수는 선언된 환경 밖에서 실행되더라도 해당 환경의 변수에 접근할 수 있다. 
클로저는 상태 관리, 데이터 캡슐화 등에 사용된다.</p>
<pre><code class="language-java">
function outer() {
  let count = 0;
  function inner() {
    count++;
    return count;
  }
  return inner;
}

const counter = outer();
console.log(counter()); // 1
console.log(counter()); // 2
</code></pre>
<h3 id="usestate훅과-클로저의-관계">useState훅과 클로저의 관계</h3>
<p>React Hook에서는 useState라는 Hook을 통해 컴포넌트 내의 상태를 관리한다. </p>
<p>함수형 컴포넌트에서 이전 상태와 현 상태의 변경이 있는지를 감지하기 위해서는 함수가 실행되었을 때 이전 상태에 대한 정보를 가지고 있어야 한다. React는 이 과정에서 클로저를 사용한다. </p>
<pre><code class="language-java">function useState(initialVal) {
  let _val = initialVal;
  const state = () =&gt; _val;
  const setState = (newVal) =&gt; {
    _val = newVal;
  };

  return [state, setState];
}

const [count, setCount] = useState(1);

console.log(count()); //1
setCount(2);
console.log(count()); //2</code></pre>
<p>실제로 useState가 어떻게 동작하는지는 리액트의 내부 코드에 담겨 있으며, 위는 그 동작을 단순화한 예제 코드이다.
이때 클로저(state,setState)가 useState 내부 스코프 _val 값을 기억하고 있기 때문에 이후에도 접근이 가능하다.</p>
<p>하지만 위의 코드에서는 문제점이 존재한다. 상태값은 함수가아닌 변수로 존재하여야 한다.</p>
<h3 id="오래된-클로저">오래된 클로저</h3>
<p>오래된 크로저란 상태값에 변화가 발생해도 이를 감지하지못하고 예전 값을 바라보게 되는 현상이다. </p>
<pre><code class="language-java">function useState(initialValue) {
  var _val = initialValue
  function setState(newVal) {
    _val = newVal
  }
  return [_val, setState] 
}
const [count, setCount] = useState(0;
console.log(count) // 0
setCount(1) 
console.log(count) // 0
</code></pre>
<p>실제 React 훅과 동일하게 만들려면 state가 함수가 아닌 변수여야 한다.
단순히 _val을 함수로 감싸지 않고 노출하면 버그가 발생한다. //count 상태값이 변경되지않음</p>
<p>state를 함수가아닌 변수로 사용 + 현재상태를 반영하기위해 컴포넌트의 상태가 필요함
아 두가지를 만족시키기 위해 어떤식으로 구현해야 될까?</p>
<h3 id="모듈-안에서의-클로저">모듈 안에서의 클로저</h3>
<pre><code class="language-java">const MyReact = (function() {
  let _val // 모듈 스코프 안에 state를 잡아놓습니다.
  return {
    render(Component) {
      const Comp = Component()
      Comp.render()
      return Comp
    },
    useState(initialValue) {
      _val = _val || initialValue // 매 실행마다 새로 할당됩니다.
      function setState(newVal) {
        _val = newVal
      }
      return [_val, setState]
    },
  }
})()
</code></pre>
<p>오래된 클로저의의 문제점을 클로저를 또 다른 클로저의 내부로 이동시켜 해결할 수 있다.</p>
<p>허나 해당 코드에서도 문제점은 존재하는데 useState를 사용하는 컴포넌트가 여러 개라면 문제가 생긴.
하나의 state 변수에 여러 컴포넌트가 접근하기 때문에 모든 컴포넌트의 state가 동일해지기 떄문이다.</p>
<h3 id="최종코드">최종코드</h3>
<pre><code class="language-java">let state = [];
let setters = [];
let cursor = 0;
let firstrun = true;

const createSetter = (cursor) =&gt; {
  return (newValue) =&gt; {
    state[cursor] = newValue;
  };
};

const useState = (initialValue) =&gt; {
  if (firstrun) {
    state.push(initialValue);
    setters.push(createSetter(cursor));
    firstrun = false;
  }

  const resState = state[cursor];
  const resSetter = setters[cursor];
  cursor++;

  return [resState, resSetter];
};</code></pre>
<p>useState로 선언된 state들은 배열에 순서대로 저장된다.
이러한 state 배열은 컴포넌트를 유일하게 구분 짓는 키를 통해 접근할 수 있게된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[git 명령어 모음]]></title>
            <link>https://velog.io/@fe_jungseok/git-%EB%AA%85%EB%A0%B9%EC%96%B4-%EB%AA%A8%EC%9D%8C</link>
            <guid>https://velog.io/@fe_jungseok/git-%EB%AA%85%EB%A0%B9%EC%96%B4-%EB%AA%A8%EC%9D%8C</guid>
            <pubDate>Tue, 08 Aug 2023 02:33:05 GMT</pubDate>
            <description><![CDATA[<h3 id="git-init">git init</h3>
<p>현재 디렉토리에 새 Git 저장소를 생성합니다.</p>
<h3 id="git-clone-url">git clone [URL]</h3>
<p>원격 저장소를 복제합니다.</p>
<h3 id="git-add-filedirectory">git add [file/directory]</h3>
<p>파일 또는 디렉토리를 스테이징 영역에 추가합니다.</p>
<h3 id="git-commit">git commit</h3>
<p>-m &quot;message&quot;: 커밋 메시지를 직접 작성합니다.</p>
<h3 id="git-branch">git branch</h3>
<p>브랜치를 생성하거나 나열합니다.
-a: 로컬과 원격의 모든 브랜치를 나열합니다.
-d [branch-name]: 브랜치를 안전하게 삭제합니다. (병합된 브랜치만 삭제 가능)
-D [branch-name]: 브랜치를 강제로 삭제합니다. (병합되지 않아도 삭제)
-m [old-branch-name] [new-branch-name]: 브랜치 이름을 변경합니다.
-r: 원격 브랜치를 나열합니다.</p>
<h3 id="git-checkout">git checkout</h3>
<p>브랜치를 전환합니다.
-b [new-branch-name]: 새 브랜치를 생성하고 해당 브랜치로 전환합니다.
-B [branch-name]: 브랜치를 생성하거나 이미 존재하는 브랜치를 리셋하고 전환합니다.
-t [remote-branch-name]: 원격 브랜치를 추적하는 브랜치를 생성하고 전환합니다.</p>
<h3 id="git-merge-branch">git merge [branch]</h3>
<p>지정된 브랜치를 현재 브랜치와 병합합니다.
--abort: 현재 병합 작업을 취소하고 원래 상태로 되돌립니다.
--continue: 충돌이 해결된 후 병합을 계속 진행합니다.</p>
<h3 id="git-pull-repository-refspec">git pull [repository [refspec]]</h3>
<p>원격 저장소의 변경 사항을 가져와 병합합니다.
--rebase: 원격 저장소의 변경 사항을 가져와 현재 브랜치 위에 리베이스합니다.
--no-rebase: 리베이스를 수행하지 않고 원격 변경 사항을 병합합니다.</p>
<h3 id="git-push-repository-refspec">git push [repository [refspec]]</h3>
<p>로컬 저장소의 변경 사항을 원격 저장소에 푸시합니다.
--force 또는 -f: 원격 브랜치에 강제로 푸시합니다 (주의 필요).
--force-with-lease: 강제 푸시를 수행하기 전에 최근 패치를 확인합니다.
-n 또는 --dry-run: 실제로 푸시하지 않고 푸시 결과를 확인합니다.
--delete <branch-name>: 원격 브랜치를 삭제합니다.</p>
<h3 id="git-reset">git reset</h3>
<p>HEAD: 최근 커밋으로 되돌립니다.
--soft: 스테이징은 유지하고 브랜치 포인터만 이동합니다.
--mixed: 스테이징을 언스테이지 상태로 되돌리고 브랜치 포인터 이동합니다.
--hard: 브랜치 포인터를 이동하고 워킹 디렉토리까지 초기화합니다.</p>
<h3 id="git-revert-commit">git revert [commit]</h3>
<p>지정된 커밋을 취소하는 새로운 커밋을 생성합니다.</p>
<h3 id="git-log">git log</h3>
<p>커밋 히스토리를 확인합니다</p>
<h3 id="git-rebase">git rebase</h3>
<p>브랜치의 기반이 되는 지점을 변경합니다.
--abort: 현재 진행 중인 rebase를 취소하고 원래의 상태로 되돌립니다.</p>
<h3 id="git-stash">git stash</h3>
<p>작업중인 변경사항을 스택에 잠시 저장할 수 있도록 하는 명령어이다. 
이를 통해 아직 완료하지 않은 일을 commit하지 않고 나중에 다시 꺼내와 마무리할 수 있다.
(작업도중 다른 브런치로 이동할때 자주 쓰임)</p>
<p>git stash save &quot;message&quot;: 변경사항을 스태시에 저장하고 메시지를 추가합니다.
git stash apply: 스태시에 저장된 변경사항을 적용합니다.
git stash pop: 스태시에 저장된 변경사항을 적용하고 스태시 목록에서 제거합니다.
git stash drop: 스태시 목록에서 특정 스태시를 제거합니다.</p>
<h3 id="git-remote">git remote</h3>
<p>원격 저장소를 관리합니다.
git remote add [name] [url]: 원격 저장소를 추가합니다.
git remote remove [name]: 원격 저장소를 삭제합니다.
git remote rename [old-name] [new-name]: 원격 저장소의 이름을 변경합니다.
git remote show [name]: 원격 저장소의 정보를 표시합니다.</p>
<h3 id="git-diff">git diff</h3>
<p>두 커밋, 브랜치 또는 스테이징 영역과 워킹 디렉토리 간의 차이점을 표시합니다.
git diff [branch1] [branch2]: 두 브랜치 간의 차이점을 표시합니다.
git diff --staged: 스테이징 영역과 최신 커밋 간의 차이점을 표시합니다.</p>
<h3 id="git-status">git status</h3>
<p>워킹 디렉토리와 스테이징 영역의 상태를 표시합니다.
git status -s 또는 git status --short: 상태를 짧게 한 줄로 표시합니다.</p>
<h3 id="git-작업영역">git 작업영역</h3>
<p>[워킹 디렉토리 (Working Directory)]:
사용자가 파일을 수정하고 작업하는 실제 디렉토리</p>
<p>[스테이징 영역 (Staging Area)]: 
커밋을 수행하기 전에, 워킹 디렉토리에서 변경된 파일 중 커밋에 포함할 파일을 선택하여 저장하는 임시 영역이다. 
&quot;스테이징 상태&quot;라고도 한다(Git에서 파일 변경 사항을 커밋하기 전에 임시로 저장하는 단계를 말한다. 
(이 상태는 변경 사항을 추적하고, 어떤 변경 사항을 다음 커밋에 포함할 것인지를 정의)</p>
<p>[레포지토리 (Repository)]:
커밋된 변경 사항들이 저장되는 곳으로, 프로젝트의 모든 버전 정보를 포함하고 있다.
파일이 수정되면 먼저 워킹 디렉토리에 변경 사항이 발생한다. 그리고 git add 명령어를 사용하여 변경된 파일을 스테이징 영역에 추가할 수 있다. 
스테이징 영역에 추가된 파일들은 git commit 명령어를 통해 레포지토리에 영구적으로 저장된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MVVM]]></title>
            <link>https://velog.io/@fe_jungseok/MVVM-jqvanos9</link>
            <guid>https://velog.io/@fe_jungseok/MVVM-jqvanos9</guid>
            <pubDate>Wed, 12 Jul 2023 07:58:33 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/fe_jungseok/post/00565112-8d6f-42e6-b93c-1ed92169c299/image.png" alt=""></p>
<p>MVVM은 UI 및 비 UI 코드를 분리하기 위한 디자인 패턴이다.</p>
<p>이는 프로그램의 복잡성을 줄이고 서로 다른 관심사를 각 영역으로 분리함으로써 관리성과 유지 보수성을 향상시킨다. 
MVVM은 사용자 인터페이스 로직을 비즈니스 로직과 분리함으로써 사용자 인터페이스의 개발과 테스트를 보다 쉽게 만들어준다.</p>
<p>사용자 인터페이스를 개발하고 테스트하기 쉽도록 사용자 인터페이스 로직을 비즈니스 로직과 분리한다. 
MVVM 패턴의 주요 구성 요소는 Model, View, ViewModel의 세 부분으로 이루어져 있다.</p>
<h3 id="model">Model:</h3>
<p>이는 데이터 및 비즈니스 로직을 나타낸다. 
모델은 데이터베이스에 접근하거나, 네트워크에서 데이터를 받아오거나, 유효성 검사 등의 비즈니스 로직을 수행한다.</p>
<h3 id="view">View:</h3>
<p>이는 사용자에게 보여지는 부분으로, 사용자 인터페이스와 관련된 모든 것을 담당한다. 
뷰는 사용자의 입력을 받고, 데이터를 보여주며, 사용자에게 다양한 인터랙션을 제공힌다.</p>
<h3 id="viewmodel">ViewModel:</h3>
<p>이는 뷰와 모델 사이의 연결 고리 역할을 한다. 
데이터 바인딩과 명령 패턴(Command Pattern)이라는 두 가지 핵심 기술을 사용는데, </p>
<p>데이터 바인딩은 ViewModel의 데이터 변경이 자동으로 View에 반영되고, 명령패턴은 View의 변경 사항이 ViewModel에 자동으로 업데이트되는 것을 의미한다. 이를 통해 View와 ViewModel 사이의 동기화를 자동으로 유지합니다.</p>
<h3 id="command-패턴">Command 패턴</h3>
<p>command 패턴은 사용자의 액션(예: 버튼 클릭, 텍스트 입력 등)을 추상화하여, ViewModel이 이러한 액션을 캡슐화하고 관리할 수 있게 한다. 이를 통해 ViewModel은 View에 대해 알지 못하며, 단지 액션에 반응하기만 하면 된다. 
이 방식은 View와 ViewModel 사이의 결합도를 최소화하고 테스트 용이성을 높이는 데 도움이 된다.</p>
<h3 id="data-binding">Data Binding</h3>
<p>사용자 인터페이스(UI) 요소가 애플리케이션의 데이터 소스와 &#39;바인딩&#39;되는 것을 의미한다. 
이를 통해 UI 요소는 데이터 변경을 실시간으로 반영하며, 사용자의 조작 등으로 인한 데이터 변경에  따른 UI 상태 변경도 즉시 반영되는 효과를 얻을 수 있다.</p>
<p>MVVM에서 데이터 바인딩은 핵심적인 역할을 한다. ViewModel의 데이터 상태가 변경될 때, 이 변경사항이 자동으로 View에 반영되어야 하는데, 이를 &#39;One-Way Data Binding&#39;(단방향 데이터 바인딩)이라고 한다. 또한, 반대로 사용자의 조작 등으로 View의 상태가 변경될 경우, 이 변경사항이 ViewModel의 데이터 상태에 자동으로 반영되어야 하는데, 이를 &#39;Two-Way Data Binding&#39;(양방향 데이터 바인딩)이라고 한다.</p>
<p>데이터 바인딩을 통해 View와 ViewModel 사이의 데이터 동기화를 자동으로 유지할 수 있다. 
이런 특성 때문에, MVVM 패턴을 지원하는 프레임워크(Angular, Vue.js 등)은 대부분 데이터 바인딩 기능을 제공한다.</p>
<h3 id="mvvm에서-데이터-바인딩은-단바향--양방향-">MVVM에서 데이터 바인딩은 단바향 ? 양방향 ?</h3>
<p>MVVM(Model-View-ViewModel) 패턴에서는 주로 양방향(Two-Way) 데이터 바인딩을 사용한다.</p>
<p>양방향 데이터 바인딩은 View의 변경이 ViewModel에 반영되고, ViewModel의 변경이 View에 반영되는 방식을 의미한다.
이는 ViewModel의 상태가 변경될 때 이를 View가 즉시 반영하도록 하며, 반대로 사용자의 액션에 의해 View의 상태가 변경될 때 ViewModel의 상태가 자동으로 업데이트되도록 하는 것을 가능하게 한다.</p>
<p>따라서 MVVM 패턴에서는 사용자의 입력과 같은 View의 상태 변화를 ViewModel이 추적하고, 이를 Model에 반영하며, 동시에 Model의 변경사항을 ViewModel이 받아와 View에 반영하는 등, 양방향의 동적인 상호작용이 일반적이다.</p>
<p>하지만, 실제 애플리케이션의 요구사항과 상황에 따라 양방향 데이터 바인딩 대신 단방향 데이터 바인딩(One-Way Data Binding)을 사용할 수도 있다. 단방향 데이터 바인딩은 ViewModel의 변경만 View에 반영되는 방식으로, 이 경우에는 View에서 발생하는 변경이 ViewModel에 직접적으로 반영되지 않는다. 이런 방식은 데이터 흐름을 좀 더 명확하게 만들어 주기 때문에 복잡한 애플리케이션에서 상태 관리를 좀 더 편리하게 할 수 있다.</p>
<br/>

<h3 id="예시">예시</h3>
<p>다음은 리액트로 간단하게 MVVM 구조를 따라 작성해본 예시코드이다.</p>
<pre><code class="language-java">
import React, { useReducer, useContext, createContext } from &#39;react&#39;;

// Model
const initialTodos = [
  { id: 1, title: &#39;Get Coffee&#39;, finished: false },
  { id: 2, title: &#39;Write simpler UIs&#39;, finished: false }
];

// ViewModel: 액션 디스패칭을 통해 커맨드 패턴을 구현한 리듀서
function todoReducer(state, action) {
  switch (action.type) {
    case &#39;add&#39;:
      return [...state, { id: Date.now(), title: action.title, finished: false }];
    case &#39;toggle&#39;:
      return state.map(todo =&gt; 
        todo.id === action.id ? { ...todo, finished: !todo.finished } : todo
      );
    default:
      throw new Error();
  }
}

// ViewModel
const TodoContext = createContext();

function TodoProvider({ children }) {
  const [state, dispatch] = useReducer(todoReducer, initialTodos);
  // 데이터 바인딩의 일부로서 상태와 디스패치 함수를 컨텍스트로 제공하는데,
  // 이를 통해 View에서 상태를 전달하고 조작할 수 있다.
  return (
    &lt;TodoContext.Provider value={{ state, dispatch }}&gt;
      {children}
    &lt;/TodoContext.Provider&gt;
  );
}

// View
function TodoListView() {
  const { state, dispatch } = useContext(TodoContext);
  // 데이터 바인딩: 컨텍스트로부터 상태와 디스패치 함수를 가져와서 활용하는 과정
  return (
    &lt;div&gt;
      {state.map(todo =&gt; (
        &lt;div key={todo.id}&gt;
          &lt;input
            type=&quot;checkbox&quot;
            checked={todo.finished}
            // 커맨드 패턴: 버튼 클릭에 대한 액션을 &#39;toggle&#39; 커맨드로 캡슐화
            onChange={() =&gt; dispatch({ type: &#39;toggle&#39;, id: todo.id })}
          /&gt;
          {todo.title}
        &lt;/div&gt;
      ))}
    &lt;/div&gt;
  );
}

function App() {
  return (
    &lt;TodoProvider&gt;
      &lt;TodoListView /&gt;
    &lt;/TodoProvider&gt;
  );
}

export default App;


</code></pre>
<p>위의 React 코드에서도 단방향 데이터 바인딩이 이루어지고 있다. </p>
<p>여기서 상태(state)는 TodoProvider 컴포넌트에서 관리되고 있으며, 이 상태는 TodoContext를 통해 TodoListView 컴포넌트로 전달되어진다.</p>
<p>그러나 코드에서 볼 수 있듯이, dispatch 함수를 통해 View에서 발생하는 이벤트를 통해 상태를 변경하는 작업이 이루어지는데, 
이를 통해 ViewModel과 View 사이의 &#39;가상의&#39; 양방향 데이터 바인딩을 구현하였다고 볼 수 있다. </p>
<p>체크박스의 상태 변경을 감지하는 이벤트 핸들러에서 dispatch 함수를 호출하여 상태를 변경하고, 이 변경된 상태가 다시 View에 반영되는 구조이다.</p>
<p>따라서 이것은 React에서 &#39;양방향 데이터 바인딩 같은 효과&#39;를 내는 하나의 방식이다. 
그러나 이는 여전히 React의 단방향 데이터 흐름 구조 내에서 이루어지는 것이므로, 순수한 의미에서의 양방향 데이터 바인딩이라고 보기는 어렵다. </p>
<p>이는 ViewModel의 상태가 변경되면 이를 View에 바로 반영하되, 반대로 View의 변경을 ViewModel에 바로 반영하는 구조인 진정한 양방향 데이터 바인딩과는 다르다.</p>
<h3 id="flux-mvvm-차이점">Flux, MVVM 차이점</h3>
<p><img src="https://velog.velcdn.com/images/fe_jungseok/post/f530339e-d037-478c-a296-d060e808259c/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/fe_jungseok/post/e15c412b-5048-447f-862b-bad24dd0de83/image.png" alt=""></p>
<p>Flux는 Dispatcher, Store, View, Action의 네 가지 주요 구성 요소를 갖지만,  MVVM은 Model, View, ViewModel의 세 가지 구성 요소를 갖는다.</p>
<p>Flux에서는 데이터 흐름이 단방향인데, View에서 사용자 입력을 받아 Action을 생성하고, 이 Action이 Dispatcher에 전달되며, Dispatcher는 이 Action을 등록된 모든 Store에 전달한다. 이후 Store가 업데이트되면, 이 변경 사항이 View에 반영된다. 따라서, Flux에서는 명시적인 업데이트 메커니즘이 필요하다.</p>
<p>MVVM에서는 데이터 바인딩 기술을 사용하여 View와 ViewModel 사이에 양방향 통신을 가능하게 한다.
이는 ViewModel의 데이터가 변경될 때 View가 자동으로 업데이트되며, 반대로 사용자 입력이 ViewModel을 자동으로 업데이트 한다. 
따라서 MVVM에서는 업데이트가 암시적으로 처리된다.</p>
<p>Flux 패턴에서는 View와 Store 사이에 직접적인 의존성이 없다. View는 단지 Dispatcher에서 이벤트를 받아 처리한다. 
반면 MVVM 패턴에서는 ViewModel이 View와 Model 사이의 연결 역할을 하며, View와 ViewModel 사이에는 데이터 바인딩을 통한 의존성이 존재한다.</p>
<p>제시한 React 코드는 MVVM에 가까운 이유는, Flux 패턴에서 볼 수 있는 Dispatcher나 여러 Store의 개념이 없기 때문이다. 대신, useContext와 useReducer를 통해 View와 ViewModel 사이에 양방향으로 데이터를 주고 받으며, ViewModel이 상태와 로직을 관리하는 형태를 볼 수 있다. 이러한 모습은 MVVM 패턴에서 ViewModel이 가지는 역할에 더 가까워 보인다. </p>
<p> ++</p>
<p>일반적으로 ViewModel은 View에 대한 모든 비즈니스 로직과 상태를 관리하는 역할을 하므로, 하나의 View에 대해 하나의 ViewModel이 연결되는 1:1 관계가 이상적일 수 있다. 이렇게 하면 View와 ViewModel 사이의 관심사가 분리되어 코드의 가독성과 유지 관리성이 향상된다.</p>
<p>그러나 실제 애플리케이션에서는 여러 View가 동일한 로직이나 상태를 공유해야 하는 경우가 자주 발생한다. 이런 경우에는 하나의 ViewModel이 여러 View에 연결되는 1:n 또는 n:1 관계를 가질 수 있다.</p>
<p>따라서, MVVM 패턴에서 View와 ViewModel의 관계는 애플리케이션의 복잡성, 요구 사항, 개발 방식 등에 따라 달라질 수 있으며, 항상 1:1 관계일 필요는 없다.</p>
<br/>

<h3 id="장단점">장단점</h3>
<p>장점</p>
<ul>
<li><p>분리된 관심사: MVVM 패턴에서는 Model, View, ViewModel의 역할이 분리되어 있다. 
이를 통해 각 구성 요소의 책임이 명확해지고 코드의 가독성과 유지 보수성이 향상된다.</p>
</li>
<li><p>데이터 바인딩: 데이터 바인딩을 통해 View와 ViewModel 사이의 상호 작용이 자동화되고, 
이를 통해 UI 코드를 간소화하고 오류를 줄일 수 있다.</p>
</li>
<li><p>테스트 용이성: ViewModel은 View로부터 분리되어 있으므로, UI 없이 비즈니스 로직을 테스트하는 것이 가능하다.</p>
</li>
<li><p>코드 재사용: ViewModel은 View에 종속되지 않기 때문에, 여러 View에서 재사용이 가능하다.</p>
</li>
</ul>
<h4 id="단점">단점</h4>
<ul>
<li><p>복잡성 증가: MVVM 패턴은 구조가 복잡하며, 이로 인해 프로젝트의 복잡성이 증가할 수 있다. </p>
</li>
<li><p>초기 학습 곡선: MVVM 패턴의 이해와 구현에는 초기 학습 곡선이 필요하다. 
개발자들이 패턴의 원리와 사용 방법을 완전히 이해하는 데 시간이 필요할 수 있다.</p>
</li>
<li><p>성능 문제: 데이터 바인딩에 의존하는 경우, 많은 수의 바인딩이 발생하면 애플리케이션의 성능에 부정적인 영향을 미칠 수 있다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[가비지 컬렉션]]></title>
            <link>https://velog.io/@fe_jungseok/%EA%B0%80%EB%B9%84%EC%A7%80-%EC%BB%AC%EB%A0%89%EC%85%98</link>
            <guid>https://velog.io/@fe_jungseok/%EA%B0%80%EB%B9%84%EC%A7%80-%EC%BB%AC%EB%A0%89%EC%85%98</guid>
            <pubDate>Mon, 19 Dec 2022 11:57:24 GMT</pubDate>
            <description><![CDATA[<h3 id="카비지-컬렉션">카비지 컬렉션</h3>
<p>C 언어같은 저수준 언어에서는 메모리 관리를 위해 malloc() 과 free()를 사용해 메모리를 수동으로 해제 한다. </p>
<p>반면, 자바스크립트는 객체가 생성되었을 때 자동으로 메모리를 할당하고 더 이상 필요하지 않을 때 자동으로 해제한다. 이를 가비지 컬렉션이라고 한다.</p>
<p>자바스크립트 엔진에 들어있는 가비지 콜렉터는 메모리 할당을 모니터링하고 할당된 메모리의 영역이 더 이상 필요하지 않은 시점을 확인하여 메모리를 회수한다. </p>
<p>가비지 컬렉션을 이해하기 위해서 일딴 메모리 생존주기 부터 알아야 된다.</p>
<h3 id="메모리-생명-주기">메모리 생명 주기</h3>
<ul>
<li><ol>
<li>필요한 메모리 할당</li>
</ol>
</li>
<li><ol start="2">
<li>할당된 메모리 사용(읽기, 쓰기)</li>
</ol>
</li>
<li><ol start="3">
<li>해당 메모리가 필요 없어지면 해제</li>
</ol>
</li>
</ul>
<h4 id="필요한-메모리-할당">필요한 메모리 할당</h4>
<p>1) 값초기화: 자바스크립트는 값을 초기화 할 때 자동으로 메모리를 할당한다.</p>
<pre><code class="language-java">var n = 123; // 정수를 담기 위한 메모리 할당
var s = &#39;azerty&#39;; // 문자열을 담기 위한 메모리 할당 

// 객체와 객체에 포함된 값들을 담기 위한 메모리 할당
var o = {
  a: 1,
  b: null
}; 

// 배열과 포함된 값들을 담기 위한 메모리 할당
var a = [1, null, &#39;abra&#39;]; 

// 함수를 담기 위한 메모리 할당
function f(a) {
  return a + 2;
} 

// 함수 표현식 또한 객체를 담기 위한 메모리를 할당
someElement.addEventListener(&#39;click&#39;, function () {
  someElement.style.backgroundColor = &#39;blue&#39;;
}, false);

2) 함수 호출을 통한 메모리 할당
var d = new Date(); // Date 객체 할당
var e = document.createElement(&#39;div&#39;); // DOM element 할당

var s = &#39;azerty&#39;; 
var s2 = s.substr(0, 3); 
// s2는 새로운 문자열입니다. //문자열은 불변값(immutable)이기 때문에 자바스크립트는 메모리를 새로 할당하지 않고, [0, 3]의 범위를 저장합니다. 

var a = [&#39;ouais ouais&#39;, &#39;nan nan&#39;]; 
var a2 = [&#39;generation&#39;, &#39;nan nan&#39;]; 
var a3 = a.concat(a2); // 4개의 원소를 가진 새로운 배열</code></pre>
<h4 id="2할당된-메모리-사용읽기-쓰기">2.할당된 메모리 사용(읽기, 쓰기)</h4>
<p>값을 사용한다는 의미는 &quot;할당된 메모리&quot;를 &quot;쓰거나 읽는다는 것&quot;을 의미한다.</p>
<p>&quot;변수나 객체 속성값을 읽고 쓸 때&quot;, &quot;함수 호출 시 함수에 인자를 넘길 때&quot; &quot;값을 사용하는 것&quot;을 의미한다.</p>
<h4 id="3할당된-메모리가-더-이상-필요-없을-때-해제">3.할당된 메모리가 더 이상 필요 없을 때 해제</h4>
<p>할당된 메모리를 해제하려면 할당된 메모리가 더 이상 필요하지 않은 시기를 결정해야 하는데, 
이를 잘못하면 메모리 누수가 발생하게 된다. 그러므로 메모리 누수 문제는 할당한 메모리를 적절히 해제하지 못해서 발생한다고 볼 수 있다.</p>
<p>C, C++과 같은 로우 레벨 언어에서는 개발자가 메모리 해제 시기를 직접 결정해야 한다. 프로그램에서 할당된 메모리가 더 이상 필요하지 않을 때, 직접 메모리 할당을 해제해야 한다.</p>
<p>자바스크립트와 같은 몇몇 하이 레벨 언어에서는 &quot;가비지 컬렉션(GC)&quot;이라는 &quot;자동 메모리 관리형식&quot;을 활용한다. </p>
<p>가비지 콜렉터의 목적은 메모리 할당을 모니터링하고 할당된 메모리의 영역이 더 이상 필요하지 않은 시점을 확인하여 회수하는 것이다.</p>
<h3 id="가비지-콜렉터-동작과정">가비지 콜렉터 동작과정</h3>
<h4 id="참조-reference">참조 (Reference)</h4>
<p>가비지 콜렉션 알고리즘의 핵심 개념은 참조이다.</p>
<p>A라는 메모리를 통해 (명시적이든 암시적이든) B라는 메모리에 접근할 수 있다면 &quot;B는 A에 참조된다.&quot;라고 이야기한다.</p>
<p>예를 들어 자바스크립트에서 모든 객체는 prototype 객체를 암시적으로 참조하고, 그 객체의 속성을 명시적으로 참조한다</p>
<h4 id="참조-세기-reference-counting-가비지-컬렉션-알고리즘">참조 세기 (Reference Counting) 가비지 컬렉션 알고리즘</h4>
<p>이 알고리즘은 &quot;더 이상 필요 없는 객체&quot;를 &quot;어떤 다른 객체도 참조하지 않는 객체&quot;라고 정의한다.
특정 객체를 참조하는 객체가 하나도 없다면, 그 객체에 대해 가비지 컬렉션을 수행한다.</p>
<pre><code class="language-java">
var o = {
  a: {
    b: 2
  }
};</code></pre>
<p>여기서 각 객체는 모두 참조되고 있기 때문에 가비지 컬렉션이 수행될 객체는 없다.</p>
<pre><code class="language-java">
let x = {
  a: {
    b: 2
  }
}</code></pre>
<p>할당된 모든 메모리가 참조당하고 있는 상태로, 가비지가 없는 상태
전역 변수는 가비지 컬렉션의 대상이 아니므로 x에 대한 카운팅을 제외</p>
<pre><code class="language-java">let y = x
x = 1</code></pre>
<p>변수 y에 변수 x를 대입하여 객체의 메모리 주소를 연결
변수 x에는 1을 할당하여 객체와의 연결을 끊은 상태
할당된 모든 메모리가 참조당하고 있는 상태로, 가비지가 없는 상태</p>
<pre><code class="language-java">let z = y.a.b
y = &#39;bumsu&#39;</code></pre>
<p>변수 z에 y.a.b를 대입하면 객체 b의 메모리 주소가 연결됨
변수 y에는 문자열을 할당하여 객체 a와의 연결을 끊은 상태
*객체 a를 참조하는 변수가 하나도 없기 때문에 가비지로 인식하고 메모리 공간을 해제</p>
<pre><code class="language-java">z = null</code></pre>
<p>변수 z에 null을 대입하여 객체 b와의 연결을 끊은 상태
*객체 b가 가비지로 인식되어 메모리 공간이 해제되고, 그에 따라 숫자 2도 메모리 해제</p>
<h4 id="한계-순환-참조">한계: 순환 참조</h4>
<p><img src="https://velog.velcdn.com/images/fe_jungseok/post/3850df25-0169-4f08-bc3a-f4fe16edc7c5/image.png" alt=""></p>
<p>이 알고리즘은 두 객체가 서로를 참조하면 문제가 발생한다. 두 객체 모두 더 이상 사용하지 않더라도 가비지 컬렉션을 수행할 수 없게 된다.</p>
<pre><code class="language-java">
function f() {
  var x = {}; 
  var y = {};

  x.a = y;
  y.a = x;
  return &#39;azerty&#39;;
}

f();</code></pre>
<p>위 코드에서 f 함수가 종료되고 나면, x, y에 저장한 객체는 사용되지 않으므로 가비지 컬렉션이 수행되어야 한다. </p>
<p>하지만 Reference-counting(참조-세기) 알고리즘에서는 두 객체 모두 참조를 가지고 있기 때문에 가비지 콜렉션이 수행되지 않는다.</p>
<h4 id="mark-and-sweep-알고리즘">Mark and Sweep 알고리즘</h4>
<p><img src="https://velog.velcdn.com/images/fe_jungseok/post/465cfdec-dbaa-4f0d-bddb-d74e881f40a1/image.png" alt=""></p>
<p>이 알고리즘에서는 &quot;더 이상 필요 없는 객체&quot;를 &quot;닿을 수 없는 객체&quot;로 정의한다. 이름에서 알 수 있듯이 무엇인 가에 표시(Mark)를 하고, 정리하는(Sweep) 알고리즘이다.</p>
<p>이 알고리즘은 roots라는 객체의 집합을 가지고 있다.(자바스크립트에서는 전역 변수들을 의미)</p>
<p>주기적으로 가비지 콜렉터는 roots로부터 시작하여 roots가 참조하는 객체들, roots가 참조하는 객체가 참조하는 객체들을 접근할 수 있는 객체라고 표시한다. 그 후, 접근할 수 없는 객체에 대해 가비지 컬렉션을 수행한다.</p>
<p>이 알고리즘은 &quot;참조되지 않는 객체&quot;는 모두 &quot;접근할 수 없는 객체&quot;이지만 역은 성립하지 않기 때문에 참조-세기 알고리즘보다 효율적이라고 할 수 있다.</p>
<pre><code class="language-java">
function f() {
  var x = {}; 
  var y = {};

  x.a = y;
  y.a = x;
  return &#39;azerty&#39;;
}

f();</code></pre>
<p>위 코드에서 함수 f가 리턴되고 나면, 전역 변수들에서 x, y에 담긴 객체들에 접근할 수 있는 방법이 없다. 따라서 두 객체에 대해 가비지 컬렉션이 수행될 수 있습니다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[호출 스케줄링]]></title>
            <link>https://velog.io/@fe_jungseok/%ED%98%B8%EC%B6%9C-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81</link>
            <guid>https://velog.io/@fe_jungseok/%ED%98%B8%EC%B6%9C-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81</guid>
            <pubDate>Mon, 19 Dec 2022 09:39:20 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/fe_jungseok/post/1d2c432a-888d-4f29-9846-f7dad90d4e74/image.png" alt=""></p>
<p>타이머 함수를 사용하여 명시적으로 호출하지 않고, 일정 시간이 지난 이후 또는 반복적으로 호출되도록 &quot;함수 호출을 예약&quot;하는 것 을 &quot;호출 스케쥴링&quot;이라고 합니다.</p>
<h3 id="settimeout-cleartimeout">setTimeout/ clearTimeout</h3>
<ul>
<li><p>setTimeout &quot;첫 번째 인수인 콜백 함수&quot;는 &quot;두 번째 인수로 전달받은 시간이 경과 한 이후&quot; &quot;실행 되도록 호출 스케줄링된다.</p>
</li>
<li><p>setTimeout 함수는 생성된 타이머를 식별할 수 있는 고유한 타이머를 &quot;식별할 수 있는 고유한 id를 반환&quot;한다.</p>
</li>
<li><p>setTimeout 함수가 반환한 타이머 id는 ① 브라우저 환경일 경우 &quot;숫자&quot;이며 ② Node.js 환경인 경우 &quot;객체&quot;다</p>
</li>
<li><p>setTimeout 함수가 반환한 타이머 id를 clearTimeout 함수의 인수로 전달하여 타이머를 취소할 수 있다.</p>
</li>
<li><p>setTimeout 함수로 생성한 타이머는 한 번 동작합니다.</p>
</li>
</ul>
<pre><code class="language-java">
// 1초(1000ms) 후 타이머가 만료되면 콜백 함수가 호출된다.
setTimeout(() =&gt; console.log(&quot;Hi!&quot;), 1000);

// 세 번째 인수로 문자열 &#39;Lee&#39; 인수로 전달
setTimeout((name) =&gt; console.log(`Hi! ${name}.`), 1000, &quot;Lee&quot;);

// 두 번째 인수(delay)를 생략하면 기본값 0이 지정된다.
setTimeout(() =&gt; console.log(&quot;Hello!&quot;));


//setTimeout 함수가 반환한 타이머 id를 clearTimeout 함수의 인수로 전달하여 타이머를 취소할 수 있다.
const timerId = setTimeout(() =&gt; console.log(&quot;Hi!&quot;), 1000);

clearTimeout(timerId);</code></pre>
<h3 id="setinterval-clearinterval">setInterval/ clearInterval</h3>
<ul>
<li><p>setInterval의 &quot;첫 번째 인수인 콜백 함수&quot;는 &quot;두 번째 인수로 전달받은 시간이 경과할 때마다&quot; &quot;반복 실행&quot;되도록 호출 스케줄링된다.</p>
</li>
<li><p>setInterval의 함수는 생성된 타이머를 식별할 수 있는 고유한 타이머를 &quot;식별할 수 있는 고유한 id를 반환&quot;한다.</p>
</li>
<li><p>setInterval의 함수가 반환한 타이머 id는 ① 브라우저 환경일 경우 &quot;숫자&quot;이며 ② Node.js 환경인 경우 &quot;객체&quot;다</p>
</li>
<li><ul>
<li>setTimeout 함수가 반환한 타이머 id를 clearInterval 함수의 인수로 전달하여 타이머를 취소할 수 있다.</li>
</ul>
</li>
<li><p>setInterval 함수로 생성한 타이머는 반복적으로 동작합니다.</p>
</li>
</ul>
<pre><code class="language-java">
let count = 1;

const timeoutId = setInterval(() =&gt; {
  console.log(count); // 1 2 3 4 5

  if (count++ === 5) clearInterval(timeoutId);
}, 1000);

console.log(&quot;timeoutId: &quot;, timeoutId);</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[값에 의한 전달, 참조에 의한 전달]]></title>
            <link>https://velog.io/@fe_jungseok/%EA%B0%92%EC%97%90-%EC%9D%98%ED%95%9C-%EC%A0%84%EB%8B%AC-%EC%B0%B8%EC%A1%B0%EC%97%90-%EC%9D%98%ED%95%9C-%EC%A0%84%EB%8B%AC</link>
            <guid>https://velog.io/@fe_jungseok/%EA%B0%92%EC%97%90-%EC%9D%98%ED%95%9C-%EC%A0%84%EB%8B%AC-%EC%B0%B8%EC%A1%B0%EC%97%90-%EC%9D%98%ED%95%9C-%EC%A0%84%EB%8B%AC</guid>
            <pubDate>Mon, 19 Dec 2022 07:24:22 GMT</pubDate>
            <description><![CDATA[<h3 id="데이터-전달pass-by-value">데이터 전달(pass by value)</h3>
<p>데이터를 변수에서 다른 변수로 전달할 때 &quot;값에 의한 전달&quot;과 &quot;참조에 의한 전달 방식&quot;이 있다.</p>
<p>이 전달 방식은 데이터 타입에 따라 다른다</p>
<ul>
<li>원시(Primirive) 타입:    값의 전달 </li>
<li>객체(Object) 타입:    참조의 전달 </li>
</ul>
<h3 id="값에-의한-전달pass-by-reference">값에 의한 전달(pass by reference)</h3>
<p>원시타입의 데이터값이 들어있는 변수를 다른 변수로 대입하면 값에 의한 전달이 발생하는데
이때 변수에 들어있는 데이터값을 다른 변수에 전달 된다.</p>
<p>이때 한 변수의 데이터값을 재할당하면, 두 변수는 별도의 메모리 주소를 가지므로 변경된 값을 공유 하지 않는다</p>
<p><img src="https://velog.velcdn.com/images/fe_jungseok/post/5a6c8973-05d7-4503-bd75-32975a1f6258/image.png" alt=""></p>
<pre><code class="language-java">
let bar = 1;
let foo = bar;
bar = 500
console.log(foo);  // 결과: 100</code></pre>
<h3 id="참조에-의한-전달">참조에 의한 전달</h3>
<p>자바스크립트에서 원시타입을 제외한 모든 데이터는 참조타입인데, 참조타입은 원시타입과 다르게 
대입과정에서 데이터값을 전달하는게 아닌, 데이터가 들어있는 메모리주소가 전달되고, 이것을 참조에 의한 전달이라고 한다. </p>
<p>이때 한 변수의 데이터를 변경하면 , 두 변수는 같은 메모리 주소를 가르키므로 똑같이 데이터 변경이 일어난다</p>
<p><img src="https://velog.velcdn.com/images/fe_jungseok/post/73d50c89-e8d7-4f5a-9aba-bd1654bd2360/image.png" alt=""></p>
<pre><code class="language-java">
let foo = {num:1}
let bar = a;
foo.num = 10;
console.log(bar.num);  // 결과: 10</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[명령형 프로그래밍 vs 선언형 프로그래밍]]></title>
            <link>https://velog.io/@fe_jungseok/%EB%AA%85%EB%A0%B9%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-vs-%EC%84%A0%EC%96%B8%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</link>
            <guid>https://velog.io/@fe_jungseok/%EB%AA%85%EB%A0%B9%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-vs-%EC%84%A0%EC%96%B8%ED%98%95-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</guid>
            <pubDate>Sat, 17 Dec 2022 13:52:17 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/fe_jungseok/post/1a852a54-264a-49eb-8886-2f8fd5790485/image.png" alt=""></p>
<p>두 프로그래밍 기법은  무엇(What)을 할 것인지, 어떻게(How) 할 건지 중에 어디에 중점을 두냐에 따라 나뉜다.</p>
<p>예시)</p>
<p>명령형(HOW): 집을 나가서 오른쪽으로 50미터 직진후 CU 에서 오른쪽으로 꺾어. 수할인마트에 들어가서 삼겹살 집어서 계산대로 가. 그러고 만원짜리 하나 드리고 100원 거슬러 받아와.</p>
<p>선언형(HOW): 삼겹살 사와</p>
<p>물론 선언적 방식의 접근을 위해서는 명령형 방식으로 &#39;어떻게 접근하는가&#39;가 먼저 추상화가 되어있어야 한다.</p>
<p>삼겹살을 사와라고 심부름을 시키는 것은 마트가 어디인지 알고, 거래를 할줄 안다 등등을 알고 있다고 전제하는 것이다.</p>
<h4 id="참고">참고</h4>
<p>명령적 언어: C, C++, Java
선언적 언어: SQL, HTML
Mix: Javascript, C#, Python</p>
<h3 id="명령형-프로그래밍">명령형 프로그래밍</h3>
<p>무엇(What)을 할 것인지 나타내기보다 어떻게(How) 할 건지를 설명하는 프로그래밍 방식</p>
<pre><code class="language-java">
// 배열을 파라미터로 받고 각 요소들의 값에 2를 곱하는 함수
function double (arr) {
  let results = []
  for (let i = 0; i &lt; arr.length; i++){
    results.push(arr[i] * 2)
  }
  return results
}</code></pre>
<p>위의 코드는 명령형 프로그래밍 방식으로 작성한 코드이다.
명시적으로 배열을 반복하거나 원하는 기능을 수행하는 방법에 대한 단계를 설명하고 있다.</p>
<p>위 코드는 &#39;상태&#39;의 일부를 변경하고 있다 (&#39;상태&#39; : 기본적으로 메모리에 저장된 것에 대한 정보)</p>
<h4 id="예시">예시</h4>
<p>절차지향 프로그래밍: 수행되어야 할 순차적인 처리 과정을 포함하는 방식 (C, C++)
객체지향 프로그래밍: 객체들의 집합으로 프로그램의 상호작용을 표현 (C++, Java, C#)</p>
<h3 id="선언형-프로그래밍">선언형 프로그래밍</h3>
<p>=어떻게 할건지(How)를 나타내기보다 무엇(What)을 할 건지를 설명하는 프로그래밍 방식</p>
<p>함수형 프로그래밍: 순수 함수를 조합하고 소프트웨어를 만드는 방식 (클로저, 하스켈, 리스프)</p>
<pre><code class="language-java">
function double (arr) {
  return arr.map((item) =&gt; item * 2)
}</code></pre>
<p>위의 코드는 명령형 프로그래밍에서 나왔던 코드를 선언형으로 변환한 코드인데, 명령형에서 기능을 수행하는것을 명시적으로 나타냈다면 선언형은 명령형 방식이 추상화된 것을 알 수 있다.</p>
<p>선언형 프로그래밍의 또 다른 이점은 프로그램이 상황에 독립적이다. 
종종 명령형 코드는 현재 상태의 컨텍스트에 의존하기 때문에 재사용하기 어려운 경우가 많다. </p>
<p>하지만 선언형 코드는 해당 코드가 달성하고자 하는 것이 무엇인지 만을 나열하기 때문에 동일한 코드를 다른 프로그램에서 재사용하기 쉽다.</p>
<h4 id="예시-1">예시</h4>
<p>함수형 프로그래밍: 순수 함수를 조합하고 소프트웨어를 만드는 방식 (클로저, 하스켈, 리스프)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[고차함수]]></title>
            <link>https://velog.io/@fe_jungseok/%EA%B3%A0%EC%B0%A8%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@fe_jungseok/%EA%B3%A0%EC%B0%A8%ED%95%A8%EC%88%98</guid>
            <pubDate>Sat, 17 Dec 2022 12:26:03 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/fe_jungseok/post/660e11e1-c661-40cb-81a7-76fec9ec6ccd/image.png" alt=""></p>
<h3 id="고차-함수">고차 함수</h3>
<p>고차 함수는 함수를 인수로 전달받거나, 함수를 반환하는 함수를 말한다.</p>
<p>고차함수는 함수형 프로그래밍의 일종으로, 자바스크립트를 함수형 프로그래밍에 알맞은 언어로 만들어주는 특성이 바로 자바스크립트가 고차 함수이다.</p>
<p>이 고차함수를 이해하기 위해선 함수형 프로그래밍과 일급객체를 먼저 이해해야 한다.</p>
<h3 id="함수형-프로그래밍">함수형 프로그래밍</h3>
<p>함수형 프로그래밍은 순수 함수와 보조 함수의 조합을 통해 조건문과 반복문을 제거하여 복잡성을 해결하고 변수의 사용을 억제하여 상태 변경과 부수효과를 피하려는 프로그래밍 패러다임이다.</p>
<h4 id="부수효과">부수효과</h4>
<p>부수효과란 다음과 같은 변화 또는 변화가 발생하는 작업을 의미한다.</p>
<ul>
<li>변수의 값이 변경됨</li>
<li>자료 구조를 제자리에서 수정함</li>
<li>객체의 필드값을 설정함</li>
<li>예외나 오류가 발생하며 실행이 중단됨</li>
<li>콘솔 또는 파일 I/O가 발생함</li>
</ul>
<h4 id="순수-함수">순수 함수</h4>
<p>부수 효들을 제거한 함수들을 순수 함수이라고 부르며, 함수형 프로그래밍에서 사용하는 함수는 이러한 순수 함수들이다.</p>
<ul>
<li>Memory or I/O의 관점에서 Side Effect가 없는 함수</li>
<li>함수의 실행이 외부에 영향을 끼치지 않는 함수</li>
</ul>
<h3 id="일급객체">일급객체</h3>
<p>일급 객체 란 객체들에 적용 가능한 연산을 모두 지원하는 객체를 가리킨다.</p>
<p>아래와 같은 특성을 보이기 때문에 자바스크립트에서 함수를 일급객체로 취급한다.</p>
<p>1) 변수(variable)에 담을 수 있다.</p>
<pre><code class="language-java">// 변수에 함수 할당
var bar = fucntion() { return &#39;javscript&#39;; };
console.log(bar()); // javascript</code></pre>
<p>2) 다른 함수를 인자(argument)로 받는다.</p>
<pre><code class="language-java">var test = function(func) {
   func(); // 파라미터로 받은 함수 호출
}

// test() 함수에 다른 함수를 파라미터로 넣어 호출
test(function() {
   console.log(&#39;javascript&#39;);
});</code></pre>
<h4 id="인수인자">인수,인자</h4>
<p><img src="https://velog.velcdn.com/images/fe_jungseok/post/923a1e8d-2a0a-45fd-8e1d-f30a3b1e9918/image.png" alt=""></p>
<ul>
<li>인자: 함수를 정의할 때 사용되는 변수를 인자(매개변수)</li>
<li>인수: 실제로 함수가 호출할 때 넘기는 변수</li>
</ul>
<p>3) 다른 함수의 결과로 리턴 될 수 있다.</p>
<pre><code class="language-java">// 함수를 리턴하는 test() 함수
function test() {
   return function() {
       console.log(&#39;javscript&#39;);
   }
}

var bar = test();
bar();</code></pre>
<h4 id="함수가-일급객체이기-때문에-할-수-있는-것은-무엇인가">함수가 일급객체이기 때문에 할 수 있는 것은 무엇인가?</h4>
<ul>
<li>고차함수(Higher order function)를 만들 수 있다.</li>
<li>콜백(callback)을 사용할 수 있다.</li>
</ul>
<h3 id="결론">결론</h3>
<p>고차 함수는 함수를 인자로 받거나 또는 함수를 반환함으로써 작동 하는 함수를 말한다. 간단히 말하자면, 고차 함수는 함수를 인자로 받거나 함수를 반환하는(return) 함수를 말한다. (위의 일급객체 특징 2,3번 참고)</p>
<p> 고차 함수들은 파라미터로 콜백 함수를 받아 사용되기 때문에, 원본 배열을 바탕으로 하는 새로운 결과값을 창조하는데 사용된다</p>
<p>결론은 고차 함수는 일반적인 함수인데 함수를 인자로 받고 함수를 반환할 수 있는 추가적인 기능을 가진 것이라고 이해하시면 된다.</p>
<p>ex) 고차함수: Array.prototype.map, Array.prototype.filter</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[모듈]]></title>
            <link>https://velog.io/@fe_jungseok/%EB%AA%A8%EB%93%88</link>
            <guid>https://velog.io/@fe_jungseok/%EB%AA%A8%EB%93%88</guid>
            <pubDate>Fri, 16 Dec 2022 17:40:50 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/fe_jungseok/post/13188bd6-42da-4308-b714-c1d889fbf852/image.png" alt=""></p>
<h3 id="모듈module">모듈(module)</h3>
<p>여러 기능들에 관한 코드가 모여있는 하나의 파일
모듈은 자신만의 파일 스코프(모듈 스코프)를 가질 수 있어야 한다.</p>
<p>자신만의 파일 스코프를 갖는 모듈의 자산(모듈에 포함되어 있는 변수, 함수, 객체 등)은 기본적으로 비공개 상태다.</p>
<p>즉, 모듈은 개별적 존재로서 애플리케이션과 분리되어 존재한다.</p>
<p>하지만 애플리캐이션과 분리되어 개별적으로 존재하는 모듈은 재사용이 불가능하므로 존재의 의미가 없다.</p>
<h3 id="export-import">export, import</h3>
<p>모듈은 공개가 필요한 자산에 한정하여 export 키워드를 사용해 명시적으로 선택적 공개가 가능하다.
공개(export)된 자산은 다른 모듈에서 재사용할 수 있다. (의존성을 갖게 된다)</p>
<p>이때 공개된 모듈의 자산을 사용하는 모듈을 모듈 사용자(module consumer)라고 한다
모듈 사용자가 특정 모듈이 공개(export)한 자산 중 일부 또는 전체를 import 키워드를 통해 자신의 스코프 내로 불러들여 재사용할 수 있다</p>
<p>자바스크립트는 기본적으로 모듈이 성립하기 위해 필요한 파일 스코프와 import, export를 지원하지 않는다.</p>
<p>따라서 자바스크립트를 클라이언트 사이드, 즉 브라우저 환경에 국한하지 않고 범용적으로 사용하려는 움직임이 생기면서 이러한 상황에 제안된 것이 CommonJS 와 AMD(asynchronous module definition)이다.</p>
<h3 id="commonjs">CommonJS</h3>
<p>자바스크립트의 공식 스펙이 브라우저만 지원했기 때문에 이를 서버사이드 및 데스크탑 어플리케이션에서 지원하기 위한 노력이 있었다. </p>
<p>그걸 위해 만든 그룹이 CommonJS이며 여기선 자바스크립트가 범용적인 언어로 쓰이기 위한 스펙을 정의하고 있다. </p>
<p>그룹을 만들었을 때,범용적인 언어로 만들기 위해서는 모듈화의 개념이 필요했고 이 그룹만의 모듈 방식을 정의하게 되었는데 그것이 바로 CommonJS 방식의 모듈화다.</p>
<p>다른 모듈을 사용할 때는 require 를, 모듈을 해당 스코프 밖으로 보낼 때에는 module.exports 를 사용하는 방식으로, Node.js에선 현재 이 방식을 사용하고 있다.</p>
<pre><code class="language-java">const printHelloWorld = () =&gt; {
  console.log(&#39;Hello Wolrd&#39;);
};

module.exports = {
  printHelloWorld
};
// &lt;a.js&gt;</code></pre>
<pre><code class="language-java">const func = require(&#39;./a.js&#39;); // 같은 디렉토리에 있다고 가정
func.printHelloWorld();
// &lt;b.js&gt;</code></pre>
<p>여기서 module.exports 의 module 은 현재 모듈에 대한 정보를 갖고 있는 객체이다. 
이는 예약어이며 그 안에 id , path , parent 등의 속성이 있고 exports 객체를 가지고 있다.</p>
<h4 id="exports-vs-moduleexports">exports vs module.exports</h4>
<p>module.exports 외에도 exports 를 사용하기도 하는데 이 관계에 대해서 명확히 이해하고 있어야 한다.</p>
<p>module.exports: 빈 객체를 참조한다.
exports: module.exports 를 참조한다.
require: 항상 module.exports 를 리턴받는다.</p>
<p>즉, 함수를 모듈 밖으로 내보내고자 할 때는 위에 예시에서 2가지 모두 사용할 수 있다.</p>
<p>exports.printHelloWorld = printHelloWorld;
module.exports = { printHelloWorld };</p>
<p>그렇다면 왜 2가지를 설정해놓았을까?</p>
<p>그 이유는 exports 는 항상 module.exports 를 참조하기 때문에 exports 를 사용하면 직접 module.exports 를 수정하지 않고 객체의 멤버를 만들거나 수정하는 방식으로 사용한다.</p>
<p>따라서, exports 에 어떤 값을 할당하거나 새로운 객체를 할당했다고 하더라도
결국 require 는 module.exports 를 리턴받기 때문에 잠재적인 버그를 피할 수가 있다.</p>
<h3 id="amdasynchronous-module-definition">AMD(asynchronous module definition)</h3>
<p>CommonJS 그룹에서 의견이 맞지 않아 나온 사람들이 만든 그룹으로 비동기 모듈에 대한 표준안을 다루는 그룹이다.</p>
<p>CommonJS가 서버쪽에서 장점이 많은 반면에 AMD는 브라우저 쪽에서 더 큰 효과를 발휘한다. 
브라우저에서는 모든 모듈이 다 로딩될 때까지 기다릴 수 없기 때문에 비동기 모듈 로딩방식으로 구현을 해놓았다.</p>
<p>이 방식에서 사용하는 함수는 define() 과 require() 이며 AMD 스펙을 가장 잘 구현한 모듈로더는 RequireJS 이다.</p>
<pre><code class="language-java">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
  &lt;title&gt;Document&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;script data-main=&quot;index.js&quot; src=&quot;require.js&quot;&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
&lt;index.html&gt;</code></pre>
<p>require.js 파일을 받아서 script 태그에 넣어주고 data-main 속성으로 require.js 가 로드된 후에 실행할 자바스크립트 파일 경로를 넣어준다.</p>
<p>즉, require.js 가 로드되자마자 index.js 가 실행되는 구조이다.</p>
<pre><code class="language-java">
require.config({
  baseUrl: &#39;/&#39;,
  paths: {
    a: &#39;a&#39;,
    b: &#39;b&#39;,
  }
});

require([&#39;a&#39;], (a) =&gt; {
  a.printA();
});
// index.js</code></pre>
<p>require.config 는 설정부분으로 기본 경로와 각 모듈에 해당하는 경로를 설정해준다. 
그 다음 require 를 통해서 첫번째 인자에 해당하는 모듈이 로드되었을 경우에 그걸 a 로 받아서 
printA() 함수를 호출하는 콜백함수를 실행한다. 의존성 모듈을 지정해주는 것이다.</p>
<pre><code class="language-java">define(() =&gt; {
  return {
    printA: () =&gt; console.log(&#39;a&#39;)
  }
});
// a.js</code></pre>
<p>모듈 a는 위와 같이 만들어져 있고 define() 을 통해서 정의된다. 
여기서도 require() 에서 의존성 모듈을 설정해준 것처럼 콜백함수가 실행되기 전에 로드되어야 할 모듈들을 지정해줄 수 있다.</p>
<h3 id="umduniversal-module-definition">UMD(Universal Module Definition)</h3>
<p>위에서 살펴본 바로, 모듈 구현방식이 CommonJS 와 AMD로 나뉘기 때문에 그걸 통합하기 위한 하나의 패턴이라고 할 수 있다.</p>
<p>AMD, CommonJS, Browser 방식의 모듈을 지원하기 위한 것으로 확인하는 방식은 코드를 살펴보면 다음과 같다.</p>
<pre><code class="language-java">
(function (root, factory) {
    if (typeof define === &#39;function&#39; &amp;&amp; define.amd) {
        // AMD. Register as an anonymous module.
        define([], factory);
    } else if (typeof module === &#39;object&#39; &amp;&amp; module.exports) {
        // Node. Does not work with strict CommonJS, but
        // only CommonJS-like environments that support module.exports,
        // like Node.
        module.exports = factory();
    } else {
        // Browser globals (root is window)
        root.returnExports = factory();
  }
}(typeof self !== &#39;undefined&#39; ? self : this, function () {

    // Just return a value to define the module export.
    // This example returns an object, but the module
    // can return a function as the exported value.
    return {};
}));
</code></pre>
<p>AMD: define() 이 함수이고 define.amd 속성의 객체를 가지고 있다.
CommonJS: module 이 객체이고 module.exports 속성의 객체를 가지고 있다.
Browser: 따로 특이사항이 없다.</p>
<p>통합하는 방식은 2개의 인자를 전달받는 함수를 실행하는 것으로, 
첫번째 인자는 Browser 쪽을 구현할 root 에 넘길 값으로 undefined 이면 this 로 아니라면 self , 즉 window 로 설정한다. </p>
<p>2번째 인자로 빈 객체 리터럴을 리턴하는 함수를 보낸다. 이렇게 되면 각각의 환경에서 모두 모듈개념을 사용할 수 있게 된다.</p>
<h3 id="es6">ES6</h3>
<p>import 와 export ES6문법이다.</p>
<p>모든 브라우저가 지원하는 것이 아니기 때문에 Babel의 @babel/plugin-transform-modules-commonjs 를 통해 변환시켜서 사용한다.</p>
<pre><code class="language-java">const A = () =&gt; {};
export default A;

// moduleA.js</code></pre>
<pre><code class="language-java">export const B = () =&gt; {};

//// moduleB.js</code></pre>
<pre><code class="language-java">import A from &#39;moduleA&#39;;
import { B } from &#39;moduleB&#39;;

//index.js</code></pre>
<p>export 를 사용할 때는 named export 와 default export 를 사용할 수 있다.</p>
<p>default export:모듈 내에서 한번만 사용할 수 있고, import 에선 내보낸 이름 그대로 바로 사용할 수 있지만
named export: 여러번 사용할 수 있다는 것이다. {} 로 묶어서 불러와야 한다. </p>
<h3 id="모듈의-장점">모듈의 장점</h3>
<p>유지보수성 : 기능들이 모듈화가 잘 되어있다면, 의존성을 그만큼 줄일 수 있기 때문에, 어떤 기능을 개선한다거나 수정할 때 훨씬 편하게 할 수 있다.</p>
<p>네임스페이스화 : 자바스크립트에서 전역변수는 전역공간을 가지기 때문에 코드의 양이 많아질수록 겹치는 네임스페이스가 많아질 수 있다.
그러나 모듈로 분리하면 &quot;모듈만의 네임스페이스&quot;를 갖기 때문에 그 문제가 해결된다.</p>
<p>재사용성 : 똑같은 코드를 반복하지 않고 모듈로 분리시켜서 필요할 때마다 재사용할 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JSON]]></title>
            <link>https://velog.io/@fe_jungseok/JSON</link>
            <guid>https://velog.io/@fe_jungseok/JSON</guid>
            <pubDate>Thu, 15 Dec 2022 22:17:33 GMT</pubDate>
            <description><![CDATA[<h3 id="json">JSON</h3>
<p>http 통신으로 데이터를 주고받을때 특정한 형식이 없으면 문제가 생긴다.
이러한 공통한 데이터 형식중 하나가 JSON이다.</p>
<ul>
<li>JavaScript Object Notation의 약자</li>
<li>클라이언트와 서버 간의 HTTP 통신을 위한 &quot;데이터 포맷&quot;이다.</li>
<li>자바스크립트에 종속되지 않는 언어 독립형 데이터 포맷으로, 대부분의 프로그래밍 언어에서 사용할 수 있다.</li>
<li>자바스크립트 객체 리터럴과 유사하게 키와 값으로 구성된 &quot;데이터 포맷&quot; 이다(프로퍼티 = key:value)</li>
<li>JSON 표현식은 사람과 기계 모두 이해하기 쉬우며 용량이 작아서, 최근에는 JSON이 XML을 대체해서 데이터 전송 등에 많이 사용한다.<br/>


</li>
</ul>
<h3 id="json-메서드">JSON 메서드</h3>
<h4 id="jsonstringifyarg-jsonstringifyarg는-객체를-문자열로-변환합니다">JSON.stringify(arg): JSON.stringify(arg)는 객체를 문자열로 변환합니다.</h4>
<pre><code class="language-java">var json = {&quot;test&quot; : &quot;value&quot;}

var incodingData = JSON.stringify(json);

//console.log(incodingData);</code></pre>
<h4 id="jsonparsearg-jsonparsearg는-문자열을-객체로-변환합니다">JSON.parse(arg): JSON.parse(arg)는 문자열을 객체로 변환합니다.</h4>
<pre><code class="language-java">var str = &#39;{&quot;test&quot; : &quot;value&quot;}&#39;;

var parsingData = JSON.parse(str);

//console.log(parsingData);</code></pre>
<h3 id="xml과-차이점">XML과 차이점</h3>
<h4 id="xml">XML</h4>
<ul>
<li>데이터 값 양쪽으로 태그가 있다.</li>
</ul>
<h4 id="json-1">JSON</h4>
<ul>
<li>태그로 표현하기 보다는 중괄호 {} 같은 형식으로 하고, 값을 &#39;,&#39;로 나열하기에 그 표현이 간단하다.</li>
</ul>
<h3 id="json-단점">JSON 단점</h3>
<p>AJAX 는 단순히 데이터만이 아니라 JavaScript 그 자체도 전달할 수 있다. </p>
<p>이 말은 JSON데이터라고 해서 받았는데 단순 데이터가 아니라 JavaScript가 될 수도 있고,
그게 실행 될 수도 있다. (데이터인 줄 알고 받았는데 악성 스크립트가 될 수 있습니다.)</p>
<p>위와 같은 이유로 받은 내용에서 순수하게 데이터만 추출하기 위한 JSON 관련 라이브러리를 따로 사용하기도 한다.
<br/></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[토큰 저장위치]]></title>
            <link>https://velog.io/@fe_jungseok/%ED%86%A0%ED%81%B0-%EC%A0%80%EC%9E%A5%EC%9C%84%EC%B9%98</link>
            <guid>https://velog.io/@fe_jungseok/%ED%86%A0%ED%81%B0-%EC%A0%80%EC%9E%A5%EC%9C%84%EC%B9%98</guid>
            <pubDate>Tue, 13 Dec 2022 12:33:58 GMT</pubDate>
            <description><![CDATA[<h2 id="토큰을-어디에-저장해야-안전할까">토큰을 어디에 저장해야 안전할까?</h2>
<p>브라우저에서 JWT를 저장할 수 있는 곳은 로컬스토리지, 쿠키 두군데가 있다. </p>
<p>하지만 로컬스토리지나 쿠키나 모두 자바스크립트로 읽을 수 있는 값들이기 때문에 
아무런 처리없이 이곳에 저장하면 굉장히 보안에 취약하다. </p>
<p>해커가 이미지 태그 혹은 브라우저 URL에 자바스크립트를 삽입 할 수 있는 취약점이 있다면 
이렇게 로컬스토리지나 쿠키에 저장된 토큰은 바로 허술하게 털려버린다.</p>
<p>브라우저의 로컬스토리지는 정말 편리하지만 XSS를 방어할 수 있는 방법이 없기 때문에 로컬스토리지보다는 쿠키가 그나마 더 보안에 낫다. 단, 이 쿠키카 Http Only이며 Secure(https)옵션이 켜져있을때 그렇다. 이 말은 쿠키를 자바스크립트로 읽어올 수 없다는 말이고 네트워크 감청을 통한 쿠키값 읽기를 방어한다는 말이다. 즉, XSS 공격을 통한 토큰 탈취를 방지할 수 있다.</p>
<h3 id="xss-공격cross-site-scripting">XSS 공격(Cross-Site Scripting)</h3>
<p><img src="https://velog.velcdn.com/images/fe_jungseok/post/d707012a-2914-401d-b2a8-a2c5cf2332e7/image.png" alt=""></p>
<p>공격자가 상대방의 브라우저에 스크립트가 실행되도록 해 사용자의 세션을 가로채거나, 웹사이트를 변조하거나, 악의적 콘텐츠를 삽입하거나, 피싱 공격을 진행하는 것을 말합니다
-&gt; 권한이 없는 사용자가 악의적인 용도로 웹 사이트에 스크립트를 삽입하는 공격 기법</p>
<p>그럼 Http Only Secure 쿠키에 액세스토큰과 리프레시 토큰을 둘다 저장해야 하는가? 라고 질문하면 그것도 그렇지 않다.</p>
<p>왜냐면, 쿠키라는것이 브라우저가 서버에 요청을 보낼떄 자동으로 포함해서 보내는 값이기 때문이다. 만약에 그 쿠키값안에 세션ID나 엑세스토큰이 들어있다면 해커가 내 인증정보를 활용해서 서버에 나인것처럼 속여서 요청을 보낼 수 있게 된다. 이게 CSRF공격이다. </p>
<h3 id="csrf-공격cross-site-request-forgery">CSRF 공격(Cross-Site Request Forgery)</h3>
<p><img src="https://velog.velcdn.com/images/fe_jungseok/post/6a097f45-f1f1-4c8f-bffd-729e6220cbbd/image.png" alt=""></p>
<p>보안은 시나리오를 생각해보면 이해가 빠른 것 같다. 내 사이트에 관리자로 로그인한 상태로(쿠키에 세션ID 혹은 엑세스토큰이 담겨져있다고 해보자.) 네이버 메일을 열었는데, 해커가 보낸 메일 속 이미지에 내 사이트 서버에 어떤 A 유저의 정보를 삭제하는 API 주소가 적혀있다고 해보자.</p>
<p>나는 그 유저 정보 삭제 API를 호출하고 싶지 않았는데 브라우저는 이미지 태그 안에 있는 스크립트를 자동으로 실행하기 때문에 갑자기 A유저 정보가 삭제되는 대참사가 발생한다. (내 브라우저 쿠키에는 인증 정보를 갖고 있기 때문에.. 브라우저 입장에서는 해커가 그 요청을 보낸게 아니라 내가 보낸게 되어버림..) 이게 바로 Cross Site Resource Forgery(교차 사이트 요청 위조 공격)이다.</p>
<h3 id="csrf-방지">CSRF 방지</h3>
<p>그러니까 이 문제를 방지하려면 항상 서버는 요청이 왔을때 그 요청이 진짜 내 사이트에서 왔는지 확인을 해야한다.</p>
<p>그런 방법으로는</p>
<ol>
<li><p>Referer 체크 (요청이 어디서 왔는가?)</p>
</li>
<li><p>CSRF 토큰 (난수 생성해서 서버에서 확인하는 방법)</p>
</li>
</ol>
<p>두가지가 있다. 아무튼 여기까지가 CSRF에 대한 설명이다.</p>
<p>쿠키라는것이 결국에 브라우저에서 자동으로 보내는값이기 때문에 인증에 활용하기도 하지만 그것때문에 CSRF 보안에 취약하다. 그래서 결론은 리프레시 토큰만 http only secure 쿠키에 저장하고 액세스 토큰은 프로그램상 로컬변수에 담아 놓는것이 그나마 제일 안전하다.</p>
<p>이렇게 되면,</p>
<ol>
<li><p>해커가 CSRF 공격을 하더라도 쿠키에는 액세스토큰이 없기 때문에 인증 불가 상태가 되어 공격이 차단된다.</p>
</li>
<li><p>해커는 http only secure 쿠키 특성상 리프레시 토큰 자체를 털 방법이 없다.</p>
</li>
<li><p>액세스 토큰은 로컬 변수에 저장되어 있기 때문에 XSS를 통해 액세스 토큰 자체를 털 수 없다.
외부에서 삽입한 자바스크립트로 로컬 변수에 접근하는것이 불가능하기 때문에
-&gt; 물론 액세스 토큰을 활용하여 유저 정보를 탈취할 수 는있다. (그래서 어찌됬건 XSS 처리는 꼭 해야함)</p>
</li>
</ol>
<p>XSS는 완벽하게 막을 수 없는데 그 이유는 어찌됬건 내가 인증을 한 상태에서는 서버에서 나에게 허용된 어떤 API들이 있는데 그 API들은 마찬가지로 XSS를 통해 해커도 호출할 수 있다는 얘기기 때문이다.</p>
<p>어쨌든 액세스토큰은 지속적으로 네트워크를 타며 노출될 가능성이 높기 때문에 만료시간을 짧게 가져가야 한다.
그리고 쿠키에 저장된 리프레시토큰을 가지고 매번 액세스 토큰을 갱신해가면서 사용하도록 로직을 구성해야한다.</p>
<p>마지막으로, 사용성을 위해 액세스 토큰이 HTTP 헤더에 없거나 만료된 경우 리프레시 토큰으로 조용히 토큰 재발급 과정이 일어날 수 있도록 로직을 작성해야한다. (silent token refresh)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Headless 컴포넌트 (부제:관심사 분리)]]></title>
            <link>https://velog.io/@fe_jungseok/Headless-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%82%AC%EC%9A%A9%ED%95%B4-%EA%B4%80%EC%8B%AC%EC%82%AC-%EB%B6%84%EB%A6%AC</link>
            <guid>https://velog.io/@fe_jungseok/Headless-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%82%AC%EC%9A%A9%ED%95%B4-%EA%B4%80%EC%8B%AC%EC%82%AC-%EB%B6%84%EB%A6%AC</guid>
            <pubDate>Sun, 18 Sep 2022 09:02:06 GMT</pubDate>
            <description><![CDATA[<p>프론트엔드에서 Headless가 어떤 의미를 뜻할까? 먼저 프론트엔드 개발을 하면서 느껴봤을 법한 일을 떠올려보자.</p>
<h3 id="ui-라이브러리의-한계">UI 라이브러리의 한계</h3>
<p>외부 UI 라이브러리를 사용할 경우, 유스케이스에 맞게 기능을 새로 추가하거나 변경하고 싶어도 그에 맞게 디자인이나 기능을 수정하기가 매우 어렵다.</p>
<p>더 나아가 해당 라이브러리에 심각한 버그가 있거나, 유지보수를 종료한다고 하면 언젠가는 바꿔야 한다. 그러다 결국 ‘그냥 컴포넌트를 만들까?‘라는 생각을 문뜩 들게 한다.</p>
<p>그래서 나온 개념이 Headless UI Component로 기능은 있지만, 스타일이 없는 컴포넌트를 의미한다.</p>
<h3 id="component-기반-ui-라이브러리-vs-headless-ui-라이브러리">Component 기반 UI 라이브러리 vs Headless UI 라이브러리</h3>
<p>물론 언제나 Headless 라이브러리가 컴포넌트 기반의 라이브러리보다 좋다는 건 아니다. 모두 장단점이 존재하며, 상황에 맞게 사용하면 된다.</p>
<h4 id="component-기반-ui-라이브러리">Component 기반 UI 라이브러리</h4>
<p>Component 기반 UI 라이브러리는 기능과 스타일이 존재하는 라이브러리를 말하며, 대표적으로 Material UI, Ant Design가 있다.</p>
<h4 id="장점">장점</h4>
<ul>
<li>바로 사용할 수 있는 마크업과 스타일이 존재</li>
<li>설정이 거의 필요 없음<h4 id="단점">단점</h4>
</li>
<li>마크업을 자유롭게 할 수 없음</li>
<li>스타일은 대부분 라이브러리에 있는 테마 기반으로만 변경할 수 있어 한정적임</li>
<li>큰 번들 사이즈</li>
</ul>
<h4 id="headless-ui-라이브러리">Headless UI 라이브러리</h4>
<p>Headless는 기능은 있지만 스타일이 없는 라이브러리로, Headless UI, Radix UI, Reach UI 등이 있다.</p>
<h4 id="장점-1">장점</h4>
<ul>
<li>마크업과 스타일을 완벽하게 제어 가능</li>
<li>모든 스타일링 패턴 지원(ex. CSS, CSS-in-JS, UI 라이브러리 등)</li>
<li>작은 번들 사이즈<h4 id="단점-1">단점</h4>
</li>
<li>추가 설정이 필요함</li>
<li>마크업, 스타일 혹은 테마 모두 지원되지 않음</li>
</ul>
<p>디자인이 그렇게 중요하지 않고, 커스텀할 곳이 많지 않다면 Component 기반 라이브러리를 사용하면 된다. 하지만 만약 반응형에 따라 디자인이 달라지고, 기능 변경이나 추가가 많이 발생한다면 Headless 라이브러리가 유지보수에 더 좋을 것 같다.</p>
<h3 id="headless-component를-만드는-원칙">Headless Component를 만드는 원칙</h3>
<p>하지만 아직 Headless 라이브러리에는 컴포넌트의 종류가 상대적으로 적다. 그래서 바로 사용해야 하는 컴포넌트가 없다면 만들어야 한다.</p>
<p>사실 Headless Component를 만드는 원칙이라기 보다는, 유지보수 하기 좋은 컴포넌트를 만드는 원칙이라고 볼 수 있다.</p>
<p>만드려는 컴포넌트에 어떤 메서드가 있는지를 먼저 결정하기보다, 그 컴포넌트가 무엇을 수행할 수 있는지부터 결정해야 한다. 그리고 사용자가 사용할 수 있는 기능들과 방법을 제공해야 한다. 이후에 그 기능을 어떻게 수행할 지 구현하면 된다.</p>
<p>여기서 중요한 점은 기능은 어떻게 구현할지는 컴포넌트 내부에 정의하는 것으로, 외부의 다른 컴포넌트들이나 사용자가 전혀 알지 않아도 된다. 밑의 예시로 한 번 알아보자.</p>
<h3 id="checkbox-컴포넌트를-headless로-리팩토링하기">Checkbox 컴포넌트를 Headless로 리팩토링하기</h3>
<p><img src="https://velog.velcdn.com/images/fe_jungseok/post/bd234023-f744-47e8-8617-bcb834926bec/image.gif" alt=""></p>
<p>위와 같은 Checkbox 컴포넌트를 만든다면 아래와 같을 것이다.</p>
<pre><code class="language-java">//Checkbox.tsx

import { useState } from &#39;react&#39;

const Checkbox = () =&gt; {
  const [isChecked, setIsChecked] = useState(false)
  return (
    &lt;label&gt;
      &lt;input
        type=&quot;checkbox&quot;
        checked={isChecked}
        onChange={() =&gt; setIsChecked(!isChecked)}
      /&gt;
      &lt;span&gt;체크박스 만들기&lt;/span&gt;
    &lt;/label&gt;
  )
}
export default Checkbox</code></pre>
<p>이를 다른 곳에서 바로 사용할 수 있게 하려면 어떤 내용을 체크하는 지에 대한 라벨, 체크가 되었는지의 상태 값, 체크하는 로직을 props를 받아야 한다. 수정한다면 아래와 같은 형태가 될 것이다.</p>
<pre><code class="language-java">//Checkbox.tsx

type CheckboxProps = {
  label: string
  isChecked: boolean
  onChange: () =&gt; void
}

const Checkbox = ({ label, isChecked, onChange }: CheckboxProps) =&gt; {
  return (
    &lt;label&gt;
      &lt;input type=&quot;checkbox&quot; checked={isChecked} onChange={onChange} /&gt;
      &lt;span&gt;{label}&lt;/span&gt;
    &lt;/label&gt;
  )
}

export default Checkbox</code></pre>
<pre><code class="language-java">//App.tsx

export default function App() {
  const [isChecked, setIsChecked] = useState(false)
  return (
    &lt;Checkbox
      label=&quot;체크박스 만들기&quot;
      isChecked={isChecked}
      onChange={() =&gt; setIsChecked(!isChecked)}
    /&gt;
  )
}</code></pre>
<p>만약 Checkbox를 사용하는 모든 곳에서 디자인과 기능이 동일하다면 이대로 사용해도 문제없다.</p>
<p>하지만 만약 특정 페이지들에서만 색상을 다르게 한다던지, 모바일에서는 체크박스를 오른쪽으로 옮겨야 한다던지 등의 레이아웃의 변경이 필요하다면 어떻게 해야할까? 디자인이 살짝 다르다는 이유로 컴포넌트를 새로 만들거나 내부에서 분기 처리하여 수정하기 시작한다면, 유지보수가 점점 더 힘들어질 것이다.</p>
<p>이럴 때 Headless 컴포넌트로 만들면 좋다. 다시 한 번 Headless 컴포넌트(aka. 유지보수 하기 좋은 컴포넌트)를 만드는 원칙들을 생각해보자.</p>
<ul>
<li>Checkbox 컴포넌트는 무엇을 하는 컴포넌트일까?</li>
<li>상태에 대한 라벨(설명)이 있다.</li>
<li>마우스로 체크박스나 라벨을 클릭할 수 있다.</li>
<li>체크가 안 된 상태라면 박스가 비어있고, 체크가 된 상태면 박스가 ✓ 아이콘이 생긴다.</li>
<li>사용자가 할 수 있는 기능은 무엇일까?</li>
<li>사용자는 Checkbox 컴포넌트를 마우스로 클릭할 수 있다.</li>
<li>사용자는 그저 Checkbox 컴포넌트를 클릭할 뿐, 컴포넌트 내부가 어떻게 구현되어 있는지는 알 수 없고, 알 필요도 없다.</li>
</ul>
<h2 id="headless-컴포넌트를-만드는-3가지-방법">Headless 컴포넌트를 만드는 3가지 방법</h2>
<h3 id="1-compound-component">1. Compound Component</h3>
<p>Material UI, Reach UI등 많은 UI 라이브러리가 Compound 컴포넌트를 사용한다.</p>
<p>Compound 컴포넌트란 같이 사용되는 컴포넌트들의 상태(state) 값을 공유할 수 있게 만들어주는 패턴이다. 코드로 한 번 알아보자.</p>
<pre><code class="language-java">//CheckboxWrapper.tsx

import * as React from &#39;react&#39;

type CheckboxContextProps = {
  id: string
  isChecked: boolean
  onChange: () =&gt; void
}

type CheckboxProps = CheckboxContextProps &amp; React.PropsWithChildren&lt;{}&gt;

const CheckboxContext = React.createContext&lt;CheckboxContextProps&gt;({
  id: &#39;&#39;,
  isChecked: false,
  onChange: () =&gt; {},
})

const CheckboxWrapper = ({
  id,
  isChecked,
  onChange,
  children,
}: CheckboxProps) =&gt; {
  const value = {
    id,
    isChecked,
    onChange,
  }
  return (
    &lt;CheckboxContext.Provider value={value}&gt;
      {children}
    &lt;/CheckboxContext.Provider&gt;
  )
}

const useCheckboxContext = () =&gt; {
  const context = React.useContext(CheckboxContext)
  return context
}

const Checkbox = ({ ...props }) =&gt; {
  const { id, isChecked, onChange } = useCheckboxContext()
  return (
    &lt;input
      type=&quot;checkbox&quot;
      id={id}
      checked={isChecked}
      onChange={onChange}
      {...props}
    /&gt;
  )
}

const Label = ({ children, ...props }: React.PropsWithChildren&lt;{}&gt;) =&gt; {
  const { id } = useCheckboxContext()
  return (
    &lt;label htmlFor={id} {...props}&gt;
      {children}
    &lt;/label&gt;
  )
}

CheckboxWrapper.Checkbox = Checkbox
CheckboxWrapper.Label = Label

export default CheckboxWrapper</code></pre>
<pre><code class="language-java">//App.tsx

import CheckboxWrapper from &#39;./CheckboxWrapper&#39;

export default function App() {
  const [isChecked, setIsChecked] = useState(false)
  return (
    &lt;CheckboxWrapper
      id=&quot;checkbox-1&quot;
      isChecked={isChecked}
      onChange={() =&gt; setIsChecked(!isChecked)}
    &gt;
      &lt;CheckboxWrapper.Checkbox /&gt;
      &lt;CheckboxWrapper.Label&gt;체크박스 만들기&lt;/CheckboxWrapper.Label&gt;
    &lt;/CheckboxWrapper&gt;
  )
}</code></pre>
<p>컴포넌트 내부에서 state를 공유하기 위해 Context API를 사용해서 처음에 작성해야 하는 코드가 꽤 많다.</p>
<p>하지만 컴포넌트를 사용하는 곳에서는 <CheckboxWrapper /> 하위에 어떤 컴포넌트가 있는지 볼 수 있고, 위치도 자유롭게 수정 가능하다.</p>
<h3 id="2-function-as-child-component">2. Function as Child Component</h3>
<p>Function as Child Component는 자식에 어떤 것이 들어올지 예상할 수 없기 때문에 children prop으로 받아 그대로 전달하는 것이다.</p>
<pre><code class="language-java">//CheckboxHeadless.ts

type CheckboxHeadlessProps = {
  isChecked: boolean
  onChange: () =&gt; void
}

const CheckboxHeadless = (props: {
  children: (args: CheckboxHeadlessProps) =&gt; JSX.Element
}) =&gt; {
  const [isChecked, setIsChecked] = useState(false)

  if (!props.children || typeof props.children !== &#39;function&#39;) return null

  return props.children({
    isChecked,
    onChange: () =&gt; setIsChecked(!isChecked),
  })
}

export default CheckboxHeadless</code></pre>
<pre><code class="language-java">//App.tsx
import CheckboxHeadless from &#39;./CheckboxHeadless&#39;

export default function App() {
  return (
    &lt;CheckboxHeadless&gt;
      {({ isChecked, onChange }) =&gt; {
        return (
          &lt;label&gt;
            &lt;input type=&quot;checkbox&quot; checked={isChecked} onChange={onChange} /&gt;
            &lt;span&gt;체크박스&lt;/span&gt;
          &lt;/label&gt;
        )
      }}
    &lt;/CheckboxHeadless&gt;
  )
}</code></pre>
<p>Compound 컴포넌트보다 작성해야 하는 코드량이 훨씬 적다. 사용하려는 state 값을 위에서 따로 선언할 필요가 없어, 다른 컴포넌트에 해당 state를 실수로 넣을 일이 적어진다. 그리고 관련된 코드가 한 곳에 모여 있어 읽기 편하다. 하지만 다른 곳에서 해당 state를 공유할 경우, CheckboxHeadless가 감싸야 할 코드량이 많아지는 단점이 있다.</p>
<h3 id="3-custom-hooks">3. Custom hooks</h3>
<p>React를 사용해본 사람이라면 가장 익숙할 법한 커스텀 훅이다.</p>
<pre><code class="language-java">useCheckbox.ts

import { useState } from &#39;react&#39;

export const useCheckbox = () =&gt; {
  const [isChecked, setIsChecked] = useState(false)

  return {
    isChecked,
    onChange: () =&gt; setIsChecked(!isChecked),
  }
}</code></pre>
<pre><code class="language-java">//App.tsx

import { useCheckbox } from &#39;./useCheckbox&#39;

export default function App() {
  const { isChecked, onChange } = useCheckbox()
  return (
    &lt;label&gt;
      &lt;input type=&quot;checkbox&quot; checked={isChecked} onChange={onChange} /&gt;
      &lt;span&gt;체크박스 만들기&lt;/span&gt;
    &lt;/label&gt;
  )
}</code></pre>
<p>위의 두 방식보다 간단하고 직관적이다. 하지만 state 값을 사용되어야 하는 Checkbox 컴포넌트가 아니라 다른 곳에 작성할 실수가 발생할 수 있다.</p>
<h3 id="결론">결론</h3>
<p>Headless 컴포넌트는 스타일이 없고 로직만 존재하는 것을 뜻한다. 마크업과 스타일 수정이 자유롭기 때문에 기능 변경이 많은 곳에서 유용하다. 하지만 장단점이 명확하니 상황에 맞게 도입해야 한다.</p>
<p>그리고 사실 기능은 언제든 변경될 수 있다. 따라서 어느 컴포넌트든 유지보수 하기 좋은 컴포넌트를 만들어야 한다. 유지보수 하기 좋은 컴포넌트란, 변경에 쉽게 대응할 수 있는 컴포넌트다. Headless라는 개념도 변경에 쉽게 대응하기 위해 생겨난 것이라 생각한다.</p>
<p>변경에 쉽게 대응하기 위해서는 해당 컴포넌트가 무엇을 하는지 알아야 하며, 내부와 외부에 두어야 할 것을 완전히 분리해야 한다. 외부가 변경되었다 하더라도 내부 컴포넌트가 영향을 받아서도 안되고, 내부가 수정되었다 하더라도 외부가 변경되어서도 안된다</p>
<h3 id="출저">출저</h3>
<ul>
<li><a href="https://www.howdy-mj.me/design/headless-components/">https://www.howdy-mj.me/design/headless-components/</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Flux]]></title>
            <link>https://velog.io/@fe_jungseok/Flux</link>
            <guid>https://velog.io/@fe_jungseok/Flux</guid>
            <pubDate>Tue, 06 Sep 2022 13:29:06 GMT</pubDate>
            <description><![CDATA[<h2 id="flux-출현-배경">Flux 출현 배경</h2>
<p>기존의 어플리케이션 환경에서 보편적으로 사용되는 패턴은 MVC이다. </p>
<p><img src="https://velog.velcdn.com/images/fe_jungseok/post/59e50cd9-5f95-406d-bdf7-2ef29ca17282/image.png" alt=""></p>
<p>Model에 데이터를 정의해 두고, Controller를 이용해 Model 데이터를 생성, 조회, 수정, 삭제하고 변경된 데이터는 View에 출력되면서 사용자에게 전달된다.</p>
<p><img src="https://velog.velcdn.com/images/fe_jungseok/post/0ab6dc51-8b42-439d-a939-3a34b28b69e6/image.png" alt=""></p>
<p>이 패턴의 문제점은 어플리케이션의 규모가 커질수록 데이터 흐름의 복잡도가 엄청나게 늘어난다. 
한개의 모델이 여러 뷰를 조작하고, 한개의 뷰가 여러 개의 모델을 조작한다면 데이터 흐름을 알기 힘들어진다.</p>
<p>데이터의 변경 사항을 신속하게 전파하기가 어렵다. 모델이 늘어날수록 전파해야 할 대상도 함께 늘어나기 때문인데, 하나의 포스트가 삭제되면 포스트에 딸려 있던 각 댓글도 함께 삭제되야 되고, 이때 댓글을 잃어버린 각 유저의 댓글 사이드바나 사이트 헤더의 전체 덧글 카운터에도 변경사항이 전파되어야 한다.</p>
<p>MVC 패턴에서는 사이드바와 헤더의 데이터를 관리하는 모델들이 포스트 모델을 항상 주시하게 만들게 될 거고 코드는 함께 복잡해진다. </p>
<p>이것의 가장 큰 원인은 바로, &#39;양방향 데이터 흐름&#39; 이라는 것 때문이다.</p>
<p><img src="https://velog.velcdn.com/images/fe_jungseok/post/9d28b380-aedb-4857-ba8e-8ddf7cf5c929/image.png" alt=""></p>
<p>Model이 View를 반영하고, View가 Model을 변경하는 양방향 데이터 흐름에서 벗어나 단방향으로만 데이터를 변경할 수 있도록 한다.</p>
<p>Action이 발생하면, Dispatcher를 통해 store의 상태를 변경하고 이를 view에 반영한다.</p>
<p>이런 Flux패턴을 적용한게 우리가 잘 알고있는 Redux이다.</p>
<h3 id="store">Store</h3>
<p>상태값을 저장하는 전역저장소. 하나의 스토어만 가질 수 있다.</p>
<h3 id="action">Action</h3>
<p>상태에 변화가 필요하다면 액션을 일으켜야한다. 액션은 객체로 표현되며 type필드를 반드시 가지고 있어야 한다.
상태 변화를 일으킬 때 참조하는 객체</p>
<h3 id="dispatcher">Dispatcher</h3>
<p>디스패처는 액션 객체를 스토어 넘겨줘서 상태를 업데이트 하는 유일한 방법이다.
이벤트 트리거라고 생각할 수 있다.</p>
<h3 id="view">View</h3>
<p>우리가 알고있느 React에 해당되는 부분. 
Store에서 어떤 이벤트(변경 등)가 발생하면 View는 변경된 점을 가져오고, 이를 바탕으로 화면을 다시 랜더링한다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MVC]]></title>
            <link>https://velog.io/@fe_jungseok/MVC</link>
            <guid>https://velog.io/@fe_jungseok/MVC</guid>
            <pubDate>Tue, 06 Sep 2022 11:22:27 GMT</pubDate>
            <description><![CDATA[<p>MVC란 Model-View-Controller의 약자로 애플리케이션을 세 가지 역할로 구분한 디자인 패턴중 하나이다.
소프트웨어 디자인 패턴은 소프트웨어 공학의 소프트웨어 설계에서 특정 상황에 공통적으로 발생하는 문제에 대한 해결책이다.</p>
<p>사용자가 입력을 담당하는 View를 통해 요청을 보내면 해당 요청을 Controller가 받고, Controller는 Model을 통해 데이터를 가져오고, 해당 데이터를 바탕으로 출력을 담당하는 View를 제어해서 사용자에게 전달한다.</p>
<p>이러한 패턴을 성공적으로 사용하면, 사용자 인터페이스로부터 비즈니스 로직을 분리하여 애플리케이션의 시작적 요소나 그 이면에서 실행되는 비즈니스 로직을 서로 영향 없이 쉽게 고칠 수 있는 애플리케이션을 만들 수 있게 됩니다.</p>
<br/>

<h3 id="동작방식">동작방식</h3>
<ul>
<li>사용자가 웹사이트에 접속 </li>
<li>Controller는 사용자가 요청한 웹페이지를 서비스하기 위해서 모델을 호출 </li>
<li>Model은 데이터베이스나 파일과 같은 데이터 소스를 제어한 후 그 결과를 Return</li>
<li>Controller는 Model이 리턴한 결과를 View에 반영 </li>
<li>데이터가 반영된 View는 사용자에게 보여짐 </li>
</ul>
<br/>



<h3 id="model">MODEL</h3>
<p>데이터와 애플리케이션이 무엇을 할 것인지를 정의하는 부분으로 내부 비즈니스 로직을 처리하기 위한 역할</p>
<p>컨트롤러가 모델을 호출을 하면 DB와 연동하여 사용자의 입출력 데이터를 다루는 일과 같은 데이터와 연관된 비즈니스 로직을 처리하는 역할 수행</p>
<p>데이터 추출, 저장, 삭제, 업데이트 등의 역할을 수행</p>
<h4 id="1-사용자가-편집하길-원하는-모든-데이터를-가지고-있어야-한다">1. 사용자가 편집하길 원하는 모든 데이터를 가지고 있어야 한다.</h4>
<p>화면안의 네모박스에 글자가 표현된다면, 네모박스의 화면 위치 정보, 네모박스의 크기정보, 글자내용, 글자의 위치, 글자의 포맷 정보 등을 가지고 있어야 한다</p>
<h4 id="2-뷰나-컨트롤러에-대해서-어떤-정보도-알지-말아야-한다">2. 뷰나 컨트롤러에 대해서 어떤 정보도 알지 말아야 한다.</h4>
<p>데이터 변경이 일어났을 때 모델에서 화면 UI를 직접 조정해서 수정할 수 있도록, 뷰를 참조하는 내부 속성값을 가지면 안 된다. -&gt; 존재 자체를 몰라야 된다</p>
<h4 id="3-변경에-대한-수신-처리-방법-전달-처리-방법을-구현해야-된다">3. 변경에 대한 수신 처리 방법, 전달 처리 방법을 구현해야 된다.</h4>
<p>컨트롤러가 모델을 변경하도록 요청하는 이벤트를 보냈을 때 이를 수신할 수 있는 처리 방법, 모델의 정보가 변경이 된다면, 이벤트를 발생시켜 뷰에게 반영할 전달 처리 방법을 구현해야 한다</p>
<p>또한 모델은 재사용가능해야 하며 다른 인터페이스에서도 변하지 않아야 합니다. </p>
<h3 id="view">View</h3>
<p>input 텍스트, 체크박스 항목 등과 같은 사용자 인터페이스 요소를 나타낸다. 사용자와 상호작용을 하며 컨트롤러로부터 받은 모델의 결과값을 사용자에게 화면으로 출력하는 일을 합니다.</p>
<h4 id="1-모델이-가지고-있는-정보를-따로-저장해서는-안된다">1. 모델이 가지고 있는 정보를 따로 저장해서는 안된다.</h4>
<p>화면에 글자를 표시 하기 위해, 모델이 가지고 있는 정보를 전달받게 될텐데, 그 정보를 유지하기 위해서 임의의 뷰 내뷰에 저장하면 안된다. 단순히 네모 박스를 그리라는 명령을 받으면, 화면에 표시하기만 하고 그 화면을 그릴 때 필요한 정보들은 저장하지 않아야 한다.</p>
<h4 id="2-모델이나-컨트롤러에-대해서-어떤-정보도-알지-말아야-한다">2. 모델이나 컨트롤러에 대해서 어떤 정보도 알지 말아야 한다.</h4>
<p>자기 자신의 빼고는 다른 요소는 참조하거나 어떻게 동작하는지 알아서는 안된다. 그냥 뷰는 데이터를 받으면 화면에 표시해주는 역할만 가진다고 보면 된다. -&gt; 존재 자체를 몰라야 된다</p>
<h4 id="3-변경에-대한-수신-처리-방법-전달-처리-방법을-구현해야-된다-1">3. 변경에 대한 수신 처리 방법, 전달 처리 방법을 구현해야 된다.</h4>
<p>유저가 변경에대한 액션을 일으키면 이것을 컨트롤러에게 전달 할 전달처리 방법과 컨트롤러어에 의해 디스플레이변경 이벤트를 수신 할 수 있는 처리 방법,</p>
<h3 id="controller">Controller</h3>
<p>화면과 Model과 View를 연결시켜주는 역할 , Model이 데이터를 어떻게 처리할지 알려주는 역할</p>
<p>사용자로부터 View에 요청이 있으면 Controller는 해당 업무를 수행하는 Model을 호출하고 Model이 업무를 모두 수행하면 다시 결과를 View에 전달하는 역할을 합니다</p>
<h4 id="1-모델이나-뷰에-대해서-알고-있어야-한다">1. 모델이나 뷰에 대해서 알고 있어야 한다.</h4>
<p>모델이나 뷰는 서로의 존재를 모르고, 변경을 외부로 알리고, 수신하는 방법만 가지고 있는데 이를 컨트롤러가 중재하기 위해 모델과 그에 관련된 뷰에 대해서 알고 있어야 한다. </p>
<h4 id="2-모델이나-뷰의-변경을-모니터링-해야-한다">2. 모델이나 뷰의 변경을 모니터링 해야 한다.</h4>
<p>모델이나 뷰의 변경 통지를 받으면 이를 해석해서 각각의 구성 요소에게 통지를 해야 한다. 
또한, 애플리케이션의 메인 로직은 컨트롤러가 담당하게 된다. </p>
<h3 id="장점">장점</h3>
<ul>
<li>각 구성요소들을 독립시켜 협업을 할 때 맡은 부분의 개발에만 집중할 수 있어 개발의 효율성을 높여준다.</li>
<li>개발 후에도 유지보수성과 확장성이 보장된다.</li>
</ul>
<h3 id="단점">단점</h3>
<ul>
<li>한개의 모델이 여러 뷰를 조작하고, 한개의 뷰가 여러 개의 모델을 조작한다면 데이터 흐름을 알기 힘들어진다.</li>
<li>프로젝트가 커질수록 버그를 찾기 어려워지고, 흐름을 추적하는데 많은 시간 소요</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[JS 함수정의 방법]]></title>
            <link>https://velog.io/@fe_jungseok/JS-%ED%95%A8%EC%88%98%EC%A0%95%EC%9D%98-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@fe_jungseok/JS-%ED%95%A8%EC%88%98%EC%A0%95%EC%9D%98-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Wed, 31 Aug 2022 16:56:29 GMT</pubDate>
            <description><![CDATA[<h3 id="함수-선언식명명-함수-선언">함수 선언식(명명 함수 선언)</h3>
<pre><code class="language-java">function func(name) {
    console.log(name);
}

func(&#39;seok&#39;);</code></pre>
<br/>

<h3 id="함수-표현식함수-리터럴">함수 표현식(함수 리터럴)</h3>
<pre><code class="language-java">var func = function(name) {
    console.log(name);
};

func(&#39;seok&#39;);</code></pre>
<h4 id="함수-표현식은-또-익명함수-표현과-명명함수-표현으로-나뉜다">함수 표현식은 또 익명함수 표현과 명명함수 표현으로 나뉜다</h4>
<pre><code class="language-java">
var func = function () {
  //...
}

var func = function originalName() {
  // ...
}</code></pre>
<br/>

<h3 id="화살표-함수">화살표 함수</h3>
<pre><code class="language-java">var func = () =&gt; {
    console.log(name);
};

func(&#39;seok&#39;);</code></pre>
<br/>

<h3 id="function-객체">Function 객체</h3>
<pre><code class="language-java">//객체 방식
var func = new Function(&#39;name&#39;, &#39;console.log(name)&#39;);

func(&#39;seok&#39;);

const adder = new Function(&#39;a&#39;, &#39;b&#39;, &#39;return a + b&#39;)
adder(2, 6)</code></pre>
<br/>

<h3 id="즉시실행-함수">즉시실행 함수</h3>
<p>함수 정의와 동시에 즉시 호출되는 함수를 즉시 실행 함수 (IIFE, Immediately Invoked Function Expression) 라고 한다.  즉시 실행 함수는 단 한 번만 호출되며 다시 호출할 수 없다.</p>
<pre><code class="language-java">(function(name) {
    console.log(name);
})(&#39;seok&#39;);</code></pre>
<h4 id="즉시실행-함수-특징">즉시실행 함수 특징</h4>
<ol>
<li>즉시 실행 함수는 함수 이름이 없는 익명 함수를 사용하는 것이 일반적이다. 
함수 이름이 있는 기명 즉시 실행 함수도 사용할 수 있다.  하지만 즉시 실행 함수를 다시 호출할 수는 없다.</li>
</ol>
<pre><code class="language-java">//익명 즉시 실행함수
(function () {
  var a = 3;
  var b = 5;
  return a * b;
})();

//기명 즉시 실행 함수
(function foo() {
  var a = 3;
  var b = 5;
  return a * b;
})();
foo(); //ReferenceError: foo is not defined</code></pre>
<ol start="2">
<li>즉시 실행 함수는 반드시 그룹 연산자 (...)로 감싸야 한다.</li>
</ol>
<pre><code class="language-java">
function () {
 //SyntaxError: Function statements require a function name</code></pre>
<ol start="3">
<li>일반적으로 즉시 실행 함수는 정의와 동시에 한번밖에 호출할 수 밖에 없지만, 함수표현식으로 정의하면 여러번 반복해서 호출 할 수 있다.</li>
</ol>
<pre><code class="language-java">var myCounter = (function (initialValue = 0) {
  let count = initialValue
  return function () {
    count++
    return count
  }
})(1)

myCounter() // 2
myCounter() // 3
myCounter() // 4</code></pre>
<ol start="4">
<li>즉시 실행 함수로, 클로져를 활용할 수 있다. 내부 함수는 변수나 다른 함수등을 쓸 수 있지만,이 함수 밖에서는 완전히 캡슐화되어 접근 할 수 없다. </li>
</ol>
<pre><code class="language-java">var myCounter = (function (initialValue = 0) {
  let count = initialValue
  return function () {
    count++
    return count
  }
})(1)

myCounter() // 2
myCounter() // 3
myCounter() // 4</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[JS 객체생성 방법]]></title>
            <link>https://velog.io/@fe_jungseok/JS-%EA%B0%9D%EC%B2%B4-%EC%83%9D%EC%84%B1-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@fe_jungseok/JS-%EA%B0%9D%EC%B2%B4-%EC%83%9D%EC%84%B1-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Wed, 31 Aug 2022 16:39:48 GMT</pubDate>
            <description><![CDATA[<p>자바스크립트에서 원시 타입을 제외한 모든 데이터 타입(객체, 함수, 배열, 정규표현식 등)은 객체다.</p>
<p>객체가 보유한 값을 &#39;프로퍼티&#39;라고 하며, 객체가 보유한 함수를 &#39;메서드&#39;라고 한다.
프로퍼티는 키와 값으로 구성된다.</p>
<h3 id="new-object-객체-생성자">new Object() 객체 생성자</h3>
<pre><code class="language-java">//Object()를 이용해서 foo 빈 객체 생성
var pserson = new Object();

// foo 객체 프로퍼티 생성 
pserson.name = &#39;seok&#39;;
pserson.age = 10;
pserson.gender = &#39;male&#39;;

console.log(typepf foo); // (출력값) object
console.log(foo); // (출력값) { name: &#39;seok&#39;, age: 10, gender: male}


// String객체 생성하기
var strObj = new String(&#39;hello&#39;);
console.log(strObj); //[String: &#39;hello&#39;]


// Array(배열)객체 생성하기
var arrObj = new Array([1, 2, 3]);
console.log(arrObj); //[ [ 1, 2, 3 ] ]
출처: https://curryyou.tistory.com/189 [카레유:티스토리]</code></pre>
<h4 id="objectcreate">Object.create()</h4>
<p> Object.create(프로토타입)  : 프로토타입 상속을 통해 객체를 만드는 방식</p>
<pre><code class="language-java">// 부모 객체 생성
var parent = {a:10, b:20};

// 자식 객체 생성(부모의 프로퍼티를 상속 받음)
var child = Object.create(parent);
console.log(child.a);  // 10</code></pre>
<h3 id="객체-리터럴">객체 리터럴</h3>
<pre><code class="language-java">var person = {
    name : &#39;seok&#39;,
    age : 10,
    gender: &#39;male&#39;,
    func1: function () {
        console.log(&#39;Hello js&#39;)
    }
}</code></pre>
<h3 id="생성자-함수">생성자 함수</h3>
<pre><code class="language-java"> // Person() 생성자 함수
var Person = function(name) {
        this.name = name;
}

// foo 객체 생성
 var foo = new Person(&#39;seok&#39;);
console.log(foo.name) // seok</code></pre>
<h3 id="클래스">클래스</h3>
<pre><code class="language-java">class Person {
  constructor(name, age) { // 인자를 받아 할당한다.
    this.name = name; 
    this.age = age;
  }

  func1() {
    console.log(`${this.name}: hello!`);
  }

  get personName() { 
  return this.name;
}
  set probName(value) { 
    this.name = value; 
  }
}

const mike = new Person(&#39;seok&#39;, 10);
console.log(mike.name);
console.log(mike.age);</code></pre>
<h3 id="객체-프로퍼티메서드-접근방법">객체 프로퍼티,메서드 접근방법</h3>
<pre><code class="language-java">객체.프로퍼티 , 객체[&#39;프로퍼티&#39;]로 접근가능하다

var person = {
    name : &#39;seok&#39;,
    age : 10,
    gender: &#39;male&#39;,
    func1: function () {
        console.log(&#39;Hello js&#39;)
    }
}

person.name;    
person.age;    
person.func1();
person[&#39;name&#39;];    
person[&#39;age&#39;];    
person[&#39;func1&#39;]();</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[webpack dev server]]></title>
            <link>https://velog.io/@fe_jungseok/webpack-dev-server</link>
            <guid>https://velog.io/@fe_jungseok/webpack-dev-server</guid>
            <pubDate>Fri, 26 Aug 2022 16:29:37 GMT</pubDate>
            <description><![CDATA[<p>webpack dev server는 웹 애플리케이션을 개발하는 과정에서 실시간으로 리로드가 되는 웹팩의 개발 서버이다.<br>매번 웹팩 명령어를 사용할 필요없이 코드의 변경사항을 감지해 브라우저에 반영해준다.</p>
<h3 id="동작원리">동작원리</h3>
<ol>
<li>webpack-dev-server의 동작원리</li>
<li>서버 실행 시 소스 파일들을 번들링하여 메모리에 저장소스 파일을 감시</li>
<li>소스 파일이 변경되면 변경된 모듈만 새로 번들링</li>
<li>변경된 모듈 정보를 브라우저에 전송</li>
<li>브라우저는 변경을 인지하고 새로고침되어 변경사항이 반영된 페이지를 로드</li>
</ol>
<h3 id="설치">설치</h3>
<pre><code class="language-java">npm i -D webpack-dev-server</code></pre>
<h3 id="설정">설정</h3>
<p>여기서 key값인 dev는 다른것으로 교체해도 상관없다.</p>
<pre><code class="language-java">// package.json
&quot;scripts&quot;: {
  &quot;dev&quot;: &quot;webpack-dev-server&quot;,
  &quot;build&quot;: &quot;webpack&quot;
}</code></pre>
<pre><code class="language-java">// webpack-config.js
// 포트,proxy서버 등등 설정가능

module.exports={
devServer:{
  port:9000,
  proxy: {
      &#39;/api&#39;: &#39;http://localhost:3000&#39;
  }
 }
}</code></pre>
<h3 id="devserver-속성">devServer 속성</h3>
<table>
<thead>
<tr>
<th align="center">속성명</th>
<th align="center">description</th>
<th align="center">CLI</th>
</tr>
</thead>
<tbody><tr>
<td align="center">host</td>
<td align="center">사용될 호스트 지정</td>
<td align="center">webpack-dev-server –host 127.0.0.1</td>
</tr>
<tr>
<td align="center">contentBase</td>
<td align="center">콘텐츠를 제공할 경로지정 (정적파일을 제공하려는 경우에만 필요)</td>
<td align="center">webpack-dev-server –content-base /path/to/content/dir</td>
</tr>
<tr>
<td align="center">compress</td>
<td align="center">모든 항목에 대해 gzip압축 사용</td>
<td align="center">webpack-dev-server –compress</td>
</tr>
<tr>
<td align="center">hot</td>
<td align="center">webpack의 HMR 기능 활성화</td>
<td align="center"></td>
</tr>
<tr>
<td align="center">inline</td>
<td align="center">inline 모드 활성화</td>
<td align="center">webpack-dev-server –inline=true</td>
</tr>
<tr>
<td align="center">port</td>
<td align="center">접속 포트 설정</td>
<td align="center">webpack-dev-server –port 9000</td>
</tr>
<tr>
<td align="center">open</td>
<td align="center">dev server 구동 후 브라우저 열기</td>
<td align="center">webpack-dev-server –open</td>
</tr>
</tbody></table>
<br/>
<br/>



<h3 id="참고">참고</h3>
<ul>
<li><a href="https://webpack.js.org/configuration/dev-server/">https://webpack.js.org/configuration/dev-server/</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[next.js data fetching]]></title>
            <link>https://velog.io/@fe_jungseok/nextjs-data-fetching</link>
            <guid>https://velog.io/@fe_jungseok/nextjs-data-fetching</guid>
            <pubDate>Fri, 26 Aug 2022 09:52:36 GMT</pubDate>
            <description><![CDATA[<p>Next.js에서 동적인 Data를 Fetching하는 방식은 아래의 4가지 방식이 있다.</p>
<ul>
<li><p>CSR(Client Side Rendering)</p>
</li>
<li><p>SSR(Server Side Rendering)</p>
</li>
<li><p>SSG(Static Site Generation)</p>
</li>
<li><p>ISR(Incremental Static Regeneration)</p>
</li>
</ul>
<h3 id="csr">CSR</h3>
<pre><code class="language-java">import { useEffect, useState } from &#39;react&#39;
import styles from &#39;../styles/Home.module.css&#39;
import axios from &#39;axios&#39;;

export default function Home() {
  const [dateTime, setDateTime] = useState(null);

  useEffect(async () =&gt; {
    try {
      const response = await axios.get(&#39;https://worldtimeapi.org/api/ip&#39;);
      setDateTime(response.data.datetime);
    }
    catch (e) {
      console.error(e);
    }
  },[]);

  return (
    &lt;div className={styles.container}&gt;
      {dateTime || &quot;불러오는 중 ...&quot;}
    &lt;/div&gt;
  )
}</code></pre>
<h3 id="ssr---getserversideprops">SSR - getServerSideProps</h3>
<p>SSR에서는 브라우저에서 데이터를 받아오는 것이 아니라 서버에서 데이터를 미리 받아서 그 값을 이용해 구성한 html 파일을 브라우저에게 전달해주기 때문이다.</p>
<p>브라우저는 데이터를 받아올 필요없이 그저 서버에서 보내준 html파일을 렌더링하면 된다. 서버에서 데이터를 받아오는 과정은 페이지가 로드되기 전 진행된다.</p>
<p>getServerSideProps는 서버에서 실행되는 함수이다. 그렇기 때문에 저 함수안에 console.log(&quot;hello&quot;)를 넣어주면 브라우저가 아닌 서버의 콘솔창에 &quot;hello&quot;가 뜨는 것을 확인할 수 있다.</p>
<pre><code class="language-java">import styles from &#39;../styles/Home.module.css&#39;
import axios from &#39;axios&#39;;

export default function Home(props) {

  const { dateTime } = props;

  return (
    &lt;div className={styles.container}&gt;
      {dateTime || &quot;불러오는 중 ...&quot;}
    &lt;/div&gt;
  )
}

export async function getServerSideProps() {
  const response = await axios.get(&quot;https://worldtimeapi.org/api/ip&quot;);

  return {
    props: {
      dateTime: response.data.datetime
    }
  }
}</code></pre>
<h3 id="ssg---getstaticpropsgetstaticpaths">SSG - getStaticProps,getStaticPaths</h3>
<p>빌스시 고정되는 값, 빌드 이후 값 변경 불가</p>
<p>getServerSideProps()는 매 페이지 요청마다 서버에서 실행되지만 getStaticProps()는 빌드할 때 한번만 실행되는 함수이다. </p>
<p>그러므로 화면에 표시된 시간을 빌드가 될 때 api 호출을 해서 받아온 데이터(시간)이다.</p>
<pre><code class="language-java">function Blog({ posts }) {
  return (
    &lt;ul&gt;
      {posts.map(post =&gt; (
        &lt;li&gt;{post.title}&lt;/li&gt;
      ))}
    &lt;/ul&gt;
  );
}



// // 빌드 타임 때, 정적으로 렌더링할 경로 설정
export async function getStaticPaths() {
  return {
    paths: [
      { params: { id: &quot;1&quot; } },
      { params: { id: &quot;2&quot; } }
      ......
      { params: { id: &quot;10&quot; } }
    ],
    // 만들어지지 않은 것도 추후 요청이 들어오면 만들어 줄 지 여부.
    fallback: true,
  }
}


export async function getStaticProps() {
  const res = await fetch(&quot;https://.../posts&quot;);
  const posts = await res.json();

  // By returning { props: posts }, the Blog component
  // will receive `posts` as a prop at build time
  return {
    props: {
      posts
    }
  };
}</code></pre>
<ul>
<li>해당 path로 설정해준 params 1~10까지만 처음에 정적파일을 생성해줌</li>
<li>fallback false이면 다른 params 수는 404 에러를 띄운다.</li>
<li>fallback true이면 다른 params 수는 처음에 처음에 빈화면을 잠시 렌더링하다가 백엔드에서 정적파일을 생성해준다.</li>
<li>그러면 next.js는 그 정적파일을 pre-rendering 목록에 추가해준다(production 환경에서만 development환경은 x)</li>
<li>getStaticPaths 사용시 getStaticProps도 같이 써줘야됨</li>
</ul>
<h3 id="isr---getstaticprops">ISR - getStaticProps</h3>
<p>getStaticProps()로 빌드시 데이터를 받아오되 일정 시간이 지난 후의 페이지 요청에 대해서는 함수가 다시 실행된다. </p>
<p>npm run build를 하고 npm run dev를 하면  페이지에 접속을 한 후 리로드를 계속 해보면 시간이 바뀌지 않지만 어느 시점에 갑자기 바뀐다. </p>
<p>빌드가 된 후 5초 뒤의 요청에 대해서는 빌드를 새로해 getStaticProps()를 다시 실행하도록 revalidate라는 것을 이용해 설정해줬기 때문이다.</p>
<p>매 5초마다 함수가 실행되는 것이 아니라 5초 뒤의 요청이 들어온 시점에 함수가 실행되는 것이다. 
그렇기 때문에 6초뒤에 페이지를 리로드하면 5초 뒤의 시간이 아닌 정확히 6초 뒤의 시간이 표시된다. </p>
<pre><code class="language-java">import styles from &#39;../styles/Home.module.css&#39;
import axios from &#39;axios&#39;;

export default function Home(props) {

  const { dateTime } = props;

  return (
    &lt;div className={styles.container}&gt;
      {dateTime || &quot;불러오는 중 ...&quot;}
    &lt;/div&gt;
  )
}

export async function getStaticProps() {
  const response = await axios.get(&quot;https://worldtimeapi.org/api/ip&quot;);

  return {
    props: {
      dateTime: response.data.datetime
    },
    revalidate: 5
  }
}</code></pre>
<h3 id="context-objects">context objects</h3>
<ul>
<li>pathname - 현재 pathname (/user?type=normal-&gt; /user)</li>
<li>query - 현재 query를 객체로 (<a href="http://localhost:3000/blog/test">http://localhost:3000/blog/test</a> -&gt; {id: &#39;test&#39;}, /post?type=secret -&gt; {type: &#39;secret&#39;})</li>
<li>asPath - 전체 path (<a href="http://localhost:3000/blog/test">http://localhost:3000/blog/test</a> -&gt; /blog/[id], /blog/test)</li>
<li>req - HTTP request object (server only)</li>
<li>res - HTTP response object (server only)</li>
<li>err - Error object if any error is encountered during the rendering</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[next.js]]></title>
            <link>https://velog.io/@fe_jungseok/Nexj.js-%EA%B8%B0%EB%8A%A5</link>
            <guid>https://velog.io/@fe_jungseok/Nexj.js-%EA%B8%B0%EB%8A%A5</guid>
            <pubDate>Fri, 26 Aug 2022 08:22:42 GMT</pubDate>
            <description><![CDATA[<p>React에서 서버 사이드 렌더링을 지원해주는 프레임워크이다.</p>
<h3 id="csr-문제점">CSR 문제점</h3>
<ul>
<li><p>ttv 문제: 클라이언트 렌더링의 경우 모든 js 파일을 로드하고 사용자는 웹을 보게된다. 이때까지 사용자는 많은 시간을 대기해야 한다다.</p>
</li>
<li><p>seo 문제: 클라이언트 사이드의 경우 첫 랜더링시 빈html파일을 받아오므로 검색엔진이 데이터가 없는줄알고 나가버린다.</p>
</li>
</ul>
<h3 id="ssr-문제점">SSR 문제점</h3>
<ul>
<li><p>서버부하: 페이지 이동시마다 서버에 데이터를 요청하므로 이는 곧 서버부하로 이어진다</p>
</li>
<li><p>ttI 문제: 서버에서 랜더링해서 브라우저로 보여지므로 TTV가 빠른반면 ,브라우저에서 js를 로드하는 시간이 있으므로 TTI가 느림</p>
</li>
<li><p>사용자 경험: 페이지 이동마다 서버에 페이지를 받아오므로 새로고침이 발생하므로 인터렉션이 느리다</p>
</li>
</ul>
<h3 id="nextjs-작동-원리-ssr--csr">Next.js 작동 원리: SSR + CSR</h3>
<p>csr,ssr 각각의 단점의 해결책으로 나온게 next.js이다</p>
<ul>
<li><p>서버에 페이지 접속을 요청하면 SSR 방식으로 HTML을 렌더링 해 온다(SSR).</p>
</li>
<li><p>그리고 브라우저에서 js를 다운로드하고 리액트를 실행한다. (→ 그래서 초기 로딩 성능도 개선하고, 이미 콘텐츠가 다 포함된 상태라 SEO도 가능함)</p>
</li>
<li><p>그리고 나서 사용자가 상호작용하면서 다른 페이지로 이동할 때는, SSR이 아닌 CSR 방식으로 브라우저에서 처리하는 것이다. (→ 그래서 CSR의 장점도 유지함)</p>
</li>
</ul>
<h3 id="설치실행">설치,실행</h3>
<pre><code class="language-java">// 설치
npx create-next-app</code></pre>
<pre><code class="language-java">// 실행 
npm run dev</code></pre>
<p><img src="https://velog.velcdn.com/images/fe_jungseok/post/fae895ca-d892-452d-b287-4ce96be906db/image.png" alt=""></p>
<h3 id="hot-reloading">hot reloading</h3>
<p>개발 중 저장되는 코드는 자동으로 새로고침된다.</p>
<h3 id="file-based-routing">File Based Routing</h3>
<p>React에서는 라우터가 없어서 보통 react-router-dom을 사용해서 렌더링한다
하지만 Nest.js의 경우 별 다른 설정없이 Routing을 할 수 있다.
폴더 내부의 파일위치나 파일명에 따라서 routing을 할 수 있다.
<img src="https://velog.velcdn.com/images/fe_jungseok/post/cc449c14-8e96-4ca0-b45e-8ba6a7b92965/image.png" alt=""></p>
<h3 id="global-style">global style</h3>
<p>다른 컴포넌트에 정의한 경우 다른 클래스와 겹쳐 오류를 발생할 수 있음으로 _app에서만 허용된다.</p>
<pre><code class="language-java">// _app.tsx
import &quot;./globals.css&quot;;

function MyApp({ Component, pageProps }) {
  return &lt;Component ponent {...pageProps} /&gt;;
}

export default MyApp;</code></pre>
<h3 id="automaticdynamic-routing">automatic,dynamic routing</h3>
<p>pages 폴더에 있는 파일은 해당 파일 이름으로 라우팅된다. (pages/page1.tsx -&gt; localhost:3000/page1)</p>
<p>public 폴더도 pages의 폴더와 동일하게 라우팅 할수있다. 그러나 모든 사람이 페이지에 접근할 수 있으므로 지양하는게 좋다.</p>
<pre><code class="language-java">import Link from &quot;next/link&quot;; //client side navigation
import { useRouter } from &quot;next/router&quot;;
import styles from &#39;../styles/Navbar.module.css&#39; //css module

function Navba() {
  const router = useRouter(); //현재 위치한 location에 대한정보가 있음
  console.log(router)

  return &lt;nav&gt;
    &lt;Link href=&quot;/&quot;&gt;&lt;a className={router.pathname===&quot;/&quot; ? styles.active:&quot;&quot;}&gt;home&lt;/a&gt;&lt;/Link&gt;
    &lt;Link href=&quot;about&quot;&gt;&lt;a className={router.pathname===&quot;/about&quot; ? styles.active:&quot;&quot;}&gt;about&lt;/a&gt;&lt;/Link&gt;
  &lt;/nav&gt;;
}

export default Navba;</code></pre>
<pre><code class="language-java">import { useEffect } from &quot;react&quot;;
import { useRouter } from &quot;next/router&quot;;
import posts from &quot;../posts.json&quot;;

export default () =&gt; {
  const router = useRouter();

  const post = posts[router.query.id as string];
  if (!post) return &lt;p&gt;noting&lt;/p&gt;;

  useEffect(() =&gt; {
    router.prefetch(&quot;/test&quot;);
  }, []);

  return (
    &lt;&gt;
      &lt;h1&gt;{post.title}&lt;/h1&gt;
      &lt;h1&gt;{post.content}&lt;/h1&gt;
      &lt;button onClick={() =&gt; router.push(&quot;test&quot;)}&gt;go to Test&lt;/button&gt;
    &lt;/&gt;
  );
};</code></pre>
<pre><code>// 동적url
import { useRouter } from &quot;next/router&quot;;

export default () =&gt; {
  const router = useRouter();

  return (
    &lt;&gt;
      &lt;h1&gt;post&lt;/h1&gt;
      &lt;p&gt;postid: {router.query.id}&lt;/p&gt;
    &lt;/&gt;
  );
};</code></pre><pre><code>import Router from &#39;next/router&#39;;
const greeting = &#39;hello&#39; 

// 해당 파일 경로와 보내고 싶은 props를 query형태로 보내준다.
const SendQuery = () =&gt; {
    Router.push({
      pathname: &#39;/register&#39;,
      query: { greetingK: &#39;안녕&#39;, greetingE: greeting },
    });
  };


&lt;button onClick={SendQuery}&gt;클릭&lt;/button&gt;


import { useRouter } from &#39;next/router&#39;;

// router를 이용해 data를 query를 통해 받아온다
const router = useRouter();
console.log(&#39;K : &#39;, router.query.greetingK);
console.log(&#39;E : &#39;, router.query.greetingE);</code></pre><h3 id="server-rendering">server rendering</h3>
<p>클라이언트 렌더링과 다르게 서버에서 html을 rendering한다.</p>
<h3 id="typescript">typescript</h3>
<p>타입스크립트 활용을 위해 웹팩을 만지거나 바벨을 만질 필요 없다. 타입스크립트를 설치하고 
(npm i typescript @types/node @types/react), (npm run dev)만 하면 자동으로 tsconfig, next-end.d.ts가 생성되어 타입스크립트로 코딩이 가능해진다.</p>
<h3 id="link">Link</h3>
<p>보통 페이지간 이동은 a 태그를 사용하나 next에서는 사용하지 않는다.</p>
<p>a 태그를 사용하면 처음 페이지에 진입시 번들 파일을 받고, a 태그에 의해 라우팅 되면 다시 번들 파일을 받기 때문이다. 또한 redux을 쓰시는 경우 라면 store의 state 값이 증발되는 현상도 일어난다. 그렇기 때문에 a 태그는 전혀 다른 사이트로 페이지를 이동시켜 다시 돌아오지 않는 경우만 사용하고, 그 이외에는 모두 Link 태그를 사용한다다.</p>
<pre><code class="language-java">import Link from &quot;next/link&quot;;

const Index = () =&gt; (
  &lt;div&gt;
    &lt;Link href=&quot;/blog&quot;&gt;
      &lt;a&gt;Blog&lt;/a&gt;
    &lt;/Link&gt;
    // 동적 link시 [] 사용
    &lt;Link href=&quot;/blog/[address]&quot;&gt;
      &lt;a&gt;Blog&lt;/a&gt;
    &lt;/Link&gt;
  &lt;/div&gt;
);</code></pre>
<h3 id="dynamic-component-import">dynamic component import</h3>
<p>dynamic component import는 react에서 lazy하게 component를 import 해오는 방식과 유사하다.</p>
<p>dynamic하게 처음 보여줘도 안되는 컴포넌트는 import 하지 않게 됨으로, 초기 화면 렌더링 속도를 상승시키기 위해 사용한다.(맨처음 보이는 컴포넌트라면 dynamic 메소드를 사용할 이유가 없음)</p>
<pre><code class="language-java"> import React, { useState } from &quot;react&quot;;
import dynamic from &quot;next/dynamic&quot;;

const DynamicComponent = dynamic&lt;{ nowTab: number }&gt;(() =&gt;
  import(&quot;./DynamicComponent&quot;)
);

const Index = () =&gt; {
  const [nowTab, setNowTab] = useState(0);

  return (
    &lt;&gt;
      {nowTab === 0 &amp;&amp; &lt;div&gt;0 tab&lt;/div&gt;}
      {nowTab === 1 &amp;&amp; &lt;DynamicComponent nowTab={nowTab} /&gt;}
    &lt;/&gt;
  );
};</code></pre>
<h3 id="single-file-components-css-module">single file components (css module)</h3>
<pre><code class="language-java">port Link from &quot;next/link&quot;; //client side navigation
import { useRouter } from &quot;next/router&quot;;
import styles from &#39;../styles/Navbar.module.css&#39; //css module

function Navba() {
  const router = useRouter(); //현재 위치한 location에 대한정보가 있음
  console.log(router)

  return &lt;nav&gt;
    &lt;Link href=&quot;/&quot;&gt;&lt;a className={`${styles.link} ${router.pathname===&quot;/&quot; ? styles.active:&quot;&quot;}`}&gt;home&lt;/a&gt;&lt;/Link&gt;
    &lt;Link href=&quot;about&quot;&gt;&lt;a className={ `${styles.link}  ${router.pathname===&quot;/about&quot; ? styles.active:&quot;&quot;}`}&gt;about&lt;/a&gt;&lt;/Link&gt;
  &lt;/nav&gt;;
}

export default Navba;

// css module -&gt; 브라우저에서 코드를열면  &lt;nav className={styles.nav}&gt; 
// 이부분 className은 무작위로 선정됨 따라서 다른 컴포넌트에서 똑같은 클래스명을 지어도 충돌할 걱정이없음
// 클래스를 여러개쓸거면 ``사용
// 1개는 : className={router.pathname===&quot;/&quot; ? styles.active:&quot;&quot;}

.active{
    color: tomato;
}
.link{
    text-decoration: none;
}</code></pre>
<h3 id="prefetching">prefetching</h3>
<p>백그라운드에서 페이지를 미리 가져온다. 기본값은 true. <Link />뷰포트에있는 모든 항목 (초기 또는 스크롤을 통해)이 미리 로드된다. 정적 생성 을 사용하는 JSON페이지는 더 빠른 페이지 전환을 위해 데이터가 포함 된 파일을 미리로드 한다.</p>
<p>이건 Link 컴포넌트를 사용해서 이뤄지는데, 링크 컴포넌트를 렌더링할때 <Link prefetch href="..."> 형식으로 prefetch 값을 전달해주면 데이터를 먼저 불러온다음에 라우팅을 시작한다. 프로덕션 레벨에서만 이루어진다.</p>
<h3 id="custom-태그로-head-태그-옮기기">custom 태그로 head 태그 옮기기</h3>
<p>우리는 페이지의 header로 다음과 같은 정보를 추가할 수 있습니다.</p>
<ul>
<li>페이지 제목을 커스텀하고 싶을때</li>
<li>meta 태그를 변경하고 싶을때</li>
</ul>
<pre><code class="language-java">import Head from &quot;next/head&quot;;

export default () =&gt; (
  &lt;div&gt;
    &lt;Head&gt;
      &lt;title&gt;새로 만들어진 타이틀 입니다&lt;/title&gt;
    &lt;/Head&gt;
    &lt;div&gt;...&lt;/div&gt;
  &lt;/div&gt;
);</code></pre>
<p>next/head로 부터 Head 컴포넌트를 받아 모든 컴포넌트에서 사용할 수 있다.
next.js가 해당 컴포넌트가 mount 할때, Head내 태그들을 페이지의 HTML의 Head에 포함 시킨다. 마찬가지로 unMount 할때, 해당 태그를 제거한다.</p>
<h3 id="_appjs">_app.js</h3>
<pre><code class="language-java">function MyApp({ Component, pageProps }) {
  return &lt;Component {...pageProps} /&gt;;
}

export default MyApp;</code></pre>
<ul>
<li>이곳에서 렌더링 하는 값은 무조건 모든 페이지에 영향을 준다.</li>
<li>최초로 실행되는 것은 _app.js</li>
<li>내부에 컴포넌트가 있다면 전부 실행하고 html의 body로 구성됨</li>
<li>여기서 props로 받은 Component는 요청한 페이지이다. Component 에는 /pages/index.js 파일이 props로 내려오게 된다.</li>
<li>pageProps는 페이지 getInitialProps를 통해 내려 받은 props들을 말한다(미리가져온 초기객체)</li>
<li>그 다음 _document.js가 실행됨</li>
<li>_app.js에서 consle.log 실행시 client, server둘다 콘솔 찍힘</li>
<li>global css를 여기서 선언한다.</li>
<li>componentDIdCatch 이용해 커스텀 에러 핸들링이 가능하다.</li>
<li>페이지 전환시 상태값을 유지할 수 있다.</li>
</ul>
<h3 id="_documentjs">_document.js</h3>
<p>meta 태그를 정의하거나, 전체 페이지에 관려하는 컴포넌트이다.</p>
<pre><code class="language-java">// pages/_document.tsx
import Document, { Html, Head, Main, NextScript } from &quot;next/document&quot;;
export default class CustomDocument extends Document {
  render() {
    return (
      &lt;Html&gt;
        &lt;Head&gt;
          // 모든페이지에 아래 메타테크가 head에 들어감, 루트파일이기에 가능한 적은 코드만 넣어야함 
          &lt;meta property=&quot;custom&quot; content=&quot;123123&quot; /&gt;
        &lt;/Head&gt;
        &lt;body&gt;
          &lt;Main /&gt;
        &lt;/body&gt;
        &lt;NextScript /&gt;
      &lt;/Html&gt;
    );
  }
}</code></pre>
<ul>
<li>이곳에서 console은 서버에서만 보이고 클라이언트에서는 안보인다.</li>
<li>render 요소는 방영하지만 페이지 구성요소만 반영되고 js는 반영안한다 즉, componentDidMount 같은 훅도 실행이 안된다다. 정말 static한 상황만 부여된다.</li>
<li>Next.js 페이지들은 마크업 정의를 건너띄기 떄문에 html,head,body태그를 사용할때는 이페이지를 필수적으로 만들어야 된다.</li>
</ul>
<h3 id="_errorjsx">_error.jsx</h3>
<p>라우팅 경로를 설정하지 않더라도  에러가 발생한다면 에러 페이지로 넘어가게 된다.
추가적으로 에러 상황에 따라서 500, 404 등도 추가할 수 있다</p>
<pre><code class="language-java">  /pages/404.js

import Header from &#39;header.js&#39;;
import Footer from &#39;footer.js&#39;;

export default function Custom404() {
  return (
    &lt;&gt;
      &lt;Header /&gt;
      &lt;h1&gt;Custom 404 Error Page&lt;/h1&gt;
      &lt;Footer /&gt;
    &lt;/&gt;
  )
}</code></pre>
<h3 id="server-side-생명주기">server side 생명주기</h3>
<ol>
<li>nextJs 서버가 GET 요청을 받는다.</li>
<li>GET 요청에 맞는 pages/Component를 찾는다.</li>
<li>_app.tsx의 getInitialProps가 있다면 실행한다.</li>
<li>route에 맞는 페이지의 Component의 getInitialProps가 있다면 실행한다. pageProps들을 받아온다.</li>
<li>_document.tsx의 getInitialProps가 있다면 실행한다. pageProps들을 받아온다.</li>
<li>모든 props들을 구성하고, _app.tsx -&gt; page Component 순서로 렌더링</li>
<li>모든 Content를 구성하고 _document.tsx를 실행하여 html 형태로 출력한다.</li>
</ol>
<h3 id="context-objects">context objects</h3>
<ul>
<li>pathname - 현재 pathname (/user?type=normal-&gt; /user)</li>
<li>query - 현재 query를 객체로 (<a href="http://localhost:3000/blog/test">http://localhost:3000/blog/test</a> -&gt; {id: &#39;test&#39;}, /post?type=secret -&gt; {type: &#39;secret&#39;})</li>
<li>asPath - 전체 path (<a href="http://localhost:3000/blog/test">http://localhost:3000/blog/test</a> -&gt; /blog/[id], /blog/test)</li>
<li>req - HTTP request object (server only)</li>
<li>res - HTTP response object (server only)</li>
<li>err - Error object if any error is encountered during the rendering</li>
</ul>
<br/>
<br/>


<h3 id="참고">참고</h3>
<ul>
<li><a href="https://nextjs.org/docs">https://nextjs.org/docs</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[immer]]></title>
            <link>https://velog.io/@fe_jungseok/immer</link>
            <guid>https://velog.io/@fe_jungseok/immer</guid>
            <pubDate>Thu, 25 Aug 2022 08:59:43 GMT</pubDate>
            <description><![CDATA[<p>immer는 currentState의 프록시객체인 임시 draftState를 생성하여 수정, nextState를 생성하게 된다. </p>
<p>불변성을 유지하기위해 기존 reducer에서는 전개연산자 ,concat, filter, map같은 함수를 이용했지만, 가독성이 떨어지면 직관적이지 않다는 단점이 있다 </p>
<p>immer를 활용하면 이부분을 해소할수 있다.</p>
<pre><code class="language-java">// 설치
npm i immer</code></pre>
<pre><code class="language-java">produce(prevState, producer: (draftState) =&gt; void): nextState
* prevState : 현재 state
* draftState : 현재 state의 프록시객체(복사판같은)
* nextState : producer 함수가 반환하는 값</code></pre>
<pre><code class="language-java">const { produce } = require(&#39;immer&#39;); //리듀서를 좀더 직관적인 형태로 정리하기위해 immer사용

const initialState = {
  isLoggingIn: false,
  data: null,
};

// nextState = produce(prevState, (draft) =&gt; {})

const userReducer = (prevState = initialState, action) =&gt; { // action을 바탕으로 새로운 state 만들어주기
  return produce(prevState, (draft) =&gt; {  // produce = nextState
    switch (action.type) { 
      case &#39;LOG_IN_REQUEST&#39;:
        draft.data = null;
        draft.isLoggingIn = true;
        break;
      case &#39;LOG_IN_SUCCESS&#39;:
        draft.data = action.data;
        draft.isLoggingIn = false;
        break;
      case &#39;LOG_IN_FAILURE&#39;:
        draft.data = null;
        draft.isLoggingIn = false;
        break;
      case &#39;LOG_OUT&#39;:
        draft.data = null;
        break;
      default:
        break;
    }
  });
};

module.exports = userReducer;</code></pre>
]]></description>
        </item>
    </channel>
</rss>