<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>lu_6.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Thu, 09 Jan 2025 08:12:50 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>lu_6.log</title>
            <url>https://velog.velcdn.com/images/lu_6/profile/e8ffaac5-1b80-482d-a485-2fb657c481fe/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. lu_6.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/lu_6" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Vue Composition API]]></title>
            <link>https://velog.io/@lu_6/Vue-Composition-API</link>
            <guid>https://velog.io/@lu_6/Vue-Composition-API</guid>
            <pubDate>Thu, 09 Jan 2025 08:12:50 GMT</pubDate>
            <description><![CDATA[<h1 id="composition-api">Composition API</h1>
<p>Vue Composition API는 Vue 3에서 새롭게 도입된 API로, 기존의 Options API를 보완하거나 대체할 수 있는 기능을 제공합니다. 
주로 코드의 재사용성과 가독성을 높이고 더 유연한 상태 관리 및 로직 구성을 가능하게 합니다.</p>
<pre><code>&lt;script setup&gt;
import { computed } from &quot;vue&quot;;
import Child from &quot;./components/Child.vue&quot;;

const count = ref(0);
const arr = reactive([1,2,3])
const double = computed(() =&gt; count.value * 2);
const increment = () =&gt; count.value++;

provide(&quot;provideC&quot;, count);

watch(count, () =&gt; {
  console.log(&quot;state2 changed&quot;);
});
&lt;/script&gt;
&lt;template&gt;
  &lt;h1&gt;{{ count }}&lt;/h1&gt;
  &lt;h2&gt;{{ double }}&lt;/h2&gt;
  &lt;button @click=&quot;increment&quot;&gt;증가&lt;/button&gt;
  &lt;Child :count=&quot;count&quot;/&gt;
&lt;/template&gt;
&lt;style scoped&gt;&lt;/style&gt;</code></pre><pre><code>&lt;script setup&gt;
import { inject, onMounted } from &quot;vue&quot;;

const props = defineProps({
    count:Number
})

const provideC = inject(&quot;provideC&quot;)
onMounted(() =&gt; {});
&lt;/script&gt;
&lt;template&gt;
   &lt;h1&gt;life&lt;/h1&gt;
   &lt;p&gt;{{ props.count }}&lt;/p&gt;
   &lt;p&gt;pc {{ provideC }}&lt;/p&gt;
&lt;/template&gt;
&lt;style scoped&gt;&lt;/style&gt;</code></pre><ul>
<li>setup : Composition API를 더욱 간편하게 사용할 수 있도록 제공되는 컴파일 타임 전용 문법입니다.</li>
<li>ref와 reactive : ref는 기본자료형, reactive는 참조 자료형의 값에 대한 반응성을 제공합니다.</li>
<li>computed : 계산된 값을 정의할 때 사용합니다.</li>
<li>watch : 특정 상태를 감시하여 그 상태가 변할 때 추가적인 동작을 수행합니다</li>
<li>defineProps : defineProps를 사용하면 컴포넌트의 props를 선언하고 사용할 수 있습니다.</li>
<li>defineEmits : defineEmits를 사용하여 컴포넌트에서 이벤트를 선언합니다.</li>
<li>provide, inject : 부모-자식 관계(또는 더 깊은 하위 관계)에서 데이터를 공유하기 위해 사용합니다.</li>
<li>라이프사이클 : onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Vue slot]]></title>
            <link>https://velog.io/@lu_6/Vue-slot</link>
            <guid>https://velog.io/@lu_6/Vue-slot</guid>
            <pubDate>Thu, 09 Jan 2025 07:44:09 GMT</pubDate>
            <description><![CDATA[<h1 id="슬롯">슬롯</h1>
<p>템플릿 조각을 자식 컴포넌트에 전달하고 자식 컴포넌트가 자체 템플릿 내에서 조각을 렌더링하도록 할 수 있습니다.</p>
<pre><code>&lt;FancyButton&gt;
  클릭하기! &lt;!-- 슬롯 컨텐츠 --&gt;
&lt;/FancyButton&gt;</code></pre><pre><code>&lt;button class=&quot;fancy-btn&quot;&gt;
  &lt;slot&gt;&lt;/slot&gt; &lt;!-- 슬롯 아울렛 --&gt;
&lt;/button&gt;</code></pre><p>슬롯 사용 시, FancyButton이 button을 렌더링하고, 내부 컨텐츠를 자식 컴포넌트에게 제공합니다.
슬롯을 사용하면 재사용한 컴포넌트를 만들 수 있습니다.</p>
<h2 id="렌더링-범위">렌더링 범위</h2>
<p>슬롯 컨텐츠는 부모 컴포넌트에 정의되어 있으므로 부모 컴포넌트의 데이터 범위에 접근할 수 있습니다.
슬롯 콘텐츠에는 하위 컴포넌트의 데이터에 대한 액세스 권한이 없습니다.</p>
<h2 id="대체-컨텐츠">대체 컨텐츠</h2>
<p>슬롯에 대체(fallback) 컨텐츠를 지정하여, 컨텐츠가 제공되지 않을 때만 렌더링되도록 할 수 있습니다.</p>
<pre><code>&lt;button type=&quot;submit&quot;&gt;
  &lt;slot&gt;
    제출 &lt;!-- 대체 컨텐츠 --&gt;
  &lt;/slot&gt;
&lt;/button&gt;</code></pre><h2 id="이름이-있는-슬롯">이름이 있는 슬롯</h2>
<p>단일 컴포넌트에 여러 개의 슬롯 아울렛이 있는 경우 사용합니다.
name이 없는 slot 아울렛은 암시적으로 &quot;default&quot;라는 이름을 갖습니다.</p>
<pre><code>&lt;div class=&quot;container&quot;&gt;
  &lt;header&gt;
    &lt;slot name=&quot;header&quot;&gt;&lt;/slot&gt;
  &lt;/header&gt;
  &lt;main&gt;
    &lt;slot&gt;&lt;/slot&gt;
  &lt;/main&gt;
  &lt;footer&gt;
    &lt;slot name=&quot;footer&quot;&gt;&lt;/slot&gt;
  &lt;/footer&gt;
&lt;/div&gt;</code></pre><p>이름이 있는 슬롯을 전달하려면, template 엘리먼트와 함께 v-slot 디렉티브를 사용하고, 슬롯 이름을 v-slot (#)에 인자로 전달해야 합니다</p>
<pre><code>&lt;BaseLayout&gt;
  &lt;template #:header&gt;
    &lt;!-- 헤더 슬롯의 컨텐츠 --&gt;
  &lt;/template&gt;
&lt;/BaseLayout&gt;</code></pre><h2 id="동적인-슬롯-이름">동적인 슬롯 이름</h2>
<pre><code>&lt;base-layout&gt;
  &lt;template v-slot:[dynamicSlotName]&gt;
    ...
  &lt;/template&gt;

  &lt;!-- 단축 문법 사용 --&gt;
  &lt;template #[dynamicSlotName]&gt;
    ...
  &lt;/template&gt;
&lt;/base-layout&gt;</code></pre><h2 id="범위가-지정된-슬롯">범위가 지정된 슬롯</h2>
<p>props를 컴포넌트에 전달하는 것처럼 속성을 슬롯 아울렛에 전달할 수 있습니다</p>
<pre><code>&lt;!-- &lt;MyComponent&gt; 템플릿 --&gt;
&lt;div&gt;
  &lt;slot :text=&quot;greetingMessage&quot; :count=&quot;1&quot;&gt;&lt;/slot&gt;
&lt;/div&gt;</code></pre><pre><code>&lt;!-- 부모 템플릿 --&gt;
&lt;MyComponent v-slot=&quot;{ text, count }&quot;&gt;
  {{ text }} {{ count }}
&lt;/MyComponent&gt;</code></pre><h2 id="이름이-있고-범위가-지정된-슬롯">이름이 있고 범위가 지정된 슬롯</h2>
<pre><code>&lt;MyComponent&gt;
  &lt;template #header=&quot;headerProps&quot;&gt;
    {{ headerProps }}
  &lt;/template&gt;

  &lt;template #default=&quot;defaultProps&quot;&gt;
    {{ defaultProps }}
  &lt;/template&gt;

  &lt;template #footer=&quot;footerProps&quot;&gt;
    {{ footerProps }}
  &lt;/template&gt;
&lt;/MyComponent&gt;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Vue provide/inject]]></title>
            <link>https://velog.io/@lu_6/Vue-provideinject</link>
            <guid>https://velog.io/@lu_6/Vue-provideinject</guid>
            <pubDate>Wed, 08 Jan 2025 07:24:16 GMT</pubDate>
            <description><![CDATA[<h2 id="prop-드릴링">Prop 드릴링</h2>
<p>provide와 inject는 Vue.js에서 컴포넌트 간 데이터 전달을 단순화하기 위해 사용됩니다.
특히, 부모 컴포넌트와 하위 컴포넌트 간에 중첩 구조가 깊어지는 경우에 유용합니다.</p>
<h2 id="provide">Provide</h2>
<pre><code>export default {
  provide: {
    message: &#39;안녕!&#39;
  }
}</code></pre><p>data()를 통해 선언된 데이터와 같이 인스턴스별 상태를 제공해야 하는 경우, provide는 함수 값을 사용해야 합니다</p>
<pre><code>export default {
  data() {
    return {
      message: &#39;안녕!&#39;
    }
  },
  provide() {
    // 함수 구문을 사용하여 `this`에 접근할 수 있습니다.
    return {
      message: this.message
    }
  }
}</code></pre><h2 id="inject">Inject</h2>
<pre><code>export default {
  inject: [&#39;message&#39;],
  created() {
    console.log(this.message) // 주입된 값
  }
}</code></pre><p>inject는 컴포넌트 자체 상태보다 먼저 구성되므로, data()에서 주입된 속성에 접근할 수 있습니다</p>
<pre><code>export default {
  inject: [&#39;message&#39;],
  data() {
    return {
      // 주입된 값을 기반으로 하는 초기 데이터
      fullMessage: this.message
    }
  }
}</code></pre><h3 id="inject시-기본-값-설정하기">inject시 기본 값 설정하기</h3>
<pre><code>export default {
  // 주입에 대한 기본값을 선언할 때
  // 객체 구문이 필요합니다.
  inject: {
    message: {
      from: &#39;message&#39;, // 주입 시 키와 같은 이름을 사용하는 경우 선택사항입니다.
      default: &#39;이것은 기본 값 문자열 입니다.&#39;
    },
    user: {
      // 생성하는 데 비용이 많이 드는 기본이 아닌 값 또는 컴포넌트 인스턴스마다
      // 고유해야 하는 값에 대해 팩토리 함수를 사용합니다.
      default: () =&gt; ({ name: &#39;철수&#39; })
    }
  }
}</code></pre><h3 id="반응형으로-만들기">반응형으로 만들기</h3>
<p>provide로 공급한 데이터는 반응성을 갖지 않습니다.
inject로 받은 값을 바꿔도 화면에 반영되지 않습니다.
반응형으로 연결된 inject를 만들기 위해, computed() 함수를 사용하여 계산된 속성을 제공해야 합니다</p>
<pre><code>import { computed } from &#39;vue&#39;

export default {
  data() {
    return {
      message: &#39;안녕!&#39;
    }
  },
  provide() {
    return {
      // 계산된 속성을 명시적으로 제공
      message: computed(() =&gt; this.message)
    }
  }
}</code></pre><h3 id="심볼-키-사용하기">심볼 키 사용하기</h3>
<p>많은 의존성 제공자가 있는 대규모 앱에서 작업하거나, 다른 개발자가 사용할 컴포넌트를 작성하는 경우, 잠재적 충돌을 피하기 위해 제공 키로 Symbol(심볼)을 사용하는 것이 가장 좋습니다.</p>
<pre><code>// keys.js
export const myInjectionKey = Symbol()</code></pre><pre><code>// 제공하는 곳의 컴포넌트에서
import { myInjectionKey } from &#39;./keys.js&#39;

export default {
  provide() {
    return {
      [myInjectionKey]: {
        /* 제공할 데이터 */
      }
    }
  }
}</code></pre><pre><code>// 주입되는 곳의 컴포넌트에서
import { myInjectionKey } from &#39;./keys.js&#39;

export default {
  inject: {
    injected: { from: myInjectionKey }
  }
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Vue 컴포넌트 이벤트]]></title>
            <link>https://velog.io/@lu_6/Vue-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%9D%B4%EB%B2%A4%ED%8A%B8</link>
            <guid>https://velog.io/@lu_6/Vue-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%9D%B4%EB%B2%A4%ED%8A%B8</guid>
            <pubDate>Wed, 08 Jan 2025 07:18:48 GMT</pubDate>
            <description><![CDATA[<h2 id="이벤트-발생-및-수신">이벤트 발생 및 수신</h2>
<p>$emit : 자식 컴포넌트에서 이벤트를 발생시켜 부모 컴포넌트에 신호를 보냅니다.</p>
<pre><code>&lt;!-- Child.vue --&gt;
&lt;template&gt;
  &lt;button @click=&quot;$emit(&#39;custom-event&#39;, &#39;Hello from Child!&#39;)&quot;&gt;Click Me&lt;/button&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  emits: [&quot;custom-event&quot;], // 정의된 이벤트
};
&lt;/script&gt;
</code></pre><p>@ : 부모 컴포넌트에서 자식 컴포넌트의 이벤트를 리스닝합니다.</p>
<pre><code>&lt;!-- Parent.vue --&gt;
&lt;template&gt;
  &lt;Child @custom-event=&quot;handleCustomEvent&quot; /&gt;
&lt;/template&gt;

&lt;script&gt;
import Child from &#39;./Child.vue&#39;;

export default {
  components: { Child },
  methods: {
    handleCustomEvent(message) {
      alert(message); // &quot;Hello from Child!&quot;
    },
  },
};
&lt;/script&gt;
</code></pre><h2 id="이벤트-인수">이벤트 인수</h2>
<p>$emit에 추가 인수를 전달할 수 있습니다</p>
<pre><code>&lt;!-- 자식 컴포넌트 (Child.vue) --&gt;
&lt;template&gt;
  &lt;button @click=&quot;$emit(&#39;custom-event&#39;, &#39;Hello&#39;, 42)&quot;&gt;Click Me&lt;/button&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  emits: [&#39;custom-event&#39;],
};
&lt;/script&gt;
</code></pre><pre><code>&lt;!-- 부모 컴포넌트 (Parent.vue) --&gt;
&lt;template&gt;
  &lt;Child @custom-event=&quot;handleEvent&quot; /&gt;
&lt;/template&gt;

&lt;script&gt;
import Child from &#39;./Child.vue&#39;;

export default {
  components: { Child },
  methods: {
    handleEvent(message, number) {
      console.log(message); // 출력: &quot;Hello&quot;
      console.log(number);  // 출력: 42
    },
  },
};
&lt;/script&gt;
</code></pre><h2 id="이벤트-유효성-검사">이벤트 유효성 검사</h2>
<p>prop 타입 유효성 검사와 마찬가지로, 배열 구문 대신 객체 구문으로 정의된 이벤트는 유효성 검사가 가능합니다.</p>
<pre><code>export default {
  emits: {
    // 유효성 검사 없음
    click: null,

    // submit 이벤트 유효성 검사
    submit: ({ email, password }) =&gt; {
      if (email &amp;&amp; password) {
        return true
      } else {
        console.warn(&#39;Invalid submit event payload!&#39;)
        return false
      }
    }
  },
  methods: {
    submitForm(email, password) {
      this.$emit(&#39;submit&#39;, { email, password })
    }
  }
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Vue props]]></title>
            <link>https://velog.io/@lu_6/Vue-props</link>
            <guid>https://velog.io/@lu_6/Vue-props</guid>
            <pubDate>Wed, 08 Jan 2025 07:02:38 GMT</pubDate>
            <description><![CDATA[<h1 id="props">props</h1>
<p>부모 컴포넌트에서 자식 컴포넌트로 값을 전달하는 데이터입니다.</p>
<p>props는 props 옵션을 사용하여 선언됩니다</p>
<pre><code>export default {
  props: [&#39;foo&#39;],
  created() {
    // props는 `this`에 노출됩니다.
    console.log(this.foo)
  }
}</code></pre><p>문자열 배열을 사용하여 props를 선언하는 것 외에도 객체 선언 문법을 사용할 수도 있습니다</p>
<pre><code>export default {
  props: {
    title: String,
    likes: Number
  }
}</code></pre><h2 id="props-이름-케이싱">Props 이름 케이싱</h2>
<p>긴 속성명을 선언할 때 obj[&#39;kebab-case&#39;]와 같이 키에 따옴표를 사용하는 번거로움을 줄이기 위해, obj.camelCase와 같이 camelCase를 사용합니다.</p>
<pre><code>export default {
  props: {
    greetingMessage: {
    type: String,
    required:true,
    }
  }
}</code></pre><pre><code>&lt;MyComponent greeting-message=&quot;안녕!&quot; /&gt;</code></pre><p>props 옵션에서 디테일한 설정이 가능합니다:</p>
<ul>
<li>type: 전달받을 데이터 타입을 제한합니다.</li>
<li>default: 기본값을 설정합니다.</li>
<li>required: 해당 prop이 반드시 전달되어야 하는지 여부를 설정합니다.</li>
<li>validator: 전달된 값이 유효한지 검사하는 함수입니다.</li>
</ul>
<h2 id="단방향-데이터-흐름">단방향 데이터 흐름</h2>
<p>모든 props는 자식 속성과 부모 속성 사이에 하향식 단방향 바인딩을 형성합니다.
부모 속성이 업데이트되면 자식으로 흐르지만 그 반대는 안됩니다.</p>
<h2 id="prop-유효성-검사">Prop 유효성 검사</h2>
<p> 컴포넌트는 props에 타입을 지정할 수 있습니다.
 지정한 요구 사항이 충족되지 않으면 Vue는 브라우저의 JavaScript 콘솔에서 경고합니다.</p>
<pre><code>    props: {
      validator(value, props) {
        // 값은 이 문자열 중 하나와 일치해야 합니다
        return [&#39;성공&#39;, &#39;경고&#39;, &#39;위험&#39;].includes(value)
      }
    },</code></pre><h2 id="불리언-캐스팅">불리언 캐스팅</h2>
<p>Boolean 타입의 props는 네이티브 불리언 속성의 동작을 모방하는 특별한 캐스팅 규칙이 있습니다.</p>
<pre><code>export default {
  props: {
    disabled: Boolean
  }
}</code></pre><pre><code>&lt;!-- :disabled=&quot;true&quot; 같음 --&gt;
&lt;MyComponent disabled /&gt;

&lt;!-- :disabled=&quot;false&quot; 같음 --&gt;
&lt;MyComponent /&gt;</code></pre><p>여러 타입을 허용하도록 프롭(prop)을 선언할 때, Boolean에 대한 캐스팅 규칙도 적용됩니다.
그러나 String과 Boolean이 모두 허용되는 경우에는 주의해야 합니다 - Boolean 캐스팅 규칙은 String보다 앞에 위치해야만 적용됩니다</p>
<pre><code>// disabled는 true로 캐스팅됩니다
export default {
  props: {
    disabled: [Boolean, Number]
  }
}
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Vue 감시자 속성]]></title>
            <link>https://velog.io/@lu_6/Vue-%EA%B0%90%EC%8B%9C%EC%9E%90-%EC%86%8D%EC%84%B1</link>
            <guid>https://velog.io/@lu_6/Vue-%EA%B0%90%EC%8B%9C%EC%9E%90-%EC%86%8D%EC%84%B1</guid>
            <pubDate>Tue, 07 Jan 2025 07:51:37 GMT</pubDate>
            <description><![CDATA[<h1 id="감시자-속성-watchers">감시자 속성 (Watchers)</h1>
<p>Vue.js에서 <strong>감시자 (Watcher)</strong> 는 데이터가 변경될 때 반응적으로 특정 로직을 실행할 수 있는 방법입니다.
주로 data 속성이나 computed 속성의 변화를 감지하고, 해당 데이터가 변할 때 자동으로 특정 작업을 수행하는 데 사용됩니다.</p>
<ul>
<li>watchedProperty: 감시할 데이터 속성</li>
<li>newVal: 속성의 변경 후 값.</li>
<li>oldVal: 속성의 변경 전 값.</li>
</ul>
<pre><code>&lt;script&gt;
export default {
  data() {
    return {
      age: 25,
    };
  },
  watch: {
    age(newVal, oldVal) {
      console.log(`Age changed from ${oldVal} to ${newVal}`);
    },
  },
};
&lt;/script&gt;</code></pre><h2 id="깊은-감시-deep-watch">깊은 감시 (Deep Watch)</h2>
<p>기본적으로 watch는 기본 자료형의 변경만 감지합니다.
만약 객체나 배열처럼 참조 자료형의 내부 값 변화를 감지하려면, 깊은 감시(deep: true)를 사용해야 합니다.</p>
<pre><code>watch: {
  &#39;watchedProperty&#39;: {
    handler(newValue, oldValue) {
      // 객체나 배열 내부 값이 변할 때마다 실행
    },
    deep: true // 깊은 감시 설정
  }
}</code></pre><p>ex</p>
<pre><code>&lt;template&gt;
  &lt;div&gt;
    &lt;button @click=&quot;changeObject&quot;&gt;Change Object&lt;/button&gt;
    &lt;p&gt;{{ userInfo }}&lt;/p&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  data() {
    return {
      userInfo: { name: &#39;John&#39;, age: 25 }
    };
  },
  watch: {
    userInfo: {
      handler(newVal, oldVal) {
        console.log(&#39;userInfo changed:&#39;, oldVal, &#39;-&gt;&#39;, newVal);
      },
      deep: true
    }
  },
  methods: {
    changeObject() {
      this.userInfo.name = &#39;Jane&#39;; // name만 변경
    }
  }
};
&lt;/script&gt;</code></pre><p>userInfo 객체가 깊은 감시를 받기 때문에, 객체의 내부 속성이 변할 때마다 handler가 호출됩니다.</p>
<p><code>immediate</code>: 감시자 생성 시 즉시 콜백 트리거. 첫 호출 시 이전 값은 undefined.
immediate: true를 사용하면 초기화 시점에도 watch 콜백을 즉시 실행할 수 있습니다. 기본적으로 watch는 데이터가 변경된 후에만 호출됩니다. 그러나 immediate를 설정하면 컴포넌트가 생성될 때에도 콜백이 실행됩니다.</p>
<pre><code>watch: {
  counter: {
    handler(newVal, oldVal) {
      console.log(`Counter changed: ${oldVal} -&gt; ${newVal}`);
    },
    immediate: true // 컴포넌트 생성 시점에도 호출
  }
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Vue 생명주기]]></title>
            <link>https://velog.io/@lu_6/Vue-%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0</link>
            <guid>https://velog.io/@lu_6/Vue-%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0</guid>
            <pubDate>Tue, 07 Jan 2025 07:41:43 GMT</pubDate>
            <description><![CDATA[<p>Vue의 <strong>생명주기(lifecycle)</strong> 는 Vue 인스턴스가 생성되고 업데이트되며 파괴될 때까지의 일련의 과정을 의미합니다.
Vue는 이 과정을 여러 단계로 나누어 각 단계에서 특정 작업을 수행할 수 있는 <strong>생명주기 훅(lifecycle hook)</strong> 을 제공합니다.</p>
<h2 id="vue-생명주기-흐름">Vue 생명주기 흐름</h2>
<p>Vue의 생명주기는 다음과 같은 순서로 진행됩니다</p>
<p>beforeCreate
created
beforeMount
mounted
beforeUpdate
updated
beforeUnmount
unmounted
각 생명주기 훅은 특정 시점에 자동으로 호출되며, 그에 따라 특정 로직을 실행할 수 있습니다.</p>
<h3 id="1-beforecreate">1. beforeCreate</h3>
<p>시점: Vue 인스턴스가 생성되기 직전.
특징: data, computed, watch 등의 옵션이 설정되지 않았기 때문에 인스턴스의 초기화가 아직 완료되지 않은 상태입니다.
용도: 데이터가 아직 설정되지 않았거나, 인스턴스가 초기화되기 전에 해야 할 작업이 있을 경우 사용합니다.</p>
<h3 id="2-created">2. created</h3>
<p>시점: Vue 인스턴스가 생성되고, 데이터가 초기화된 후 호출됩니다.
특징: 데이터, 메소드, 계산된 속성 등 인스턴스가 초기화된 상태지만, DOM은 아직 렌더링되지 않았습니다.
용도: 서버에서 데이터를 가져오거나, 인스턴스가 생성된 후에 추가적인 로직을 수행할 때 사용합니다.</p>
<h3 id="3-beforemount">3. beforeMount</h3>
<p>시점: 컴포넌트가 마운트되기 직전, 즉 DOM에 처음 추가되기 전입니다.
특징: 아직 렌더링된 DOM 요소는 없지만, 템플릿이 컴파일된 상태입니다.
용도: 초기 렌더링 전에 DOM을 준비해야 할 때 사용합니다.</p>
<h3 id="4-mounted">4. mounted</h3>
<p>시점: 컴포넌트가 마운트된 후, 즉 DOM에 추가된 후 호출됩니다.
특징: DOM에 접근할 수 있으며, 외부 라이브러리나 API 요청 등을 사용할 수 있습니다.
용도: DOM을 직접 조작하거나, 외부 API에서 데이터를 가져오는 등의 작업에 적합합니다.</p>
<h3 id="5-beforeupdate">5. beforeUpdate</h3>
<p>시점: 데이터가 변경되어 DOM 업데이트가 일어나기 직전에 호출됩니다.
특징: DOM은 아직 업데이트되지 않았습니다.
용도: DOM 업데이트 전에 필요한 작업을 처리할 수 있습니다. 예를 들어, 특정 데이터 변경에 따른 처리가 필요할 때 사용합니다.</p>
<h3 id="6-updated">6. updated</h3>
<p>시점: 데이터가 변경되어 DOM이 업데이트된 후 호출됩니다.
특징: DOM이 업데이트된 후에 호출되므로, DOM이 완전히 반영된 상태에서 작업을 진행할 수 있습니다.
용도: DOM 변경 후 후속 작업이나 애니메이션 등을 처리할 때 사용됩니다.</p>
<h3 id="7-beforeunmount">7. beforeUnmount</h3>
<p>시점: 컴포넌트가 파괴되기 직전에 호출됩니다.
특징: 컴포넌트가 사라지기 전 상태에서 호출되므로, 자원을 해제하거나 리소스를 정리할 때 사용합니다.
용도: 타이머나 이벤트 리스너 제거 등의 작업에 적합합니다.</p>
<h3 id="8-unmounted">8. unmounted</h3>
<p>시점: 컴포넌트가 파괴된 후, 즉 DOM에서 완전히 제거된 후 호출됩니다.
특징: 컴포넌트가 완전히 사라졌으므로 더 이상 상태나 DOM을 변경할 수 없습니다.
용도: 정리 작업을 하거나, 남아 있는 이벤트 리스너나 인터벌 등을 제거하는 데 사용됩니다.</p>
<h3 id="beforeupdate-vs-updated">beforeUpdate vs updated</h3>
<p>beforeUpdate와 updated는 모두 데이터 변경 후 호출되는 생명주기 훅입니다.
차이점은 바로 &quot;DOM 업데이트 직전&quot;과 &quot;DOM 업데이트 직후&quot;의 시점 차이입니다.</p>
<p>beforeUpdate:
시점: 데이터가 변경되었지만, DOM이 아직 업데이트되기 전에 호출됩니다.
특징: 데이터 변경 사항이 UI에 반영되기 전에 호출됩니다.
용도: 이 훅에서 데이터 변경이 이루어지면 DOM에 반영되지 않기 때문에 필요한 추가 작업을 할 수 없습니다. 예를 들어, UI에서 데이터 변경을 보고 무엇을 해야 하는지 결정을 내릴 수 있지만, 그 시점에서는 DOM에 반영되지 않았기 때문에 상태 변화가 즉시 반영되지 않습니다.</p>
<p>updated:
시점: 데이터가 변경되고, DOM이 이미 업데이트된 후에 호출됩니다.
특징: 데이터 변경 사항이 UI에 반영된 후 호출됩니다.
용도: DOM 업데이트 이후의 작업을 처리할 수 있습니다. 예를 들어, 애니메이션을 실행하거나, 업데이트된 DOM을 기반으로 추가적인 로직을 수행할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Vue 컴포넌트 등록]]></title>
            <link>https://velog.io/@lu_6/Vue-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EB%93%B1%EB%A1%9D</link>
            <guid>https://velog.io/@lu_6/Vue-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EB%93%B1%EB%A1%9D</guid>
            <pubDate>Tue, 07 Jan 2025 03:52:33 GMT</pubDate>
            <description><![CDATA[<h1 id="vue-컴포넌트-등록-방법">Vue 컴포넌트 등록 방법</h1>
<h2 id="1-전역-컴포넌트-등록">1. 전역 컴포넌트 등록</h2>
<p>모든 컴포넌트에서 별도의 import 없이 사용할 수 있음.
Vue 애플리케이션 전역에 등록되므로 컴포넌트를 사용하지 않아도 로드됨.
보통 공용 컴포넌트(예: Modal, Button, Navbar)에 사용.</p>
<pre><code class="language-js">//main.js
import &quot;./assets/css/index.css&quot;;

import { createApp } from &quot;vue&quot;;
import App from &quot;./App.vue&quot;;
import First from &quot;./components/First.vue&quot;;

const app = createApp(App);
//전역 컴포넌트 등록 방법
app.component(&quot;First&quot;, First);

app.mount(&quot;#app&quot;);</code></pre>
<pre><code>&lt;script&gt;
import First from &quot;./components/First.vue&quot;;

export default {
  data() {
    return {};
  },
};
&lt;/script&gt;
&lt;template&gt;
  &lt;h1 className=&quot;text-3xl font-bold underline&quot;&gt;Hello world!&lt;/h1&gt;
  &lt;First /&gt;
&lt;/template&gt;</code></pre><h2 id="2-지역-컴포넌트-등록">2. 지역 컴포넌트 등록</h2>
<p>특정 컴포넌트 내부에서만 사용 가능.
Vue 컴포넌트 내의 components 옵션으로 등록.
성능 최적화 가능.
각 컴포넌트에서만 사용 가능하므로 네이밍 충돌 방지.
매번 import 및 components에 등록 필요.</p>
<pre><code>&lt;script&gt;
import First from &quot;./components/First.vue&quot;;

export default {
  name:&quot;App&quot;,
  components:{
    First
  },
  data() {
    return {};
  },
};
&lt;/script&gt;
&lt;template&gt;
  &lt;h1 className=&quot;text-3xl font-bold underline&quot;&gt;Hello world!&lt;/h1&gt;
  &lt;First /&gt;
&lt;/template&gt;</code></pre><h2 id="scoped">Scoped</h2>
<h3 id="scoped-스타일의-작동-원리">Scoped 스타일의 작동 원리</h3>
<p>Vue는 scoped 스타일을 자동으로 컴파일하여 각 컴포넌트의 DOM 요소에 <strong>고유한 특성(selector attribute)</strong> 을 추가합니다.
다음과 같이 스타일을 정의하면</p>
<pre><code>&lt;template&gt;
  &lt;div class=&quot;example&quot;&gt;Hello&lt;/div&gt;
&lt;/template&gt;

&lt;style scoped&gt;
.example {
  color: red;
}
&lt;/style&gt;</code></pre><p>컴파일 후 HTML은 다음과 같이 변환됩니다</p>
<pre><code>&lt;div class=&quot;example&quot; data-v-12345&gt; &lt;!-- 고유 데이터 속성 추가 --&gt;
  Hello
&lt;/div&gt;</code></pre><p>따라서, 이 스타일은 다른 컴포넌트의 example 클래스에 영향을 주지 않습니다.</p>
<h3 id="scoped와-자식-컴포넌트">Scoped와 자식 컴포넌트</h3>
<p>부모 컴포넌트의 scoped 스타일은 자식 컴포넌트의 루트 요소에도 영향을 줄 수 있습니다.
영향을 주지 않으려면 자식 컴포넌트를 다른 요소로 감싸야합니다.</p>
<pre><code>&lt;!-- ParentComponent.vue --&gt;
&lt;template&gt;
  &lt;div&gt;
    &lt;ChildComponent /&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;style scoped&gt;
div {
  color: red;
}
&lt;/style&gt;</code></pre><p>자식 컴포넌트의 루트 요소가 div인 경우, 부모의 스타일이 자식 컴포넌트에도 적용됩니다.</p>
<pre><code>&lt;!-- ChildComponent.vue --&gt;
&lt;template&gt;
  &lt;div&gt;I&#39;m a child component&lt;/div&gt;
&lt;/template&gt;</code></pre><h3 id="scoped와-속성">Scoped와 속성</h3>
<p>컴포넌트에서 속성을 설정하면, 해당 속성은 컴포넌트의 루트 요소에만 적용됩니다.
props 속성으로 데이터를 전달받을 수 있고, props로 받지 않는 속성만 root요소에 붙습니다.
만약 컴포넌트에 루트 요소가 없으면 속성이 적용되지 않습니다.
v:bind로 string아닌 다른 타입으로 전달 가능합니다.</p>
<pre><code>&lt;template&gt;
  &lt;MyComponent id=&quot;unique-id&quot; class=&quot;custom-class&quot; /&gt;
&lt;/template&gt;</code></pre><pre><code>&lt;div id=&quot;unique-id&quot; class=&quot;custom-class&quot; data-v-12345&gt;&lt;/div&gt;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Vue computed]]></title>
            <link>https://velog.io/@lu_6/Vue-computed</link>
            <guid>https://velog.io/@lu_6/Vue-computed</guid>
            <pubDate>Tue, 07 Jan 2025 01:10:36 GMT</pubDate>
            <description><![CDATA[<h1 id="계산된-속성-computed-properties">계산된 속성 (Computed Properties)</h1>
<p>계산된 속성은 Vue의 데이터 변경에 기반하여 자동으로 업데이트되는 <strong>읽기 전용 속성</strong>입니다.</p>
<p>경우에 따라 <strong>읽기-쓰기 속성</strong>으로도 활용할 수 있습니다.</p>
<p>데이터에 기반해서 가공처리를 할 때 사용하고, 연산비용이 높지 않아 Vue에서 권장하는 방법입니다.</p>
<p>데이터가 바뀌면 캐싱을 풀고 다시 계산합니다.</p>
<pre><code>&lt;script&gt;
export default {
  data() {
    return {
      firstName: &quot;Jane&quot;,
      lastName: &quot;Doe&quot;,
    };
  },
  computed: {
    fullName() {
      return `${this.firstName} ${this.lastName}`;
    },
  },
};
&lt;/script&gt;

&lt;template&gt;
  &lt;div&gt;
    &lt;p&gt;Full Name: {{ fullName }}&lt;/p&gt;
  &lt;/div&gt;
&lt;/template&gt;
</code></pre><p>fullName은 캐싱되며, firstName 또는 lastName이 변경될 때만 다시 계산됩니다.</p>
<h3 id="계산된-속성에-getter와-setter를-정의하여-데이터를-양방향으로-바인딩할-수-있습니다">계산된 속성에 getter와 setter를 정의하여, 데이터를 양방향으로 바인딩할 수 있습니다.</h3>
<pre><code>&lt;script&gt;
export default {
  data() {
    return {
      firstName: &quot;John&quot;,
      lastName: &quot;Smith&quot;,
    };
  },
  computed: {
    fullName: {
      get() {
        return `${this.firstName} ${this.lastName}`;
      },
      set(newValue) {
        const parts = newValue.split(&quot; &quot;);
        this.firstName = parts[0] || &quot;&quot;;
        this.lastName = parts[1] || &quot;&quot;;
      },
    },
  },
};
&lt;/script&gt;

&lt;template&gt;
  &lt;div&gt;
    &lt;input v-model=&quot;fullName&quot; /&gt;
    &lt;p&gt;First Name: {{ firstName }}&lt;/p&gt;
    &lt;p&gt;Last Name: {{ lastName }}&lt;/p&gt;
  &lt;/div&gt;
&lt;/template&gt;
</code></pre><p>사용자 입력에 따라 firstName과 lastName을 자동으로 업데이트할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Vue 이벤트]]></title>
            <link>https://velog.io/@lu_6/Vue-%EC%9D%B4%EB%B2%A4%ED%8A%B8</link>
            <guid>https://velog.io/@lu_6/Vue-%EC%9D%B4%EB%B2%A4%ED%8A%B8</guid>
            <pubDate>Tue, 07 Jan 2025 01:05:55 GMT</pubDate>
            <description><![CDATA[<h2 id="이벤트-리스닝">이벤트 리스닝</h2>
<p>일반적으로 v-on 디렉티브는 단축 문법으로 @ 기호를 사용합니다.
v-on:click=&quot;handler&quot; 또는 줄여서 @click=&quot;handler&quot;와 같이 사용합니다.</p>
<pre><code>&lt;button @click=&quot;count++&quot;&gt;1 추가&lt;/button&gt;
&lt;p&gt;숫자 값은: {{ count }}&lt;/p&gt;</code></pre><h2 id="이벤트-객체-접근하기">이벤트 객체 접근하기</h2>
<p>$event를 사용하여 메서드에 전달하거나 인라인 화살표 함수를 사용할 수 있습니다.</p>
<pre><code>&lt;!-- 특수한 키워드인 $event 사용 --&gt;
&lt;button @click=&quot;warn(&#39;아직 양식을 제출할 수 없습니다.&#39;, $event)&quot;&gt;
  제출하기
&lt;/button&gt;

&lt;!-- 인라인 화살표 함수 사용 --&gt;
&lt;button @click=&quot;(event) =&gt; warn(&#39;아직 양식을 제출할 수 없습니다.&#39;, event)&quot;&gt;
  제출하기
&lt;/button&gt;


function warn(message, event) {
  // 이제 네이티브 이벤트 객체에 접근할 수 있습니다.
  if (event) {
    event.preventDefault()
  }
  alert(message)
}</code></pre><h2 id="이벤트-수식어">이벤트 수식어</h2>
<p>v-on은 점(.)으로 시작하는 지시적 접미사인 이벤트 수식어를 제공합니다.</p>
<pre><code>&lt;!-- 클릭 이벤트 전파가 중지됩니다. --&gt;
&lt;a @click.stop=&quot;doThis&quot;&gt;&lt;/a&gt;

&lt;!-- submit 이벤트가 더 이상 페이지 리로드하지 않습니다. --&gt;
&lt;form @submit.prevent=&quot;onSubmit&quot;&gt;&lt;/form&gt;

&lt;!-- 수식어를 연결할 수 있습니다. --&gt;
&lt;a @click.stop.prevent=&quot;doThat&quot;&gt;&lt;/a&gt;

&lt;!-- 이벤트에 핸들러 없이 수식어만 사용할 수 있습니다. --&gt;
&lt;form @submit.prevent&gt;&lt;/form&gt;

&lt;!-- event.target이 엘리먼트 자신일 경우에만 핸들러가 실행됩니다. --&gt;
&lt;!-- 예를 들어 자식 엘리먼트에서 클릭 액션이 있으면 핸들러가 실행되지 않습니다. --&gt;
&lt;div @click.self=&quot;doThat&quot;&gt;...&lt;/div&gt;

&lt;!-- 이벤트 리스너를 추가할 때 캡처 모드 사용           --&gt;
&lt;!-- 내부 엘리먼트에서 클릭 이벤트 핸들러가 실행되기 전에, --&gt;
&lt;!-- 여기에서 먼저 핸들러가 실행됩니다.                --&gt;
&lt;div @click.capture=&quot;doThis&quot;&gt;...&lt;/div&gt;

&lt;!-- 클릭 이벤트는 단 한 번만 실행됩니다. --&gt;
&lt;a @click.once=&quot;doThis&quot;&gt;&lt;/a&gt;

&lt;!-- 핸들러 내 `event.preventDefault()`가 포함되었더라도 --&gt;
&lt;!-- 스크롤 이벤트의 기본 동작(스크롤)이 발생합니다.        --&gt;
&lt;div @scroll.passive=&quot;onScroll&quot;&gt;...&lt;/div&gt;</code></pre><h2 id="입력키-수식어">입력키 수식어</h2>
<p>키보드 이벤트를 수신할 때, 특정 키를 확인해야 하는 경우가 많기 때문에, 키 수식어를 지원합니다:</p>
<pre><code>&lt;!-- `key`가 `Enter`일 때만 `submit`을 호출합니다 --&gt;
&lt;input @keyup.enter=&quot;submit&quot; /&gt;

&lt;!-- $event.key가 &#39;PageDown&#39;일 경우에만 호출됩니다 --&gt;
&lt;input @keyup.page-down=&quot;onPageDown&quot; /&gt;

&lt;!-- Alt + Enter --&gt;
&lt;input @keyup.alt.enter=&quot;clear&quot; /&gt;

&lt;!-- Ctrl + Click --&gt;
&lt;div @click.ctrl=&quot;doSomething&quot;&gt;시작하기&lt;/div&gt;

&lt;!-- exact --&gt;
&lt;!-- Ctrl과 함께 Alt 또는 Shift를 누른 상태에서도 클릭하면 실행됩니다. --&gt;
&lt;button @click.ctrl=&quot;onClick&quot;&gt;A&lt;/button&gt;

&lt;!-- 오직 Ctrl만 누른 상태에서 클릭해야 실행됩니다. --&gt;
&lt;button @click.ctrl.exact=&quot;onCtrlClick&quot;&gt;A&lt;/button&gt;

&lt;!-- 시스템 입력키를 누르지 않고 클릭해야지만 실행됩니다. --&gt;
&lt;button @click.exact=&quot;onClick&quot;&gt;A&lt;/button&gt;</code></pre><h2 id="마우스-버튼-수식어">마우스 버튼 수식어</h2>
<p>특정 마우스 버튼에 의해 이벤트가 트리거 되도록 제한하고 싶을 때 사용합니다.
<code>.left</code> <code>.right</code> <code>.middle</code></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Lv1. 숫자 문자열과 영단어]]></title>
            <link>https://velog.io/@lu_6/Lv1.-%EC%88%AB%EC%9E%90-%EB%AC%B8%EC%9E%90%EC%97%B4%EA%B3%BC-%EC%98%81%EB%8B%A8%EC%96%B4</link>
            <guid>https://velog.io/@lu_6/Lv1.-%EC%88%AB%EC%9E%90-%EB%AC%B8%EC%9E%90%EC%97%B4%EA%B3%BC-%EC%98%81%EB%8B%A8%EC%96%B4</guid>
            <pubDate>Sun, 05 Jan 2025 15:02:13 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/81301">https://school.programmers.co.kr/learn/courses/30/lessons/81301</a>
네오와 프로도가 숫자놀이를 하고 있습니다. 네오가 프로도에게 숫자를 건넬 때 일부 자릿수를 영단어로 바꾼 카드를 건네주면 프로도는 원래 숫자를 찾는 게임입니다.</p>
<p>다음은 숫자의 일부 자릿수를 영단어로 바꾸는 예시입니다.</p>
<p>1478 → &quot;one4seveneight&quot;
234567 → &quot;23four5six7&quot;
10203 → &quot;1zerotwozero3&quot;
이렇게 숫자의 일부 자릿수가 영단어로 바뀌어졌거나, 혹은 바뀌지 않고 그대로인 문자열 s가 매개변수로 주어집니다. s가 의미하는 원래 숫자를 return 하도록 solution 함수를 완성해주세요.</p>
<h2 id="정답-코드">정답 코드</h2>
<pre><code class="language-js">function solution(s) {
  const numbers = {
    0: &quot;zero&quot;,
    1: &quot;one&quot;,
    2: &quot;two&quot;,
    3: &quot;three&quot;,
    4: &quot;four&quot;,
    5: &quot;five&quot;,
    6: &quot;six&quot;,
    7: &quot;seven&quot;,
    8: &quot;eight&quot;,
    9: &quot;nine&quot;,
  };
  let word = &quot;&quot;;
  let result = &quot;&quot;;
  for (let i = 0; i &lt; s.length; i++) {
    word += s[i];
    if (!isNaN(Number(word))) {
      result += word;
      word = &quot;&quot;;
    } else {
      for (key in numbers) {
        if (word === numbers[key]) {
          result += key;
          word = &quot;&quot;;
          break;
        }
      }
    }
  }

  return Number(result);
}

//&quot;one4seveneight&quot;    1478</code></pre>
<h2 id="해설">해설</h2>
<ol>
<li>영단어 표를 객체로 선언해줍니다.</li>
<li>word = 객체에 단어가 포함되어있는지 확인하기 위함  result = 결과 반환용</li>
<li>매개변수로 받은 s를 반복하면서 word에 추가해줍니다.</li>
<li>추가한 후, 만약 word가 숫자라면 result에 추가하고 word를 초기화합니다.
!isNaN(Number(word)) =&gt; 만약 숫자가 아닌 알파벳이라면 Number(word)가 NaN이므로 false</li>
<li>만약 알파벳이라면 word가  선언한 numbers 객체의 값(numbers[key])과 일치하는 것이 있는지 확인합니다.</li>
<li>일치하는 것이 있다면 result에 key를 추가합니다.</li>
<li>일치하는 것이 없다면 다시 반복문을 진행합니다.</li>
<li>반복문이 끝난 후 string 형태의 result를 숫자로 바꿔 반환합니다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Lv1. 두 개 뽑아서 더하기]]></title>
            <link>https://velog.io/@lu_6/Lv1.-%EB%91%90-%EA%B0%9C-%EB%BD%91%EC%95%84%EC%84%9C-%EB%8D%94%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@lu_6/Lv1.-%EB%91%90-%EA%B0%9C-%EB%BD%91%EC%95%84%EC%84%9C-%EB%8D%94%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 05 Jan 2025 14:53:33 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/68644">https://school.programmers.co.kr/learn/courses/30/lessons/68644</a>
정수 배열 numbers가 주어집니다. numbers에서 서로 다른 인덱스에 있는 두 개의 수를 뽑아 더해서 만들 수 있는 모든 수를 배열에 오름차순으로 담아 return 하도록 solution 함수를 완성해주세요.</p>
<h2 id="정답-코드">정답 코드</h2>
<pre><code class="language-js">function solution(numbers) {
  const set = new Set();
  for (let i = 0; i &lt; numbers.length; i++) {
    for (let j = i + 1; j &lt; numbers.length; j++) {
      set.add(numbers[i] + numbers[j]);
    }
  }
  return Array.from(set).sort((a, b) =&gt; a - b);
}

// [2,1,3,4,1] =&gt; [2,3,4,5,6,7]</code></pre>
<h2 id="해설">해설</h2>
<ol>
<li>두 수를 더해서 만들 수 있는 수를 반환해야 하므로 중복이 없는 set을 선언해줍니다.</li>
<li>숫자를 더하면서 set에 추가합니다. (2+1=3, 2+3=5, 2+4=6, 2+1=3(이미 set에 있으므로 추가X))</li>
<li>set을 오름차순 정렬한 후, 배열로 바꿔 반환합니다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Lv.1 3진법 뒤집기]]></title>
            <link>https://velog.io/@lu_6/Lv.1-3%EC%A7%84%EB%B2%95-%EB%92%A4%EC%A7%91%EA%B8%B0</link>
            <guid>https://velog.io/@lu_6/Lv.1-3%EC%A7%84%EB%B2%95-%EB%92%A4%EC%A7%91%EA%B8%B0</guid>
            <pubDate>Sun, 05 Jan 2025 14:48:55 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/68935">https://school.programmers.co.kr/learn/courses/30/lessons/68935</a>
자연수 n이 매개변수로 주어집니다. n을 3진법 상에서 앞뒤로 뒤집은 후, 이를 다시 10진법으로 표현한 수를 return 하도록 solution 함수를 완성해주세요.</p>
<h2 id="정답-코드">정답 코드</h2>
<pre><code class="language-js">function solution(n) {
  const str = n.toString(3);
  let reversed = &quot;&quot;;
  for (let i = str.length - 1; i &gt;= 0; i--) {
    reversed += str[i];
  }
  return parseInt(reversed, 3);
}</code></pre>
<h2 id="해설">해설</h2>
<ol>
<li>n을 toString(3)으로 3진법으로 바꿔준다. (str = &#39;1200&#39;)</li>
<li>3진법으로 바꾼 것을 뒤에서부터 reversed에 추가한다. (reversed = &#39;0012&#39;)</li>
<li>parseInt(reversed, 3)를 이용하여 reversed를 3진법에서 10진법으로 바꿔준다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Lv1. 예산]]></title>
            <link>https://velog.io/@lu_6/Lv1.-%EC%98%88%EC%82%B0</link>
            <guid>https://velog.io/@lu_6/Lv1.-%EC%98%88%EC%82%B0</guid>
            <pubDate>Sun, 05 Jan 2025 14:40:31 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/12982">https://school.programmers.co.kr/learn/courses/30/lessons/12982</a></p>
<p>S사에서는 각 부서에 필요한 물품을 지원해 주기 위해 부서별로 물품을 구매하는데 필요한 금액을 조사했습니다. 그러나, 전체 예산이 정해져 있기 때문에 모든 부서의 물품을 구매해 줄 수는 없습니다. 그래서 최대한 많은 부서의 물품을 구매해 줄 수 있도록 하려고 합니다.</p>
<p>물품을 구매해 줄 때는 각 부서가 신청한 금액만큼을 모두 지원해 줘야 합니다. 예를 들어 1,000원을 신청한 부서에는 정확히 1,000원을 지원해야 하며, 1,000원보다 적은 금액을 지원해 줄 수는 없습니다.</p>
<p>부서별로 신청한 금액이 들어있는 배열 d와 예산 budget이 매개변수로 주어질 때, 최대 몇 개의 부서에 물품을 지원할 수 있는지 return 하도록 solution 함수를 완성해주세요.</p>
<h2 id="정답-코드">정답 코드</h2>
<pre><code class="language-js">function solution(d, budget) {
  d.sort((a, b) =&gt; a - b);
  let rest = budget;
  let cnt = 0;
  for (let i = 0; i &lt; d.length; i++) {
    if (rest &lt; d[i]) break;
    rest = rest - d[i];
    cnt++;
  }
  return cnt;
}

// d = [1,3,2,5,4]  budget = 9   result = 3</code></pre>
<h2 id="해설">해설</h2>
<ol>
<li>최대한 많은 부서에 지원해야 하므로 d를 오름차순으로 정렬한다.</li>
<li>오름차순으로 정렬한 d를 첫 번째 인덱스부터 순서대로 rest와 비교한다.</li>
<li>rest가 더 크다면 rest 에서 d[i]를 빼고 cnt를 1 증가시킨다.</li>
<li>rest와 비교하여 d[i]가 더 크다면 반복문을 종료한다.</li>
<li>cnt 반환</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Vue v-model]]></title>
            <link>https://velog.io/@lu_6/Vue-v-model</link>
            <guid>https://velog.io/@lu_6/Vue-v-model</guid>
            <pubDate>Fri, 03 Jan 2025 07:13:02 GMT</pubDate>
            <description><![CDATA[<h1 id="v-model">v-model</h1>
<p>양방향 데이터 바인딩을 처리하는 디렉티브입니다.</p>
<h2 id="v-model로-폼-요소-제어하기">v-model로 폼 요소 제어하기</h2>
<h3 id="input">input</h3>
<pre><code>&lt;script&gt;
export default {
  data() {
    return {
      userId: &quot;test&quot;,
    };
  },
};
&lt;/script&gt;

&lt;template&gt;
  &lt;div&gt;
    &lt;label&gt;ID&lt;/label&gt;
    &lt;input type=&quot;text&quot; v-model=&quot;userId&quot; /&gt;
  &lt;/div&gt;
&lt;/template&gt;
</code></pre><h3 id="textarea">textarea</h3>
<pre><code>&lt;script&gt;
export default {
  data() {
    return {
      directiveName: &quot;v-model&quot;,
      str: &quot;여러 줄 바꿈\n텍스트에어리어&quot;,
    };
  },
};
&lt;/script&gt;

&lt;template&gt;
  &lt;div&gt;
    &lt;h1&gt;{{ directiveName }}&lt;/h1&gt;
    &lt;textarea v-model=&quot;str&quot; /&gt;
  &lt;/div&gt;
&lt;/template&gt;
</code></pre><h3 id="select">select</h3>
<pre><code>&lt;script&gt;
export default {
  data() {
    return {
      food: &quot;바나나&quot;,
    };
  },
};
&lt;/script&gt;

&lt;template&gt;
  &lt;div&gt;
    &lt;label&gt;ID&lt;/label&gt;
    &lt;select v-model=&quot;food&quot;&gt;
      &lt;option value=&quot;사과&quot;&gt;사과&lt;/option&gt;
      &lt;option value=&quot;바나나&quot;&gt;바나나&lt;/option&gt;
      &lt;option value=&quot;멜론&quot;&gt;멜론&lt;/option&gt;
    &lt;/select&gt;
  &lt;/div&gt;
&lt;/template&gt;
</code></pre><h3 id="checkbox">checkbox</h3>
<pre><code>&lt;script&gt;
export default {
  data() {
    return {
      checked: true,
    };
  },
};
&lt;/script&gt;

&lt;template&gt;
  &lt;div&gt;
    &lt;input type=&quot;checkbox&quot; v-model=&quot;checked&quot; /&gt;
  &lt;/div&gt;
&lt;/template&gt;
</code></pre><p>checkbox는 체크가 되었을 때의 값과 안되었을때의 값을 따로 지정할 수도 있습니다.</p>
<pre><code>&lt;script&gt;
export default {
  data() {
    return {
      checked: &quot;참&quot;,
    };
  },
};
&lt;/script&gt;

&lt;template&gt;
  &lt;div&gt;
    &lt;input
      type=&quot;checkbox&quot;
      v-model=&quot;checked&quot;
      true-value=&quot;참&quot;
      false-value=&quot;거짓&quot;
    /&gt;
    {{ checked }}
  &lt;/div&gt;
&lt;/template&gt;
</code></pre><p>여러개의 checkbox</p>
<pre><code>&lt;script&gt;
export default {
  data() {
    return {
      checked: [],
    };
  },
};
&lt;/script&gt;

&lt;template&gt;
  &lt;div&gt;
    &lt;label
      &gt;&lt;input type=&quot;checkbox&quot; v-model=&quot;checked&quot; value=&quot;사과&quot; /&gt; 사과
    &lt;/label&gt;
    &lt;label
      &gt;&lt;input type=&quot;checkbox&quot; v-model=&quot;checked&quot; value=&quot;바나나&quot; /&gt;바나나&lt;/label
    &gt;
    &lt;label&gt;&lt;input type=&quot;checkbox&quot; v-model=&quot;checked&quot; value=&quot;멜론&quot; /&gt;멜론&lt;/label&gt;
    &lt;p&gt;{{ checked }}&lt;/p&gt;
  &lt;/div&gt;
&lt;/template&gt;
</code></pre><h3 id="radio">radio</h3>
<pre><code>&lt;script&gt;
export default {
  data() {
    return {
      checked: &quot;&quot;,
    };
  },
};
&lt;/script&gt;


&lt;template&gt;
  &lt;div&gt;
    &lt;label&gt;&lt;input type=&quot;radio&quot; v-model=&quot;checked&quot; value=&quot;사과&quot; /&gt; 사과 &lt;/label&gt;
    &lt;label&gt;&lt;input type=&quot;radio&quot; v-model=&quot;checked&quot; value=&quot;바나나&quot; /&gt;바나나&lt;/label&gt;
    &lt;label&gt;&lt;input type=&quot;radio&quot; v-model=&quot;checked&quot; value=&quot;멜론&quot; /&gt;멜론&lt;/label&gt;
    &lt;p&gt;{{ checked }}&lt;/p&gt;
  &lt;/div&gt;
&lt;/template&gt;
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Vue 스타일]]></title>
            <link>https://velog.io/@lu_6/Vue-%EC%8A%A4%ED%83%80%EC%9D%BC</link>
            <guid>https://velog.io/@lu_6/Vue-%EC%8A%A4%ED%83%80%EC%9D%BC</guid>
            <pubDate>Fri, 03 Jan 2025 05:48:16 GMT</pubDate>
            <description><![CDATA[<p>Vue에서 스타일을 사용하는 방법</p>
<h2 id="1-기본-sfc에서-사용">1. 기본 SFC에서 사용</h2>
<p>Scoped: 스타일이 현재 컴포넌트에서만 적용됩니다.</p>
<pre><code>&lt;style scoped&gt;
.example {
  color: red;
}
&lt;/style&gt;</code></pre><h2 id="2-style-태그에서-파일-import">2. Style 태그에서 파일 Import</h2>
<p>스타일 파일을 style 태그 내에서 import 할 수 있으며, 이 import도 scoped에 영향을 받습니다.</p>
<pre><code>&lt;style scoped&gt;
@import &#39;./styles.css&#39;; /* 해당 스타일이 scoped 내에서만 적용 */
&lt;/style&gt;</code></pre><h2 id="3-main에서-import-전역으로">3. Main에서 Import (전역으로)</h2>
<p>main.js에서 스타일을 import하면 전역으로 적용됩니다.</p>
<h2 id="4-인라인-스타일">4. 인라인 스타일</h2>
<p>스타일 속성에 직접 값을 입력합니다.</p>
<pre><code>&lt;template&gt;
  &lt;div :style=&quot;{ color: textColor }&quot;&gt;Hello&lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  data() {
    return {
      textColor: &#39;red&#39;
    };
  }
};
&lt;/script&gt;</code></pre><p>v-bind를 사용한 스타일: v-bind로 스타일을 바인딩할 때는 카멜 케이스를 사용합니다.</p>
<pre><code>&lt;template&gt;
  &lt;div :style=&quot;{ backgroundColor: backgroundColor, fontSize: fontSize }&quot;&gt;Hello&lt;/div&gt;
&lt;/template&gt;</code></pre><p>배열 스타일 바인딩: 여러 스타일 객체를 배열로 묶어 바인딩할 수 있습니다.</p>
<pre><code>&lt;template&gt;
  &lt;div :style=&quot;[styleObject1, styleObject2]&quot;&gt;Hello&lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  data() {
    return {
      styleObject1: { color: &#39;blue&#39; },
      styleObject2: { fontSize: &#39;20px&#39; }
    };
  }
};
&lt;/script&gt;</code></pre><h2 id="5-클래스-바인딩">5. 클래스 바인딩</h2>
<p>v-bind:class를 사용하여 동적으로 클래스 이름을 바인딩할 수 있습니다.</p>
<pre><code>&lt;template&gt;
  &lt;div :class=&quot;{ active: isActive, &#39;text-red&#39;: isRed }&quot;&gt;Hello&lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  data() {
    return {
      isActive: true,
      isRed: false
    };
  }
};
&lt;/script&gt;</code></pre><p>CSS 프레임워크와 Styled Componets를 이용해서 스타일할 수 있습니다.</p>
<h2 id="6-tailwind-css-bootstrapvue">6. Tailwind CSS, BootstrapVue</h2>
<h2 id="7-vue-styled-components">7. Vue Styled Components</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[Vue 옵션 API, Vue 문법]]></title>
            <link>https://velog.io/@lu_6/Vue-%EC%98%B5%EC%85%98-API-Vue-%EB%AC%B8%EB%B2%95</link>
            <guid>https://velog.io/@lu_6/Vue-%EC%98%B5%EC%85%98-API-Vue-%EB%AC%B8%EB%B2%95</guid>
            <pubDate>Thu, 02 Jan 2025 08:17:59 GMT</pubDate>
            <description><![CDATA[<h2 id="sfc">SFC</h2>
<p>Vue의 SFC(Single File Component)는 Vue의 독자적인 구성 방식으로, HTML, JavaScript, CSS를 한 파일 안에서 작성하는 시스템입니다.</p>
<pre><code class="language-vue">&lt;template&gt;
  &lt;!-- Vue 컴포넌트의 HTML 구조 --&gt;
  &lt;div class=&quot;app&quot;&gt;
    &lt;h1&gt;{{ title }}&lt;/h1&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  name: &quot;App&quot;,
  data() {
    return {
      title: &quot;Vue SFC 기본 구조&quot;,
    };
  },
};
&lt;/script&gt;

&lt;style&gt;
/* Vue 컴포넌트의 스타일 */
.app {
  text-align: center;
  color: #42b983;
}
&lt;/style&gt;</code></pre>
<ul>
<li>template
Vue 컴포넌트의 HTML 구조를 정의합니다.
반드시 한 개의 최상위 루트 요소가 있어야 합니다.</li>
<li>script
Vue의 로직과 데이터, 메서드 등을 정의합니다.
기본적으로 export default를 사용하며, Vue 컴포넌트로 내보냅니다.</li>
<li>style
Vue 컴포넌트의 CSS를 정의합니다.
scoped 속성을 추가하면 해당 컴포넌트의 스타일에만 적용됩니다.</li>
</ul>
<h2 id="옵션-apioptions-api">옵션 API(Options API)</h2>
<p>옵션 API는 data, methods, computed, watch, props, components, emits 등 다양한 옵션을 통해 컴포넌트를 구성하는 방식입니다.
옵션 API의 핵심은 컴포넌트의 설정을 객체 형식으로 정의하는 것입니다.
이 방식은 코드가 명확하고 이해하기 쉽지만, 상태 관리가 복잡해지면 코드가 다소 길어질 수 있습니다.
그러나 Vue 3에서 제공하는 Composition API와 비교할 때, 옵션 API는 더 직관적이고 학습 곡선이 낮습니다.</p>
<h2 id="vue-필수-문법">Vue 필수 문법</h2>
<h3 id="1-데이터-정의하기">1. 데이터 정의하기</h3>
<p>data 속성은 컴포넌트의 상태를 정의하는 객체입니다. 이 객체의 프로퍼티는 컴포넌트에서 사용할 수 있는 데이터가 됩니다.</p>
<pre><code>const app = Vue.createApp({
  data() {
    return {
      message: &#39;Hello, Vue!&#39;,
      count: 0
    };
  }
});
</code></pre><h3 id="2-데이터-보간">2. 데이터 보간</h3>
<p>데이터 보간은 템플릿에서 데이터를 표시하는 방법입니다. 중괄호({{ }})를 사용하여 데이터를 출력할 수 있습니다.</p>
<pre><code>&lt;div id=&quot;app&quot;&gt;
  &lt;h1&gt;{{ message }}&lt;/h1&gt;
  &lt;p&gt;Count: {{ count }}&lt;/p&gt;
  &lt;button @click=&quot;count++&quot;&gt;Increase Count&lt;/button&gt;
&lt;/div&gt;</code></pre><h3 id="3-디렉티브">3. 디렉티브</h3>
<h4 id="v-html-v-text">v-html, v-text</h4>
<p>HTML, 텍스트를 안전하게 출력합니다.</p>
<pre><code>data() {
  return {
    htmlContent: &#39;&lt;strong&gt;This is bold text&lt;/strong&gt;&#39;
    rawText: &#39;&lt;h1&gt;This will not be rendered&lt;/h1&gt;&#39;
  };
}


&lt;div v-html=&quot;htmlContent&quot;&gt;&lt;/div&gt;
&lt;div v-text=&quot;message&quot;&gt;&lt;/div&gt;
</code></pre><h4 id="v-pre">v-pre</h4>
<p>내용을 출력하기 전에 컴파일하지 않도록 합니다.</p>
<pre><code>data() {
  return {
    rawText: &#39;&lt;h1&gt;This will not be rendered&lt;/h1&gt;&#39;
  };
}

&lt;pre v-pre&gt;{{ rawText }}&lt;/pre&gt;
</code></pre><h4 id="v-bind">v-bind</h4>
<p>HTML 속성에 데이터를 바인딩합니다.</p>
<pre><code>data() {
  return {
    imageSrc: &#39;path/to/image.jpg&#39;
  };
}

&lt;img v-bind:src=&quot;imageSrc&quot; alt=&quot;Dynamic Image&quot;&gt;
&lt;--축약 가능--&gt;
&lt;img :src=&quot;imageSrc&quot; alt=&quot;Dynamic Image&quot;&gt;
&lt;-- 속성과 변수 이름이 같을 경우 --&gt;
&lt;img :src alt=&quot;Dynamic Image&quot;&gt;</code></pre><h4 id="5-v-if-v-else-if-v-else">5. v-if, v-else-if, v-else</h4>
<p>조건에 따라 요소를 렌더링합니다.</p>
<pre><code>&lt;div v-if=&quot;count &gt; 0&quot;&gt;Count is positive&lt;/div&gt;
&lt;div v-else-if=&quot;count &lt; 0&quot;&gt;Count is negative&lt;/div&gt;
&lt;div v-else&gt;Count is zero&lt;/div&gt;</code></pre><h4 id="6-v-show">6. v-show</h4>
<p>조건에 따라 요소의 표시 여부를 결정합니다. (CSS display 속성 사용)</p>
<pre><code>data() {
  return {
    isVisible: true
  };
}

&lt;div v-show=&quot;isVisible&quot;&gt;This is visible&lt;/div&gt;</code></pre><h4 id="7-v-cloak">7. v-cloak</h4>
<p>Vue가 컴파일될 때까지 해당 요소를 숨깁니다.</p>
<pre><code>&lt;div v-cloak&gt;{{ message }}&lt;/div&gt;

&lt;style&gt;
[v-cloak] { display: none; }
&lt;/style&gt;
</code></pre><h4 id="8-v-for">8. v-for</h4>
<p>리스트를 반복하여 렌더링합니다.</p>
<pre><code>data() {
  return {
    items: [
      { id: 1, name: &#39;Item 1&#39; },
      { id: 2, name: &#39;Item 2&#39; },
      { id: 3, name: &#39;Item 3&#39; }
    ]
  };
}

&lt;ul&gt;
  &lt;li v-for=&quot;item in items&quot; :key=&quot;item.id&quot;&gt;{{ item.name }}&lt;/li&gt;
&lt;/ul&gt;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Vue 시작하기]]></title>
            <link>https://velog.io/@lu_6/Vue-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@lu_6/Vue-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 24 Dec 2024 07:33:35 GMT</pubDate>
            <description><![CDATA[<h1 id="vue-시작하기">Vue 시작하기</h1>
<p>뷰는 사용자 인터페이스(UI, User Interface)를 만드는 데 사용하는 자바스크립트 기반 오픈소스
<strong>프로그레시브</strong> 프레임워크입니다.
<strong>프로그레시브 프레임워크</strong>란 이미 다른 사양으로 개발된 웹 애플리케이션에서 일부분만 ‘점진적으로(progressive)’ 적용할 수 있도록 모듈화하고 유연한 구조를 갖춘 프레임워크를 의미합니다</p>
<p>Vue는 주로 웹페이지를 쉽고 빠르게 제작하기 위해 사용합니다.</p>
<h2 id="mvvm">MVVM</h2>
<p>뷰는 MVVM 아키텍처 패턴을 따릅니다.
MVVM 아키텍처 패턴은 데이터를 보여주는 뷰(view) 영역과 데이터를 처리하는 모델(model) 사
이에 데이터를 중개하는 뷰 모델(view model) 계층을 두어 UI와 데이터 처리 로직의 상호 의존
성을 줄이는 아키텍처 패턴을 말합니다. 
<img src="https://velog.velcdn.com/images/lu_6/post/32572cc7-d28d-434b-bd03-11c5b6c46205/image.png" alt=""></p>
<h2 id="양방향바인딩">양방향바인딩</h2>
<p>뷰는 데이터의 바인딩이 양방향 바인딩입니다.
예를 들어서 리액트에서는 상태를 정의하고, 상태를 이벤트와 연결해서 직접 값을 바꿔야 하는 단방향 바인딩입니다.
뷰는 양방향 바인딩이기 때문에 생성한 데이터를 연결해주기만 하면 끝입니다.</p>
<pre><code>&lt;div id=&quot;app&quot;&gt;
  &lt;input v-model=&quot;message&quot; placeholder=&quot;Type something&quot;&gt;
  &lt;p&gt;The message is: {{ message }}&lt;/p&gt;
&lt;/div&gt;

&lt;script&gt;
  new Vue({
    el: &#39;#app&#39;,
    data: {
      message: &#39;&#39;
    }
  });
&lt;/script&gt; </code></pre><h2 id="필수-익스텐션">필수 익스텐션</h2>
<p>일반적으로 vue 확장자 파일은 비주얼 스튜디오 코드가 인식하지 못합니다. 그래서 아래와 같은 익스텐션을 필수로 설치해야 합니다.</p>
<p><img src="https://velog.velcdn.com/images/lu_6/post/632db54d-ec3f-4100-b532-d38101bf8a9b/image.png" alt=""></p>
<h2 id="vue-애플리케이션-만들기">Vue 애플리케이션 만들기</h2>
<h3 id="cdn으로-설치하기">CDN으로 설치하기</h3>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot; /&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;
    &lt;title&gt;Document&lt;/title&gt;
    &lt;script src=&quot;https://unpkg.com/vue@3/dist/vue.global.js&quot;&gt;&lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div id=&quot;app&quot;&gt;
      &lt;h1&gt;{{ message }}&lt;/h1&gt;
      &lt;h1&gt;{{count}}&lt;/h1&gt;
      &lt;button @click=&quot;increment&quot;&gt;증가&lt;/button&gt;
    &lt;/div&gt;
    &lt;script&gt;
      const { createApp } = Vue;
      createApp({
        data() {
          return {
            message: &quot;Hello, World&quot;,
            count: 0,
          };
        },
        methods: {
          increment() {
            this.count += 1;
          },
        },
      }).mount(&quot;#app&quot;);
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre><h3 id="vite로-설치하기">vite로 설치하기</h3>
<pre><code>npm create vite@latest .
</code></pre><h3 id="vue로-설치하기-공식-홈페이지-권장">Vue로 설치하기 (공식 홈페이지 권장)</h3>
<pre><code>npm create vue@latest .

✔ Package name: … vues
✔ Add TypeScript? … No / Yes
✔ Add JSX Support? … No / Yes
✔ Add Vue Router for Single Page Application development? … No / Yes
✔ Add Pinia for state management? … No / Yes
✔ Add Vitest for Unit Testing? … No / Yes
✔ Add an End-to-End Testing Solution? › No
✔ Add ESLint for code quality? › No
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[React React-Router]]></title>
            <link>https://velog.io/@lu_6/React-React-Router</link>
            <guid>https://velog.io/@lu_6/React-React-Router</guid>
            <pubDate>Thu, 05 Dec 2024 05:48:25 GMT</pubDate>
            <description><![CDATA[<h1 id="react-router">React Router</h1>
<p>React Router는 React 애플리케이션에서 클라이언트 측 라우팅을 구현하기 위한 라이브러리입니다.
이를 통해 URL을 기반으로 화면을 렌더링하고, SPA(Single Page Application)에서 라우트 간 전환을 부드럽게 처리할 수 있습니다.</p>
<p>React Router는 라우팅을 설정하는 BrowserRouter 컴포넌트와 Route, Link 등의 컴포넌트를 활용합니다.</p>
<pre><code class="language-tsx">//main.tsx
import { StrictMode } from &quot;react&quot;;
import { createRoot } from &quot;react-dom/client&quot;;
import App from &quot;./App.tsx&quot;;
import &quot;./css/index.css&quot;;
import { BrowserRouter } from &quot;react-router&quot;;

createRoot(document.getElementById(&quot;root&quot;)!).render(
  &lt;StrictMode&gt;
    &lt;BrowserRouter&gt;
      &lt;App /&gt;
    &lt;/BrowserRouter&gt;
  &lt;/StrictMode&gt;
);
</code></pre>
<pre><code class="language-tsx">//App.tsx
import React from &quot;react&quot;;
import { Routes, Route } from &quot;react-router-dom&quot;;

function App() {
  return (
      &lt;Routes&gt;
        &lt;Route path=&quot;/&quot; element={&lt;Home /&gt;} /&gt;
        &lt;Route path=&quot;/about&quot; element={&lt;About /&gt;} /&gt;
        &lt;Route path=&quot;/contact&quot; element={&lt;Contact /&gt;} /&gt;
      &lt;/Routes&gt;
  );
}
export default App;
</code></pre>
<h2 id="중첩-라우팅">중첩 라우팅</h2>
<p>부모 라우트는 자동으로 자식 라우트에 포함됩니다.
<code>/dashboard</code> <code>/dashboard/settings</code> 로 접근할 수 있습니다.</p>
<pre><code class="language-tsx">&lt;Routes&gt;
  &lt;Route path=&quot;dashboard&quot; element={&lt;Dashboard /&gt;}&gt;
    &lt;Route index element={&lt;Home /&gt;} /&gt;
    &lt;Route path=&quot;settings&quot; element={&lt;Settings /&gt;} /&gt;
  &lt;/Route&gt;
&lt;/Routes&gt;</code></pre>
<p>Outlet을 사용하여 부모 라우트에서 자식 라우트를 렌더링할 수 있습니다.</p>
<pre><code class="language-tsx">import { Outlet } from &quot;react-router&quot;;

export default function Dashboard() {
  return (
    &lt;div&gt;
      &lt;h1&gt;Dashboard&lt;/h1&gt;
      &lt;Outlet /&gt;
    &lt;/div&gt;
  );
}</code></pre>
<h2 id="레이아웃-라우팅">레이아웃 라우팅</h2>
<p>공통 레이아웃을 가지는 라우트를 그룹화하여 관리합니다.
path를 작성하지 않으면 URL에 segment가 추가되지 않습니다.
<code>/</code> <code>/contact</code>  <code>/projects</code> <code>/projects/123</code> <code>/projects/123/edit</code></p>
<pre><code class="language-tsx">&lt;Routes&gt;
  &lt;Route element={&lt;MarketingLayout /&gt;}&gt;
    &lt;Route index element={&lt;MarketingHome /&gt;} /&gt;
    &lt;Route path=&quot;contact&quot; element={&lt;Contact /&gt;} /&gt;
  &lt;/Route&gt;

  &lt;Route path=&quot;projects&quot;&gt;
    &lt;Route index element={&lt;ProjectsHome /&gt;} /&gt;
    &lt;Route element={&lt;ProjectsLayout /&gt;}&gt;
      &lt;Route path=&quot;:pid&quot; element={&lt;Project /&gt;} /&gt;
      &lt;Route path=&quot;:pid/edit&quot; element={&lt;EditProject /&gt;} /&gt;
    &lt;/Route&gt;
  &lt;/Route&gt;
&lt;/Routes&gt;</code></pre>
<h2 id="index">Index</h2>
<p>부모의 기본 경로(path=&quot;/&quot;)에서 렌더링되는 기본 자식 라우트입니다. index 속성을 사용합니다.</p>
<pre><code class="language-tsx">&lt;Routes&gt;
  &lt;Route path=&quot;/&quot; element={&lt;MainLayout /&gt;}&gt;
    &lt;Route index element={&lt;Home /&gt;} /&gt; {/* 기본 페이지 */}
    &lt;Route path=&quot;about&quot; element={&lt;About /&gt;} /&gt;
  &lt;/Route&gt;
&lt;/Routes&gt;</code></pre>
<h2 id="route-prefixes">Route Prefixes</h2>
<p>element 속성을 작성하지 않으면 레이아웃을 추가하지 않고 segment를 추가합니다.</p>
<pre><code class="language-tsx">&lt;Routes&gt;
  &lt;Route path=&quot;/dashboard&quot; &gt;
    &lt;Route path=&quot;settings&quot; element={&lt;Settings /&gt;} /&gt;
    &lt;Route path=&quot;profile&quot; element={&lt;Profile /&gt;} /&gt;
  &lt;/Route&gt;
&lt;/Routes&gt;</code></pre>
<h2 id="dynamic-segments">Dynamic Segments</h2>
<p>경로에 동적으로 변경 가능한 변수를 사용합니다.
<code>/users/123</code></p>
<pre><code class="language-tsx">&lt;Routes&gt;
  &lt;Route path=&quot;/users/:userId&quot; element={&lt;UserProfile /&gt;} /&gt;
&lt;/Routes&gt;</code></pre>
<h2 id="splats">Splats</h2>
<p>경로의 나머지 모든 부분을 지정합니다.</p>
<pre><code class="language-tsx">&lt;Routes&gt;
  &lt;Route path=&quot;/files/*&quot; element={&lt;FileViewer /&gt;} /&gt;
&lt;/Routes&gt;</code></pre>
<h2 id="linking">Linking</h2>
<p>Link와 NavLink를 사용하여 페이지 간 이동이 가능합니다.
NavLink는 현재 활성화 된 경로에 특정 클래스나 스타일을 추가할 수 있습니다.</p>
<pre><code class="language-tsx">&lt;NavLink
  to=&quot;/&quot;
  className={({ isActive }) =&gt;
    isActive ? &quot;active&quot; : &quot;&quot;
  }
&gt;
  Home
&lt;/NavLink&gt;

&lt;Link to=&quot;/concerts/salt-lake-city&quot;&gt;Concerts&lt;/Link&gt;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[React 데이터 통신]]></title>
            <link>https://velog.io/@lu_6/React-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%86%B5%EC%8B%A0</link>
            <guid>https://velog.io/@lu_6/React-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%86%B5%EC%8B%A0</guid>
            <pubDate>Wed, 04 Dec 2024 15:26:39 GMT</pubDate>
            <description><![CDATA[<h1 id="데이터-통신">데이터 통신</h1>
<p>리액트에서 데이터 통신을 할 때는 axios 라이브러리나 fetch API를 사용하여 처리합니다.
여러가지 편의 기능은 axios 라이브러리가 더 뛰어나지만, 별도의 라이브러리를 설치해서 사용해야 한다는 단점이 있습니다.</p>
<h2 id="fetch-api-get">Fetch API GET</h2>
<p>Fetch API는 브라우저 내장 HTTP 요청 라이브러리로, 최신 웹 표준입니다.</p>
<pre><code class="language-tsx">import { useEffect, useState } from &#39;react&#39;;

export default function Fetch1() {
  const [posts, setPosts] = useState([]);
  useEffect(() =&gt; {
    fetch(&#39;http://localhost:3001/posts&#39;)
      .then((res) =&gt; {
        if (!res.ok) {
          throw Error(&#39;Could not fetch the data for that resource&#39;);
        }
        return res.json();
      })
      .then((data) =&gt; {
        setPosts(data);
      });
  }, []);
  return &lt;pre&gt;{JSON.stringify(posts, null, 2)}&lt;/pre&gt;;
}</code></pre>
<h3 id="fetch-api-post-put-patch-delete">Fetch API Post, Put, Patch, Delete</h3>
<pre><code class="language-tsx">export default function FetchCURD() {

  const postHandler = async () =&gt; {
    try {
      const res = await fetch(&#39;http://localhost:3001/posts&#39;, {
        method: &#39;POST&#39;,
        headers: {
          &#39;Content-Type&#39;: &#39;application/json&#39;,
        },
        body: JSON.stringify({ id: &#39;3&#39;, title: &#39;a title&#39;, views: 100 }),
      });

      if (!res.ok) {
        throw new Error(&#39;Failed to post&#39;);
      }

      const data = await res.json();
      console.log(data);
    } catch (e) {
      console.log(e);
    }
  };


  const deleteHandler = async () =&gt; {
    try {
      const res = await fetch(&#39;http://localhost:3001/posts/3&#39;, {
        method: &#39;DELETE&#39;,
      });

      if (!res.ok) {
        throw new Error(&#39;Failed to delete&#39;);
      }

      const data = await res.json();
      console.log(data);
    } catch (e) {
      console.log(e);
    }
  };


  const putHandler = async () =&gt; {
    try {
      const res = await fetch(&#39;http://localhost:3001/posts/1&#39;, {
        method: &#39;PUT&#39;,
        headers: {
          &#39;Content-Type&#39;: &#39;application/json&#39;,
        },
        body: JSON.stringify({ title: &#39;a new title&#39;, views: 200 }),
      });

      if (!res.ok) {
        throw new Error(&#39;Failed to put&#39;);
      }

      const data = await res.json();
      console.log(data);
    } catch (e) {
      console.log(e);
    }
  };


  const patchHandler = async () =&gt; {
    try {
      const res = await fetch(&#39;http://localhost:3001/posts/1&#39;, {
        method: &#39;PATCH&#39;,
        headers: {
          &#39;Content-Type&#39;: &#39;application/json&#39;,
        },
        body: JSON.stringify({ title: &#39;a patch title&#39; }),
      });

      if (!res.ok) {
        throw new Error(&#39;Failed to patch&#39;);
      }

      const data = await res.json();
      console.log(data);
    } catch (e) {
      console.log(e);
    }
  };
  return (
    &lt;&gt;
      &lt;button onClick={postHandler}&gt;POST&lt;/button&gt;
      &lt;button onClick={deleteHandler}&gt;DELETE&lt;/button&gt;
      &lt;button onClick={putHandler}&gt;PUT&lt;/button&gt;
      &lt;button onClick={patchHandler}&gt;PATCH&lt;/button&gt;
    &lt;/&gt;
  );
}</code></pre>
<h2 id="axios">Axios</h2>
<p>Axios는 HTTP 요청을 처리하기 위한 서드파티 라이브러리입니다.
요청과 응답 데이터를 자동 변환합니다.</p>
<pre><code class="language-tsx">import axios from &#39;axios&#39;;
import { useEffect, useState } from &#39;react&#39;;

export default function Axios1() {
  const [posts, setPosts] = useState([]);
  useEffect(() =&gt; {
    axios
      .get(&#39;http://localhost:3001/posts&#39;)
      .then(({ status, statusText, data }) =&gt; {
        console.log(status, statusText, data);
        setPosts(data);
      });
  }, []);

  return &lt;pre&gt;{JSON.stringify(posts, null, 2)}&lt;/pre&gt;;
}</code></pre>
<h3 id="axios-post-put-patch-delete">Axios Post, Put, Patch, Delete</h3>
<pre><code class="language-tsx">import axios from &#39;axios&#39;;

export default function AxiosCRUD() {
  const postHandler = async () =&gt; {
    try {
      const res = await axios.post(&#39;http://localhost:3001/posts&#39;, {
        id: &#39;3&#39;,
        title: &#39;a title&#39;,
        views: 100,
      });

      console.log(res.data);
    } catch (e) {
      console.log(e);
    }
  };

  const deleteHandler = async () =&gt; {
    try {
      const res = await axios.delete(&#39;http://localhost:3001/posts/3&#39;);
      console.log(res.data);
    } catch (e) {
      console.log(e);
    }
  };

  const putHandler = async () =&gt; {
    try {
      const res = await axios.put(&#39;http://localhost:3001/posts/1&#39;, {
        title: &#39;a new title&#39;,
        views: 500,
      });

      console.log(res.data);
    } catch (e) {
      console.log(e);
    }
  };

  const patchHandler = async () =&gt; {
    try {
      const res = await axios.patch(&#39;http://localhost:3001/posts/1&#39;, {
        title: &#39;a patch title&#39;,
      });

      console.log(res.data);
    } catch (e) {
      console.log(e);
    }
  };

  return (
    &lt;&gt;
      &lt;button onClick={postHandler}&gt;POST&lt;/button&gt;
      &lt;button onClick={deleteHandler}&gt;DELETE&lt;/button&gt;
      &lt;button onClick={putHandler}&gt;PUT&lt;/button&gt;
      &lt;button onClick={patchHandler}&gt;PATCH&lt;/button&gt;
    &lt;/&gt;
  );
}</code></pre>
<h3 id="axioscreate">axios.create</h3>
<p>axios.create() 메서드를 사용하여 기본 구성 옵션을 설정하고 재사용 가능한 Axios 인스턴스를 만드는 방법입니다.
이를 사용하면 여러 컴포넌트나 파일에서 HTTP 요청을 효율적으로 관리할 수 있습니다.</p>
<pre><code class="language-tsx">import axios from &quot;axios&quot;;

export const axiosInstance = axios.create({
  baseURL: `https://api.themoviedb.org/3/movie`,
  headers: {
    Authorization:
      &quot;Bearer eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiI3Nzk1Y2EwNDE0MTE0NzM3MGNmZmFkZjFjOTc2ZWRkNCIsIm5iZiI6MTczMzI5MTIzOS44Miwic3ViIjoiNjc0ZmVjZTc0NDg0N2U5N2RmZjQwM2YwIiwic2NvcGVzIjpbImFwaV9yZWFkIl0sInZlcnNpb24iOjF9.DjLrcmHH_hv2Y9c_Qj_N3lqwNNLcxsv5yThiGFgkARQ&quot;,
  },
});

export const getNowPlaying = async () =&gt; {
  try {
    const { data } = await axiosInstance.get(
      `/now_playing?language=en-US&amp;page=1`
    );
    return data;
  } catch (error) {
    throw new Error(&quot;API 호출을 실패했습니다.&quot;);
  }
};

export const getUpcoming = async () =&gt; {
  try {
    const { data } = await axiosInstance.get(
      `/upcoming?language=en-US&amp;page=1`
    );
    return data;
  } catch (error) {
    throw new Error(&quot;API 호출을 실패했습니다.&quot;);
  }
};

export const getTopRated = async () =&gt; {
  try {
    const { data } = await axiosInstance.get(
      `/top_rated?language=en-US&amp;page=1`
    );
    return data;
  } catch (error) {
    throw new Error(&quot;API 호출을 실패했습니다.&quot;);
  }
};
</code></pre>
]]></description>
        </item>
    </channel>
</rss>