<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>violet_yang.log</title>
        <link>https://velog.io/</link>
        <description>violet's development note</description>
        <lastBuildDate>Wed, 28 May 2025 08:27:54 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>violet_yang.log</title>
            <url>https://velog.velcdn.com/images/violet_yang/profile/1c6e0e1f-ba99-4d50-a27d-cb785c36756a/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. violet_yang.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/violet_yang" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[TIL] env 환경변수 설정]]></title>
            <link>https://velog.io/@violet_yang/TIL-env-%ED%99%98%EA%B2%BD%EB%B3%80%EC%88%98-%EC%84%A4%EC%A0%95</link>
            <guid>https://velog.io/@violet_yang/TIL-env-%ED%99%98%EA%B2%BD%EB%B3%80%EC%88%98-%EC%84%A4%EC%A0%95</guid>
            <pubDate>Wed, 28 May 2025 08:27:54 GMT</pubDate>
            <description><![CDATA[<h4 id="오늘-발생한-이슈는-local-환경에서-정상-호출-하지만-개발계에서-계속-비정상적인-api주소가-매핑되며-405-에러를-return-했다">오늘 발생한 이슈는 local 환경에서 정상 호출, 하지만 개발계에서 계속 비정상적인 API주소가 매핑되며 405 에러를 return 했다.</h4>
<br>

<p>문제의 원인은 개발계 빌드파일을 관리하는 vercel에 환경변수 세팅이 누락되어 발생했고, 환경변수 세팅을 별도로 세팅해줘야 하는 이유는 .env 파일이 gitignore 리스트에 포함되어 있어서 vercel은 환경변수를 찾지 못한 것이었다. 따라서, 환경변수를 추가한 뒤 Redeploy를 실행시켜 이슈를 해결했다.</p>
<p>하지만, 처음에는 middleware가 endpoint를 제대로 찾지 못해 token 발행이 비정상 작동하는 것으로 의심하고 삽질을 잠깐(?)동안 하다가, 클라이언트 -&gt; 미들웨어 과정에서 발생하는 것 같다는 선임의 피드백을 통해 Network tab을 통해 Request URL이 잘못된 것을 추적할 수 있었다.</p>
<br>

<p>클라이언트에서 오더버튼 클릭 시, 즉 서버에 call할 때 환경변수가 매핑되어야 할 위치에 undefined이 프린팅 되는 것이었고 </p>
<pre><code> const orderUrl = `${process.env.NEXT_PUBLIC_MIDDLEWARE_URL}/on-orders/${branchKey}`</code></pre><p>local 환경에는 존재했던 env 환경변수가 개발계에는 동일하게 매핑이 되지 않았던 것을 확인했다.</p>
<hr>
<p>해결은 간단했지만 의심가는 코드를 바로 찾지 못한 게 아쉬웠고, 
유저의 액션이 발생했을 때의 흐름을 단계적으로 생각하지 않았던 접근이 원인을 바로 알아낼 수 없었던 트리거였다고 생각한다. </p>
<p>삽질을 줄이기 위해선 </p>
<p>1) 액션 발생 후 로직의 흐름을 단계적으로 파악해보고
2) 더 많은 버그를 만나며 경험을 쌓는 수밖에 없을 것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Canada] 중간 점검]]></title>
            <link>https://velog.io/@violet_yang/Canada</link>
            <guid>https://velog.io/@violet_yang/Canada</guid>
            <pubDate>Sat, 07 Dec 2024 22:50:30 GMT</pubDate>
            <description><![CDATA[<p>캐나다에 온 지 1년 5개월이 다 되어간다.
한국생활이 싫어서라기보다는 더 많은 경험을 해보고자 했던 나의 결정이다. 
30이 넘은 나이에 가족, 친구 남자친구도 뒤로 한 채 그렇게 벤쿠버로 왔다.</p>
<p>벤쿠버의 생활은 한국과는 비교할 수 없을만큼 여유롭다.
그리고 한국과는 비교할 수 없을만큼 지루하다고 말할 수도 있다.
왜냐면 여기는 한국처럼 밤문화가 발달하지도 않았고, 직장이 중심이 되는 사회도 아니며,
그 무엇보다도 &#39;family oriented&#39;가 핵심인 문화를 가진 곳이기 때문이다.
30분동안 버스가 안와도 아무도 불평하지 않고, 푹설 후 제설작업이 없어도 잔뜩 쌓인 눈속에서 행복해하며, 미세먼지 없는 하늘을 보고만 있어도 행복해지는 이곳이 재미없고 답답하다며 한국으로 다시 돌아가는 사람들도 많다.</p>
<p>하지만 나는 여기에 와서 생각했다. 
결혼을 한 뒤 아이를 키운다면 무한경쟁과 돈, 성적만이 아이들의 가치를 뒤흔드는 한국이 아니라 이곳에서 양육하고 싶다고.. 물론 이곳에 사는 학생들도 나름의 고충이 있겠지만, 아름다운 자연을 느낄 수 있고 가족들과 행복한 시간을 보내며, 올바른 세계관을 가진 그런 자녀로 키우고 싶다고.
정착하기까지 해야할 것도, 해내야 할일도, 견뎌야 할 상황도 많겠지만 여기까지 인도하신 선하신 그분의 뜻을 믿으며 한걸음 한걸음 나가가는 것. 평안과 기쁨, 감사를 잃지 않는 삶을 지키는 것. 이 또한 내가 할 일이지 않나 싶다.</p>
<p><br><br></p>
<p>지금은 좋은 동료들과 함께 일하는 작은 스타트업에서 일하고 있지만, 취업 전엔 참 힘들었던 거 같다.
왜냐면 북미권 학교를 졸업하지도 않았고 해외경력도 없었으며, 외국인의 신분으로 IT쪽에는 한 사람도 연줄이 존재하지 않았기 때문이다. 프론트엔드 개발자로 일하다가 넘어왔지만 실력에 대한 자신감도 낮았기에 심적으로 부담이 컸던 것 같다.</p>
<p>지금 돌아보니 참 바쁘게 살았던 거 같은데, 개발도 내가 좋아서 시작한 일인데 이런저런 핑계로 미루고 미루다가 이제는 더이상 간과해서는 안되는 시점에 도달해버렸다.
25년을 3주 앞둔 지금, 자나깨나 내 걱정인 엄마, 부족한 실력이지만 잘하고 있다며 응원해주는 동료들, 여전히 나를 믿어주고 도와주는 팔계, 그리고 무엇보다도 연차만큼 내 몫을 해내고 싶은 나의 의지가 마음을 다잡게 한다.</p>
<br>
출신지, 취업시장, 미래의 경쟁자들은 내가 컨트롤 할 수 없지만
실력과 노력, 멘탈은 내 바운더리 안에 있는 요소들이기 때문에 끈기만 있다면 언젠가는 보상을 받게 될 것이다.
기록하고 시도하자.. 내 스스로에게 다짐 하며 글을 마무리 한다.]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 상위 컴포넌트에서 함수 제어하기]]></title>
            <link>https://velog.io/@violet_yang/TIL-%EC%83%81%EC%9C%84-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%97%90%EC%84%9C-%ED%95%A8%EC%88%98-%EC%A0%9C%EC%96%B4%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@violet_yang/TIL-%EC%83%81%EC%9C%84-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%97%90%EC%84%9C-%ED%95%A8%EC%88%98-%EC%A0%9C%EC%96%B4%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 16 Apr 2024 09:07:07 GMT</pubDate>
            <description><![CDATA[<p>리액트 컴포넌트는 상위,하위 모듈 간 데이터 통신을 할 때 Props라는 개념이 존재한다.
Props는 변수, 함수, 컴포넌트가 될 수 있으며 그 중 함수를 전달하고 사용하는 방법을 알아보자.</p>
<pre><code class="language-js">// custom component

import { Option } from &#39;./select.ts&#39; 

type Props = { 
    options : Option[], // options Props는 Option 타입의 배열형태로 데이터를 전달한다.
    onChecked? : Function, // onChecked Props는 Function 타입 데이터를 주고 받는다
    value : string | number // value Props는 string 혹은 number 타입의 데이터를 전달 받는다.
}

export default function JwtSelect({options, onChecked, value} : Props) {

    const handleOnChecked = (currentvalue : any) =&gt; {
        if(onChecked) onChecked(currentvalue)
    }

    return (
        options.map((option : Option) =&gt; 
        &lt;div&gt;
            {option.name}
        &lt;input type=&quot;checkbox&quot; checked={value === option.value} onClick={handleOnChecked(option.value)}/&gt;
        &lt;/div&gt;
        )
 )
}</code></pre>
<br>

<pre><code class="language-js">// layout.tsx
export default function Layout() {

      const [value, setValue] = useState&lt;string | number(0)

    const handleCheck = (currentValue : string | number) =&gt; {    
    setCheckValue(currentValue)
  }

  const testOptions = [
    {name : &#39;나는 나는 저팔계&#39;, value : &#39;왜 나를 싫어하나&#39;},
    {name : &#39;나는 사오정&#39;, value : &#39;나방나온다아아아&#39;} ]
}

return (
    &lt;&gt;
&lt;JwtSelect options={testOptions} value={value} onChecked={handleCheck}/&gt;
    &lt;/&gt;
}</code></pre>
<p>두 개의 컴포넌트가 &#39;layout&#39; &lt;-&gt; &#39;custom component&#39; 통신을 할 때, options의 Props로 데이터를 넘겨주듯, 하위 컴포넌트(custom component)에서 onChecked로 전파된 함수형 props는 상위 컴포넌트(layout)에서 &#39;handleCheck&#39;라는 이름을 가진 함수로 재정의된다.
handleCheck함수로 Props 함수를 재정의하지 않는다면 하위컴포넌트에서 정의만 하고 상위 컴포넌트에서는 아무런 이벤트가 발생하지 않는다. 즉, handleCheck 로 재정의된 함수가 해당 컴포넌트(layout)에서 수행할 동작들을 제어한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] 프로젝트 구동원리]]></title>
            <link>https://velog.io/@violet_yang/TIL-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B5%AC%EB%8F%99%EC%9B%90%EB%A6%AC</link>
            <guid>https://velog.io/@violet_yang/TIL-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B5%AC%EB%8F%99%EC%9B%90%EB%A6%AC</guid>
            <pubDate>Fri, 19 May 2023 10:30:17 GMT</pubDate>
            <description><![CDATA[<h2 id="1--node-in-framework">1 ) Node in Framework</h2>
<p>Node.js란? 자바스크립트를 실행시키는 런타임 환경(특정언어로 만든 프로그램을 실행할 수 있도록 해주는 프로그램- Node.js는 자바의 JRE와 같은 역할 )</p>
<p>자바스크립트는 프로그래밍 언어이기 때문에 컴퓨터가 이것을 해석하기 위해서는 엔진이 필요했다. 인터넷 익스플로러에는 차크라, 파리어폭스에는 스파이더 몽키라는 엔진이 내장되어 있다. 즉, 자바스크립트의 런타임 환경인 브라우저마다 탑재된 엔진이 각각 달랐기 때문에, 동일한 프로그래밍언어(javascript)를 사용해도 브라우저별로 성능이 달랐으며, V8엔진이 탑재된 크롬 브라우저 출시 이후 이전 브라우저와는 눈으로 비교될 만큼 엄청난 성능을 자랑했다.</p>
<p>Node 개발 이전에 자바스크립트는 브라우저에 종속된 언어로써, 자바스크립트 코드를 실행하고 해석하는 인터프리터가 각각의 브라우저에 내장되어 있었기 때문에 브라우저에서만 사용이 가능했다.</p>
<p>하지만, 크롬의 V8엔진이 오픈소스로 공개되었고, 브라우저(크롬)가 없어도 동작이 가능하도록 심지어 자바스크립트로도 서버를 만들 수 있도록 업그레이드 된 것이 Node.js 라는 프로그램이다.</p>
<p>Node.js를 설치하면 NPM(Node Package Manager)이 함께 설치되며, 이 npm을 통해 React, Vue 등과 같은 프레임워크 개발을 위한 모듈을 다운받아 사용할 수 있다.</p>
<BR>

<h2 id="2-packagejson-and-script-statement">2) package.json and script statement</h2>
<p>pakage.json은 개발자가 배포한 pakage(프로젝트)를 관리하기 위한 문서파일로, 모듈의 의존성 파일 리스트와 버전관리가 설정된 곳이다. </p>
<pre><code>{
  &quot;name&quot;: &quot;seo-next&quot;,
  &quot;version&quot;: &quot;0.1.0&quot;,
  &quot;private&quot;: true,
  &quot;scripts&quot;: { // 빌드나 실행에 필요한 명령문
    &quot;dev&quot;: &quot;next dev&quot;,
    &quot;build&quot;: &quot;next build&quot;,
    &quot;start&quot;: &quot;next start&quot;,
    &quot;lint&quot;: &quot;next lint&quot;
  },
  &quot;dependencies&quot;: { // 프로젝트 실행 시 필요한 의존성 모듈
    &quot;@types/node&quot;: &quot;20.1.7&quot;,
    &quot;@types/react&quot;: &quot;18.2.6&quot;,
    &quot;@types/react-dom&quot;: &quot;18.2.4&quot;,
    &quot;eslint&quot;: &quot;8.40.0&quot;,
    &quot;eslint-config-next&quot;: &quot;13.4.2&quot;,
    &quot;next&quot;: &quot;13.4.2&quot;,
    &quot;react&quot;: &quot;18.2.0&quot;,
    &quot;react-dom&quot;: &quot;18.2.0&quot;,
    &quot;typescript&quot;: &quot;5.0.4&quot;
  }
}</code></pre><p>기본적으로는 포르젝트의 이름, 버전, scripts, dependencies로 구성되며, 추가/삭제/수정을 통해 커스톰하게 사용할 수 있다. 그 중 script문의 “dev”와 “bulid” 명령어를 좀 더 자세하게 살펴보자.</p>
<pre><code class="language-json">// yesbee2 admin
&quot;scripts&quot;: {
    &quot;dev&quot;: &quot;env-cmd -f .env next dev&quot;,
    &quot;build-dev&quot;: &quot;env-cmd -f .env.development next build&quot;,
    &quot;build-prod&quot;: &quot;env-cmd -f .env.prod next build&quot;,
    &quot;start&quot;: &quot;next start&quot;,
    &quot;lint&quot;: &quot;next lint&quot;,
    &quot;export-dev&quot;: &quot;npm run build-dev &amp;&amp; next export -o _static&quot;,
    &quot;start-dev&quot;: &quot;pm2 start npm --name &#39;yesbee-admin&#39; -- start -- -p 38082&quot;,
    &quot;stop-dev&quot;: &quot;pm2 stop &#39;yesbee-admin&#39;&quot;,
    &quot;restart&quot;: &quot;pm2 restart &#39;yesbee-admin&#39;&quot;
  },</code></pre>
<ul>
<li>dev(start) - 보통은 둘 중 하나의 명령어 통해 개발 모드로 프로그램을 실행하는 명령어이다. npm run 명령어와 같이 쓰이며, 설정한 스크립트문이 동작하는데 yesbee의 dev는 node명령어 중 하나인 env-cmd가 트리거 되도록 설정되어 있다. 이는 env 파일에 설정한 개발환경을 사용하여 동작하도록  한다.</li>
<li>build - 배포 환경에서 사용할 파일을 만들어주며, 명령어를 수행하면 <code>dist</code>폴더와 폴더 하위에 새로운 파일들이 생성된다. 해당 파일들을 통해 브라우저가 프로그램을 동작시키며, 빌드된 결과는 자바스크립트 인터프리터를 위해 사용된다.</li>
</ul>
<BR>

<h2 id="3-host-domain">3) Host domain</h2>
<p>Azure나 AWS와 같은 플래폼에서 웹앱을 생성하면 IP주소를 부여받게 된다. </p>
<p>이 IP주소는 브라우저의 URL과 같은 역할을 하는데,  50.231.38.87 과 같이 숫자 주소를 매번 외워서 접속할 수 없기 때문에 클라이언트 도메인을 따로 구매하여 부여받은 IP주소를 연동해줘야 한다.</p>
<h4 id="--도메인구매">- 도메인구매</h4>
<p>  도메인을 판매하는 대표적 사이트로는 gabia, CAFE24, namecheap 등이 있으며, 사용 할 URL 주소를 검색한 뒤, 사용기간 및 도메인에 맞게 금액을 지불하여 도메인을 구매한다.</p>
<h4 id="--사이트와-dns등록">- 사이트와 DNS등록</h4>
<p>  도메인 구매가 완료되면 호스팅 주소와 IP주소를 연동시킨다. 
  이때 연동은 도메인을 구입한 도메인 판매 플래폼에서 네임서버를 관리하도록 설정할 수도 있고, 구매는 도메인 구입처, 네임서버는 타플래폼으로 관리되도록 설정할 수도 있다. AZURE의 경우 네임서버를 위임할 수 있으며 사용방법은 <a href="https://learn.microsoft.com/ko-kr/azure/dns/dns-domain-delegation">링크</a> 를 따라가면 확인할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/violet_yang/post/55b81d80-a0a2-4975-bc7f-1f8aab0bf91b/image.png" alt=""></p>
<p><a href="https://thebook.io/007046/0044/">IT 엔지니어를 위한 네트워크 입문: 7.2.1 DNS 소개 - 2</a></p>
<p>즉, 사용자가 웹 브라우저에서 <a href="http://www.yesbee.com">www.yesbee.com</a> 을 입력 시, DNS가 해당 도메인과 일치하는 IP주소를 찾아 사용자 컴퓨터에 되돌려주고, 응답받은 IP주소를 통해 실제 <a href="http://www.yesbee.com%EC%97%90">www.yesbee.com에</a> 접속하게 되는 것이다.</p>
<hr>
<h4 id="참고">참고</h4>
<p>  <a href="https://www.youtube.com/watch?v=_jJSzoV1uSg">조코딩</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] Component and Rendering ]]></title>
            <link>https://velog.io/@violet_yang/TIL-Component-and-Rendering</link>
            <guid>https://velog.io/@violet_yang/TIL-Component-and-Rendering</guid>
            <pubDate>Wed, 10 May 2023 02:48:13 GMT</pubDate>
            <description><![CDATA[<p>React, Vue 등 프레임워크를 사용하다보면 컴포넌트(Component), 렌더링(Rendering), Props와 같은 개념들이 등장한다.</p>
<p>먼저, 프레임워크(Framework)에 대해 간략하게 짚어보겠다.</p>
<p>Frame이라는 영어단어에서도 알 수 있듯이 일종의 틀 혹은 규격이 정해진 구조를 의미하며, 전체적인 흐름은 프레임워크가 결정을 한다. 즉, 틀/규격 의 규칙에 맞게 코드를 작성하면 element object를 직접 제어하지 않더라도 렌더링이 일어나며 이는 가상 DOM에서 제어가 된다. </p>
<pre><code class="language-jsx">const test = getElementById(&#39;id&#39;)</code></pre>
<p>위와 같이 HTML 조작없이도(프레임워크 내부적으로 세팅됨) 웹 페이지가 브라우저에 표시된다.</p>
<h1 id="그렇다면-렌더링이란-무엇일까">그렇다면, 렌더링이란 무엇일까?</h1>
<p><strong>렌더링이란 컴포넌트 내부의 state(:지역변수)와 props(:컴포넌트 간 통신을 위한 파라미터)에 기반하여 UI를 세팅하라고 요청하는 행위를 뜻한다.</strong> </p>
<p>HTML파일을 브라우저에 뿌려주는 과정이라고 생각하면 된다.</p>
<p>HTML파일이 브라우저에 뿌려지는 과정에서 HTML를 파싱하여 DOM트리를 만들고, CSS를 파싱하여 CSSOM 트리를 만든 뒤, DOM과 CSSOM가 결합하여 렌더링 트리가 생성된다.</p>
<p>이렇게 만들어진 렌더링 트리는 각 노드의 크기와 위치를 계산한 뒤, 브라우저를 통해 화면에 나타나는 것이다.</p>
<p>React에서는 생명주기(컴포넌트의 실행→업데이트→소멸) 내에서 렌더링과 리렌더링이 자주 일어나는데, 초기에 발생한 렌더링이 특정 조건에 따라 다시 발생하면 리렌더링이라고 지칭한다.</p>
<p>리액트의 리렌더링은 1) state의 변경, 2) props의 변경, 3)중앙 상태값(context, store) 변경, 4)상위 컴포넌트의 리렌더링(컴포넌트의 중첩구조) 에 의해 나타나며, </p>
<p>리렌더링이 일어나면 생명주기 hook이 다시 실행되며, return 문을 통해 기존과 달라진 부분을 업데이트 시켜주고 최종적으로 실제 DOM에 반영이 된다.</p>
<p>따라서, 무분별한 리렌더링이 일어나지 않도록 컴포넌트를 잘 구축할 필요가 있다.</p>
<BR>

<h1 id="계속해서-살펴볼-개념은-컴포넌트이다">계속해서 살펴볼 개념은, 컴포넌트이다.</h1>
<p><strong>컴포넌트란 재사용이 가능한 조각 혹은 구성요소로써, 특정 기능을 위한 기능적 단위(모듈)와 유사한 개념이다.</strong> 시스템을 아우르는 테이블 설계가 백엔드 프로그래밍의 핵심인 것처럼, 프론트앤드 프로그래밍은 컴포넌트 구조에 따라 유지보수의 용이성이 좌우될 만큼 중요한 부분이다.</p>
<p>퍼즐을 맞추거나 블록을 쌓듯이, 조각 하나하나를 결합하여 최종 조립품(한 개의 화면)이 완성되는 것이다. </p>
<p>컴포넌트를 이용하면 반복되는 요소를 공통 모듈로 구축하여 유사한 코드를 반복 구현하지 않아도 되지만, 컴포넌트를 지나치게 재활용하면 수정사항이 생겼을 때, 수정이 필요하지 않은 컴포넌트에도 영향을 미치게 되므로 응집도와 결합도의 밸런스를 잘 맞춰야 한다.</p>
<h3 id="컴포넌트-예시">컴포넌트 예시</h3>
<h4 id="--yesbee에-구축된-navnavigation-컴포넌트">- yesbee에 구축된 nav(navigation) 컴포넌트</h4>
<p>  로그인 API 통신결과의 response 데이터 중 menuTreeJson children의 Length에 따라 메뉴 개수가 동적으로 제어된다. 대메뉴(견적관리, 상품관리…)부터 소메뉴(견적요청리스트, Latest Transactions)까지 한 개의 컴포넌트 로  구성되어 있으며, 수정사항 발생 시 해당 컴포넌트에서만 처리하면 된다.
<img src="https://velog.velcdn.com/images/violet_yang/post/3aeb3eb7-750b-4751-9cfa-09f24915b0eb/image.png" alt=""></p>
<h4 id="--hive에-구축된-navnavigation-컴포넌트">- hive에 구축된 nav(navigation) 컴포넌트</h4>
<p><strong>A컴포넌트가 B 컴포넌트를 포함하는 구조로
A 컴포넌트를 상위 혹은 부모 컴포넌트,
B 컴포넌트를 하위 혹은 자식 컴포넌트로 부른다.</strong></p>
<p>입고/출고/재고 와 같은 대메뉴는 A컴포넌트의 HTML 엘리먼트 및 CSS로,
입고관리,입고검수관리 와 같은 소메뉴는 B컴포넌트에서 컨트롤 되며 A와 B 간의 데이터 공유는 <strong>props</strong>를 통해 일어난다.</p>
<p>props는 두 컴포넌트 간 데이터를 주고 받으면서 함수의 parameter와 같은 역할을 담당하며, </p>
<p>A 컴포넌트는 B 컴포넌트에 <strong>props</strong>로 입고관리,입고검수 등의 라벨정보를 포함하고 있는 오브젝트 배열을 전달한다.</p>
<p><strong>props</strong>를 전달받은 B컴포넌트에서 데이터 가공 및 CSS를 정의하여 element로 보여지도록 하고 </p>
<p>완성된 B컴포넌트는 A컴포넌트 내부에서 import 한 뒤 B컴포넌트가 필요한 props 데이터를 명시하기만 해주면 2개의 컴포넌트의 조합으로 화면이 만들어진다.</p>
<p>2개의 컴포넌트로 구성되었기 때문에 수정사항 위치에 따라 A 혹은 B, 때로는 A와 B 둘다 수정이 필요하기도 하다.</p>
<p><img src="https://velog.velcdn.com/images/violet_yang/post/cceedfe9-115b-4550-ad85-23418e195136/image.png" alt=""></p>
<br>

<p>얼핏보면, 컴포넌트는 하나로 구축했을 때 유지/보수 측면에서 더 용이하다고 생각할 수 있지만 그러지 않다. 컴포넌트 즉, 모듈의 크기가 커지면 커질 수록 코드의 양이 많아지기 때문에 가독성이 떨어질 수 있고, 화면상에서 데이터나 CSS 업데이트가 필요하지 않은 UI까지 불필요하게 리렌더링이 될 수 있기 때문에 전체적인 비즈니스 로직에 기반하여 구축할 필요가 있다.    </p>
<hr>
<h3 id="참고">참고</h3>
<p><a href="https://narup.tistory.com/272">티스토리-기은</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] Data parsing to .xlsx-SheetJs]]></title>
            <link>https://velog.io/@violet_yang/TIL-Data-parsing-to-.xlsx-SheetJs</link>
            <guid>https://velog.io/@violet_yang/TIL-Data-parsing-to-.xlsx-SheetJs</guid>
            <pubDate>Tue, 25 Apr 2023 05:00:29 GMT</pubDate>
            <description><![CDATA[<p>When you need Excel files from server data, using xlsx library can help code simpler and more easier to develop a function of Exceldownload.</p>
<p>In this article, you will know not only how to parse data(json) to sheet but customized header names on the top of excel name of file that you download.</p>
<br>

<h2 id="usage">Usage</h2>
<h3 id="1-to-use-xlsx-functions-install-xlsm-library-in-your-terminal-on-the-same-project-you-work-on">1. To use xlsx functions, install xlsm library in your terminal on the same project you work on.</h3>
<p><code>npm install xlsx</code> <a href="https://www.npmjs.com/package/xlsx">npm: xlsx</a></p>
<p>Then, npm package will be injected in package.json where indicates being ready to exposes the module in each file.</p>
<br>

<h3 id="2-import-the-module-parameter-in-the-top-of-file">2. Import the module parameter in the top of file</h3>
<pre><code class="language-jsx">import { utils, writeFile } from &#39;xlsx&#39;;</code></pre>
<br>


<h3 id="3-generate-a-worksheet-and-create-a-new-workbook">3. Generate a worksheet and create a new workbook</h3>
<pre><code class="language-jsx">const workSheet = utils.json_to_sheet(data) //data : server data which transfers into excel data
const workbook = utils.book_new();</code></pre>
<ul>
<li><code>json_to_sheet</code> generates a worksheet which and <code>book_new</code> creates a new workbook whice will be attacted in excel file.</li>
</ul>
<br>

<h3 id="4-convert-default-headers-into-customized-ones-and-add-an-exisiting--worksheet-to-a-workbook">4. Convert default headers into customized ones and add an exisiting  worksheet to a workbook</h3>
<pre><code class="language-jsx">utils.sheet_add_aoa(workSheet, [header], { origin: 0 });
utils.book_append_sheet(workbook, workSheet, sheetName);   </code></pre>
<ul>
<li><code>sheet_add_aoa</code> takes 3 parameters. One is worksheet, Second is an array of arrays of JS values for updating a worksheet object and the other is the cell’s location starting point</li>
<li><code>book_append_sheet</code> appends a worksheet to the workbook. Set the sheetName you want to use in the third parameter</li>
</ul>
<br>

<h3 id="5-finally-generate-and-attempt-to-save-file">5. Finally, generate and attempt to save file</h3>
<pre><code class="language-jsx"> writeFile(workbook, filename, opts);</code></pre>
<p><code>writeFile</code> creates a spreadsheet file and tries to write it to the system. </p>
<p>While this is happening, In the browser, it will try to prompt the user to download the file. In NodeJS, it will write to the local directory.</p>
<p><br><br></p>
<hr>
<h2 id="codes">Codes</h2>
<pre><code class="language-javascript">import { utils, writeFile } from &#39;xlsx&#39;;

const data = axios.post(&#39;api/download/test&#39;);
const header = [&#39;이름&#39;, &#39;나이&#39;, &#39;주소&#39;, &#39;번호&#39;]

if(data.lenght){
    try {
        const workSheet = utils.json_to_sheet(data)
        const workbook = utils.book_new();
        utils.sheet_add_aoa(workSheet, [header], { origin: 0 });
        utils.book_append_sheet(workbook, workSheet, sheetName[0]);
        writeFile(workbook, `${title}.xlsx`);
    }catch(e) {
        console.error(e)
        alert(&#39;다운로드 실패. 다시 시도해주세요.&#39;)
    }
}else {
    alert(&#39;데이터가 없습니다. 목록에서 확인해주세요.&#39;)
}</code></pre>
<p><br><br></p>
<hr>
<h2 id="reference">Reference</h2>
<p><a href="https://www.npmjs.com/package/xlsx">npmjs_xlsx</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] getServerSideProps in Next.js]]></title>
            <link>https://velog.io/@violet_yang/TIL-getServerSideProps-in-Next.js</link>
            <guid>https://velog.io/@violet_yang/TIL-getServerSideProps-in-Next.js</guid>
            <pubDate>Thu, 16 Mar 2023 14:55:02 GMT</pubDate>
            <description><![CDATA[<h2 id="getserversideprops-소개">getServerSideProps 소개</h2>
<p>getServerSideProps 는 페이지 렌더링 이전에 데이터를 먼저 fetch 해야할 때 사용한다. 즉, 컴포넌트 UI가 화면에 보여지기 이전에 getServerSideProps 에서 return 한 데이터를 pre-render 하여 컴포넌트 내에서 props로 전달받을 수 있다.
현업에서 서버쪽 요구사항을 구현하려면 getServerSideProps가 알맞은 선택지였고, 요구사항과 사용한 이유를 간략하게 설명해보겠다.</p>
<br>

<p>먼저, 요구사항은 다음과 같았다.
<em>1. 첫번째 페이지 api call의 명세 : requestBody 에 {id : null, date : &#39;&#39;} 담아서 전송</em>
_2. 두번째 ~마지막 페이지 api call 명세 : 첫번째 페이지의 마지막 데이터 중 id와 date 를  requestBody 에 {id : 2234, date : &#39;2023-03-11&#39;}의 형태로 전송 _</p>
<p>api를 call 하는 onGridReady() 함수는 agGrid Library 내부에서 실행 및 감지되는 인터페이스로 ProductPage 컴포넌트가 mount 되는 시점 즉, useEffect hook에서 트리거된다. 따라서, onGridReady 내부에서 데이터를 선언하면 onGridReady가 호출될 때마다 데이터가 initialize되는 이슈가 있었다. 따라서, 전역변수로 관리되어야 했고 그 시점은 화면이 브라우저에 렌더링 되기 이전이 적합했기 때문에 next.js에서 제공해주는 getServerSideProps() 를 선택했다.</p>
<br>

<p>그렇다면, getServerSideProps 는 언제 실행되고 어떻게 해서 컴포넌트까지 데이터를 연결시킬 수 있는 것일까? 먼저 아래 코드를 살펴보자. (두개의 함수는 동일한 페이지에 세팅)</p>
<br>
<br>

<h2 id="getserversideprops-예시">getServerSideProps 예시</h2>
<pre><code class="language-javascript">// declare getServerSideProps
export async function getServerSideProps() {
  return {
    props: { id: null, date: &#39;&#39; }, // will be passed to the page component as props as being {}
  };
}</code></pre>
<ul>
<li>ProductPage 컴포넌트의 props로 object형을 전달하며, 그 내부는 {id : null, date : &#39;&#39;} 로 세팅되어 있다.</li>
<li>경우에 따라 getServerSideProps에 파라미터를 받을 수 있다 ex) getServerSideProps(context)
<a href="https://nextjs.org/docs/api-reference/data-fetching/get-server-side-props">Context parameter</a></li>
</ul>
<br>

<pre><code class="language-javascript">export default function ProductPage({ id, date }) {

  const onGridReady = async (gridOption) =&gt; {
    gridOption?.api?.setDatasource({
      async getRows(params) {
        try {
          const blockSize = 50;
          const filteredData = params.filterModel;
          const rs = await ProductApi({
            page: parseInt(params.startRow / blockSize) + 1,
            size: blockSize,
            search: {
              id,
              date,
              ...filteredData,
            },
          });

          let lastRow = -1;
          lastRow = rs.data.payload.content === rs.data.payload.content &gt; 0;

          const hasRow = rs.data.payload.content.length &gt; 0;
          if (hasRow) {
            const index = rs?.data?.payload.content.length - 1;
            // overide last value from server to current constant
            id = rs?.data?.content[index].id;
            date = rs?.data?.content[index].date;
            params.successCallback(rs?.data?.content, lastRow);
          } else gridOption?.api?.showNoRowsOverlay();
        } catch (e) {
          console.error(e);
          params.failCallback([], 0);
        }
      },
    });
    gridOption?.api?.sizeColumnsToFit();
  };
  };
}</code></pre>
<ul>
<li>ProductPage 컴포넌트를 call 하는 시점에 getServerSideProps() 가 실행되며, ProductPage 페이지는 getServerSideProps() 함수에서 return한 데이터를 props 가진 채 pre-rendered 된다. 이때 props는 JSON 형태로 전달되기 때문에, 데이터 사용과 가공이 어렵지 않다. </li>
<li>컴포넌트에 전달된 id와 date는 각각 null, &#39;&#39;의 value값으로 초기화 작업이 이루어졌고, 이는 getServerSideProps() 함수의 return문에 명시되어 있다.</li>
<li>전달받은 id 및 date는 서버 호출시 ProductApi()의 search key에 value값으로 들어가며, 서버통신 이후 id = rs?.data?.content[index] 구문에 의해 데이터가 동적으로 바뀐다. </li>
</ul>
<hr>
<h4 id="참고">참고</h4>
<p><a href="https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props">next.js</a>
<a href="https://pollen-port-115.notion.site/3-2-Pre-rendering-Data-Fetching-with-Github-badd5975a6b64b4eb167828520804fea">프리온보딩</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Diffenrences between ‘null’ and ‘undefined’]]></title>
            <link>https://velog.io/@violet_yang/Diffenrences-between-null-and-undefined</link>
            <guid>https://velog.io/@violet_yang/Diffenrences-between-null-and-undefined</guid>
            <pubDate>Mon, 20 Feb 2023 14:11:51 GMT</pubDate>
            <description><![CDATA[<p>In Javascript, there could be comparison logics to differenciate <em>‘null’</em> from <strong>‘undefined’</strong>.
<strong>‘undefined’</strong> is a state when valiables are declared but have no value.
<em>‘null’</em> is a state when valiables are declared but allocate emtpy value.</p>
<p>For example, when the response of requesting Http has no specific property, it is evaluated as <strong>undefined</strong>
But, Unlike <strong>undefined</strong>, <em>null</em> shows when there are no values explicitly  </p>
<pre><code class="language-javascript">const { data } = Axios.get(&#39;https://github.com.test&#39;)
console.log(data) // {customer : &#39;yang&#39;, address : null, 
// itemList : [{itemName : &#39;candy&#39;, itemQty : 2, errorCode : 300101, errorRemark : &#39;no matched item&#39;]}

console.log(data.zipCode) // undefined</code></pre>
<br>

<pre><code class="language-javascript">typepf null // &#39;object&#39;
typeof undefined // &#39;undefined&#39;
null === undefined // false
null == undefined // true</code></pre>
<p>How does the ‘<em>null</em> === <strong>undefined</strong>’ statement come out? 
The answer is false</p>
<p>Because ‘_null_’ is set as the value to exactly indicate “no value” while ‘<strong>undefined</strong>’ is that when properties don’t exist or valiable desn’t have value.</p>
<p>Also, typeof null evaluates “object”. On the other hand, undefined evalutes “undefined” </p>
<p>To long story short,
‘_null_’ and ‘<strong>undefined</strong>’ are different in some reasons as mentioned above.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] slice vs splice]]></title>
            <link>https://velog.io/@violet_yang/TIL-slice-vs-splice</link>
            <guid>https://velog.io/@violet_yang/TIL-slice-vs-splice</guid>
            <pubDate>Thu, 16 Feb 2023 14:59:16 GMT</pubDate>
            <description><![CDATA[<p>When a delete Button is clicked, clicked data should be removed on page.
In that perspective, There are two way to get rid of clicked data
One is slice method, and the other is splice method.</p>
<p>Both are used with array data structure and return array as well.
On the other hand, It&#39;s necessary to know some differences.</p>
<br>

<h2 id="slice">slice</h2>
<p>slice() slice elements from start index to right before end one and return sliced arrays from original array.</p>
<blockquote>
<p>slice(start, end)</p>
</blockquote>
<pre><code class="language-javascript">const sliceTest = [1,2,3,4,5]
slice(0, 3) // [1,2,3] slice from index 0 to index 2 (doesn&#39;t contain end index)

console.log(sliceTest) // [1,2,3,4,5] ** no change in original array </code></pre>
<br>

<h2 id="splice">splice</h2>
<p>splice() splice elements from start index and remove as much as given count and return spliced arrays from original array.</p>
<blockquote>
<p>splice(start, deleteCount)</p>
</blockquote>
<pre><code class="language-javascript">const spliceTest = [1,2,3,4,5]
splice(0, 3) // [1,2,3,4] remove 3 elements from starting index
console.log(spliceTest) // [5] ** change in original array </code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] every & some]]></title>
            <link>https://velog.io/@violet_yang/TIL-every-some</link>
            <guid>https://velog.io/@violet_yang/TIL-every-some</guid>
            <pubDate>Tue, 07 Feb 2023 14:19:24 GMT</pubDate>
            <description><![CDATA[<h2 id="every">every</h2>
<p>every() checks if <strong>every</strong> of element in array is satisfied with a given condition. When meeting statement, this function returns true and vice versa.
So, only when all of elements pass the test, it returns true.</p>
<h2 id="some">some</h2>
<p>some() checks if <strong>any</strong> of element in array is satisfied with a given condition. When meeting statement, this function returns true and vice versa.</p>
<br>
<br>

<hr>
<h2 id="example">Example</h2>
<h3 id="as-is">as-is</h3>
<pre><code class="language-javascript"> const valid =
    state.companyUsersList.filter(user =&gt; Object.values(user).includes(&#39;&#39;))
      .length === 0 &amp;&amp;
    state.companyUsersList.filter(user =&gt; user.isDefault).length === 1</code></pre>
<h3 id="to-be">to-be</h3>
<pre><code class="language-javascript">  const valid =
    state.companyUsersList.every(user =&gt; !Object.values(user).includes(&#39;&#39;)) &amp;&amp;
    state.companyUsersList.some(user =&gt; user.isDefault)</code></pre>
<p>By using <strong><em>every</em></strong> and <strong><em>some</em></strong>, no need to add length property to get Boolean type. It can be simpler and cleaner code!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] axios get method & query string]]></title>
            <link>https://velog.io/@violet_yang/TIL-axios-get-method-query-string</link>
            <guid>https://velog.io/@violet_yang/TIL-axios-get-method-query-string</guid>
            <pubDate>Fri, 03 Feb 2023 05:22:58 GMT</pubDate>
            <description><![CDATA[<p>While using a Axios library, I had no doubt how it makes query string itself. Just sending parameters inside of Object as a second parameter lets it call <strong>‘GET’</strong> request with Axios. </p>
<p>So after searching what happens inside, The thing is this. It’s because Axios serializes <strong>option.params</strong> which is the second parameter and add it to the query string as shown below.
<br></p>
<pre><code class="language-javascript">import axios from &#39;axios&#39;

const params = {page : 1, size : 100, itemNumber : 234}
axios.get(&#39;https://axios.test.com/&#39;, { params } )

//parameters are translateed into the query string
axios.get(&#39;https://axios.test.com/request?page=1&amp;size=2&amp;itemNumber=234&#39;)</code></pre>
<br>

<p>To long story short, <em>Serializer</em> is a bulit in axios&#39;s function so that developers don&#39;t need to parse each parameter to query string. 
Once all parameters are included in Object GET method parse them into query string through &#39;toJSON()&#39; </p>
<br>

<p><a href="https://masteringjs.io/tutorials/axios/get-query-params">Mastering axios</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] HTTP vs HTTPS]]></title>
            <link>https://velog.io/@violet_yang/TIL-HTTP-vs-HTTPS</link>
            <guid>https://velog.io/@violet_yang/TIL-HTTP-vs-HTTPS</guid>
            <pubDate>Wed, 25 Jan 2023 12:08:52 GMT</pubDate>
            <description><![CDATA[<p>HTTP</p>
<p>HTTP/1</p>
<ul>
<li>한 개의 요청에 한개의 연결 즉, 1:1 관계로 요청시마다 연결 개수가 정비례하여 RTT가 증가</li>
<li>RTT의 증가로 서버에 부담 및 응답시간 지연 -&gt; 스플리팅,코드압축, Base64 인코딩 </li>
</ul>
<p>HTTP/1.1</p>
<ul>
<li>연결 시마다 TCP-3way handshaking 으로 처리하지 않고 keep-alive옵션을 통해 한번의 TCP연결로 여러 개의 파일을 송수신 할 수 있도록 변경</li>
<li>헤더에 많은 meta데이터가 들어 있어서 압축이 되지 않아 용량이 큼</li>
<li>HOL Blocking 때문에 성능 저하 문제가 발생<blockquote>
<p>HOL Blocking
같은 큐에 있는 패킷이 이전 패킷에 의해 지연될 때 발생하는 성능 저하 현상
ex) img.jsp</p>
</blockquote>
</li>
</ul>
<p>HTTP2</p>
<ul>
<li>HTTP/1.x 에 비해 응답 시간이 빠르며, 지연 시간이 줄어든 방식으로 멀티플렉싱, 헤더 압축, 서버 푸시, 우선순위에 따른 요청처리를 지원한다.</li>
</ul>
<blockquote>
<p>멀티플렉싱
여러 개의 스트림으로 송수신 하는 방법.
패킷 손실에 대응할 수 있어 데이터가 손실되어도 해당 스트림에만 영향을 미친다.</p>
</blockquote>
<ul>
<li>HTTP/1.x에서 발생했던 HOL Blocking 문제를 해결할 수 있게 됨</li>
<li>HTTP/1.x의 이슈였던 헤더의 크기를 허프만 코딩을 활용하여 개선</li>
<li>클라이언트 요청 없이 서버에서 리소스를 푸시(html 파일 요청으로 html+css 파일 전달)</li>
</ul>
<p>HTTPS
HTTP 위에서 동작하며, 어플리케이션과 전송 계층 사이에 SSL/TLS 계층을 넣은 요청을 의미
&#39;통신을 암호화&#39; 하는 데에 의의가 있다. SSL/TLS 를 통해 클라이언트-서버 외 제3자가 정보를 &#39;인터셉터&#39; 하는 것을 방지한다.
사이퍼 슈트, AEAD 사이퍼 모드, 디피-헬만 키 교환 암호화 알고리즘, SHA-256-알고리즘 등을 통해 데이터를 암호화 하며 이를 기반으로 인증 확인 작업이 일어나고 한번의 RTT로 데이터를 송수신한다.</p>
<ul>
<li>SEO에 도움. 구글브라우저 내에서도 HTTPS 서비스를 하는 사이트의 검색 우선순위가 높아 많은 사용자들의 유입을 기대할 수 있다.</li>
</ul>
<p>SEO</p>
<ul>
<li><p>캐노니컬 </p>
<pre><code>&lt;link rel=&quot;canonical&quot; href=&quot;https//test.com&quot;&gt;</code></pre><p>link 에 캐노니컬을 설정해야 한다.
<a href="https://yozm.wishket.com/magazine/detail/1420/">요즘IT, 캐노니컬</a></p>
</li>
<li><p>메타설정</p>
<pre><code>&lt;meta name=&quot;referrer&quot; content=&quot;origin-when-crossorigin&quot; id=&quot;meta_referrer&quot;&gt;</code></pre><p>html 파일 가장 윗부분에 메타를 설정해야 한다.
<a href="https://yozm.wishket.com/magazine/detail/816/">요즘IT, 메타설정</a>
...</p>
</li>
</ul>
<p>HTTPS 구축은</p>
<ol>
<li>구매한 CA인증키로 서비스 구축</li>
<li>로드밸런서 </li>
<li>CDN</li>
</ol>
<p>HTTPS/3</p>
<ul>
<li>TCP -&gt; UDP 기반으로 정보를 교환 : 3way-handshaking 과정의 생략 따라서, 초기 연결까지 지연 시간이 줄어든다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] Level1- 음양 더하기]]></title>
            <link>https://velog.io/@violet_yang/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-Level1-%EC%9D%8C%EC%96%91-%EB%8D%94%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@violet_yang/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-Level1-%EC%9D%8C%EC%96%91-%EB%8D%94%ED%95%98%EA%B8%B0</guid>
            <pubDate>Fri, 20 Jan 2023 14:54:30 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/violet_yang/post/3f9199df-6da9-4f3d-8e8b-1bf34f8d8311/image.png" alt=""></p>
<p>What i have to do in this problem is to add all the numbers based on each integer&#39;s sign.
Signs array has Boolean type as each element. &#39;true&#39; element represents a positive element, but &#39;false&#39; means a negative one.
Step by step, i thought of changing each element of absolutes to interger according to a real sign and add all numbers using <strong>&#39;reduce&#39;</strong> method.</p>
<br>

<h4 id="first-change-absolutess-element-to-a-real-interger-using-map-method">First, change absolutes&#39;s element to a real interger using <em>&#39;map&#39;</em> method.</h4>
<h4 id="and-then-return-sum-added-all-elements-using-reduce">And then, return sum added all elements using <em>&#39;reduce&#39;</em></h4>
<br>


<h3 id="my-code">My Code.</h3>
<hr>
<pre><code class="language-javascript">function solution(ab, signs) {
    const real = ab.map((num, idx)=&gt; {
        return signs[idx] === false ? -num : +num
    })

    return real.reduce((acc,cur)=&gt; acc+cur, 0)
}</code></pre>
<p>This can be passed in all cases. But, wanted to make them shorter and more effective, I searched a best code and noticed that <strong>&#39;reduce&#39;</strong> method can be used a lot.</p>
<br>
<br>

<h3 id="a-simplest-code">A simplest Code.</h3>
<pre><code class="language-javascript">function solution(absolutes, signs) {
    return absolutes.reduce((acc, val, i) =&gt; acc + (val * (signs[i] ? 1 : -1)), 0);
}</code></pre>
<p>Surprisingly, multiply 1 or -1 by curent element was the key point to solve this problem. It didn&#39;t need to change each to a real sign, If being dealt with addition to multiplied sign by current value. What a amazing ! </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] History API]]></title>
            <link>https://velog.io/@violet_yang/TIL-History-API</link>
            <guid>https://velog.io/@violet_yang/TIL-History-API</guid>
            <pubDate>Thu, 19 Jan 2023 14:49:25 GMT</pubDate>
            <description><![CDATA[<h2 id="history-api란">History API란?</h2>
<p>Window 객체에 내장되어 있는 객체로, 브라우저의 세션 기록에 접근하여 사용자의 방문 기록을 통해 페이지를 조작하도록 도와주는 속성을 가진다. back(), forward(), go() 메서드를 제공하며, history 객체를 사용하여 방문 기록을 탐색하거나 페이지를 이동할 수 있다. </p>
<p>개발자도구-콘솔창에 window 객체를 호출함으로써 쉽게 확인해보기 바란다.</p>
<p><img src="https://velog.velcdn.com/images/violet_yang/post/a4aa85f0-d834-4f38-8469-66913d0bd3f5/image.png" alt=""></p>
<br>
<br>

<h2 id="history-api-사용">History API 사용</h2>
<p>Vue, React 프레임워크에서 <strong>History API</strong>를 기반으로 페이지(라우터)를 이동하는데, 흔히 사용하는 방문 기록을 통한 화면이동은 프레임워크에서 제공하는 것이 아니라 Chrome, Edge, Safari 등 웹 브라우저의 내장 기능이라고 보면 된다.  </p>
<pre><code class="language-javascript">history.go(1)
history.back(-1)
history.forward(2)</code></pre>
<hr>
<h4 id="참조">참조</h4>
<p><a href="https://developer.mozilla.org/ko/docs/Web/API/History_API">MDN</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스] Level1- 예산]]></title>
            <link>https://velog.io/@violet_yang/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-Level1-%EC%98%88%EC%82%B0</link>
            <guid>https://velog.io/@violet_yang/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-Level1-%EC%98%88%EC%82%B0</guid>
            <pubDate>Tue, 17 Jan 2023 14:52:15 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/violet_yang/post/66230579-d8e3-46a1-8d9f-f9807cd045d7/image.png" alt=""></p>
<p>This problem is to get maximum how many departments you can give money based on their requesting money. Each money should be exactly the same as department’s requesting. Not to more not to less.
Thinking about how to resolve this, I dive into making steps with two arguments.</p>
<br>

<h4 id="first-make-for-loop-and-inject-statement-to-check-each-value-is-larger-than-budget">First, make for loop and inject statement to check each value is larger than budget.</h4>
<h4 id="second-calculate-remaining-budget-by-subracting-a-current-value-in-for-loop-and-push-the-current-value-into-array">Second, calculate remaining budget by subracting a current value in for loop and push the current value into array.</h4>
<h4 id="lastly-get-the-length-of-array-so-that-you-can-check-the-numbers-of-departments">Lastly, get the length of array so that you can check the numbers of departments.</h4>
<br>

<h3 id="my-code">My Code.</h3>
<hr>
<pre><code class="language-javascript">function solution(d, budget) {
    let answer = [];

    let remain = budget;
    for(let i = 0; i&lt; d.length; i++){
        if(d[i] &lt;= remain){
            remain = remain-d[i]
            answer.push(d[i])
        }
    }
    return answer.length;
}</code></pre>
<p>But, when mine was wrong in some cases. Afther being refered to other&#39;s solution, It&#39;s understandable why given &quot;d&quot; array should be sorted by ascending order.</p>
<p>So, the final solution is below</p>
<pre><code class="language-javascript">function solution(d, budget) {
    let answer = [];

    d.sort((a,b)=&gt; a-b)
    let remain = budget;
    for(let i = 0; i&lt; d.length; i++){
        if(d[i] &lt;= remain){
            remain = remain-d[i]
            answer.push(d[i])
        }
    }
    return answer.length;
}</code></pre>
<h4 id="the-point-of-this-problem-is-to-sort">The point of this problem is to Sort</h4>
<br>
<br>

<h3 id="a-simplest-code">A simplest Code.</h3>
<pre><code class="language-javascript">function solution(d, budget) {
    d.sort((a, b) =&gt; a - b);
    while (d.reduce((a, b) =&gt; (a + b), 0) &gt; budget) {
      d.pop();
    }

    return d.length;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] ESLint & Prettier]]></title>
            <link>https://velog.io/@violet_yang/TIL-Eslint-Prettier</link>
            <guid>https://velog.io/@violet_yang/TIL-Eslint-Prettier</guid>
            <pubDate>Sun, 15 Jan 2023 14:32:30 GMT</pubDate>
            <description><![CDATA[<h2 id="eslint">ESLint</h2>
<p>ESLint는 자바스크립트 코드에서 발견되는 문제시되는 패턴들을 식별하기 위한 정적 코드 분석 도구로 니콜라스 C. 자카스가 2013년에 개발하였다.
ESlint를 사용하기 위해서는 Node.js 가 꼭 설치되어 있어야 하며, VSCode 에디터에서 사용하려면 eslint extention 과 eslint library 모두 설치 및 세팅이 필요하다.</p>
<p><strong>ESlint는</strong> Codeing Convetion과 같이 가독성 있는 코드를 작성하는 규칙에 대해 명시하고 선행된 rules에 벗어난 코딩스타일이 존재하면 <em>&#39;error&#39;</em> 또는 <em>&#39;warning&#39;</em> 표시하거나 유효성 체크를 <em>&#39;off&#39;</em> 할 수도 있다. 따라서, <strong>ESLint는 버그를 더 빠르게 찾고 고칠 수 있도록 도와준다.</strong></p>
<br>
<br>
<br>

<h3 id="사용방법">사용방법</h3>
<ol>
<li><p>install <span style="background-color: gray"> ** ESLint extention<strong></span>  and <span style="background-color: gray"> ** ESLint library</strong></span>
<strong>ESLint</strong> 는 VSCode(텍스트 에디터)에 의존하여 구동되기 때문에, 에디터 확장 프로그램으로 설치하고, 설치된 확장 프로그램은 workspace 내에 설치된 ESLint library 를 통해 코드의 규칙을 판단하고 에러를 찾아낸다. </p>
<br>

<ol start="2">
<li>make  <span style="background-color: gray"> <strong>.eslintrc</strong></span> file</li>
</ol>
<p>*<em>.eslintrc *</em>파일을 통해서는 확장성, 플러그인 을 개별적으로 명시할 수 있기 때문에 커스텀 한 설정으로 협업 시 다른 사람이 작성한 코드의 가독성을 높여준다.</p>
</li>
</ol>
<br>
<br>

<h3 id="기본설정">기본설정</h3>
<pre><code class="language-javascript">module.exports = {
  root: true,
  env: {
    browser: true,
    es2021: true,
  },
  extends: [&#39;eslint:recommended&#39;, &#39;plugin:react/recommended&#39;],
  parserOptions: {
    ecmaVersion: &#39;latest&#39;,
    sourceType: &#39;module&#39;,
  },
  plugins: [],
  rules: {
    quotes: [&#39;error&#39;, &#39;single&#39;],
    // semi: [&#39;error&#39;, &#39;never&#39;],
    // &#39;space-in-brackets&#39;: [&#39;error&#39;, &#39;always&#39;],
    // endOfLine: 0, //개행 설정. windows에서 prettier를 사용할 시 crlf 오류가 발생하기 떄문에 설정
  },
};</code></pre>
<ul>
<li><h4 id="root">root</h4>
<p>.eslintrc 파일을 찾을 때 검색범위를 설정하는 옵션으로, 현재 리텍토리에서만 확인할지 그 상위 폴더까지 올라갈지 범위를 설정한다. <em>*<em>default : true *</em></em></p>
</li>
<li><h4 id="env">env</h4>
<p>자바스크립트가 node, browser 등 여러 환경에서 실행될 수 있기에 환경에 따라 사용 가능한 고유 객체(ex : window) 를 미리 알려줌으로써 오류가 나지 않도록 설정하는 옵션</p>
</li>
<li><h4 id="extends">extends</h4>
<p>이미 제공된 lint를 그대로 설정할 수 있는 옵션으로 basic 규칙을 수정하고 싶다면, rules 옵션에서 덮어쓰는 설정이 가능하다. _**ex :   &#39;extends&#39;: [&#39;airbnb &#39;]</p>
</li>
<li><p>*_</p>
</li>
<li><h4 id="parseroptions">parserOptions</h4>
<p>ESLint가 순수자바스크립트 코드만 이해할 수 있기 때문에 코드를 최신 문법으로 작성한 경우 파서를 사용하도록 설정해주는 옵션이다.</p>
</li>
<li><h4 id="plugins">plugins</h4>
<p>ESLin- t 기본규칙 외에 추가적인 규칙을 사용할 수 있도록 만들어주는 옵션으로, 해당 규칙에 어긋났을 때 <em><strong>error, warn, off</strong></em> 에 대한 설정은 extends 혹은 rules 옵션에서 명시한다._</p>
</li>
<li><h4 id="rules">rules</h4>
<p>사용자 규칙을 정의하는 옵션으로 extends 옵션에서 자동으로 설정된 rules을 오버라이드 할 때 유용하다. <em><strong>ex : quotes: [&#39;error&#39;, &#39;single&#39;]</strong></em></p>
</li>
</ul>
<br>
<br>

<hr>
<h2 id="prettier">Prettier</h2>
<h4 id="참조">참조</h4>
<p><a href="https://helloinyong.tistory.com/325">helloinyong</a>
<a href="https://www.daleseo.com/eslint-config/">DaleSeo</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] path alias & craco]]></title>
            <link>https://velog.io/@violet_yang/TIL-Path-Alias</link>
            <guid>https://velog.io/@violet_yang/TIL-Path-Alias</guid>
            <pubDate>Wed, 11 Jan 2023 14:59:27 GMT</pubDate>
            <description><![CDATA[<h2 id="absolute-path-vs-relative-path">Absolute Path vs Relative Path</h2>
<p>There are two ways to indicate path of files.
One is <strong>‘Absolute Path’</strong> and the other is <strong>‘Relative Path’</strong></p>
<p><strong>Absolute Path</strong> is a method to show a file’s path with Root Directory like src</p>
<pre><code class="language-jsx">// Relative Path

import Checkbox from &#39;../../components/Checkbox&#39;
import Api from &#39;../../../service/http/common/auth&#39;</code></pre>
<br>
On the other hand **Relative Path** shows paths based on a current located in file and parent or child file could be differenciated from where the current file is.

<pre><code class="language-jsx">// Relative Path

import Checkbox from &#39;@/common/components/Checkbox&#39;
import Api from &#39;@/service/http/common/auth&#39;</code></pre>
<p>Both are okay, but I prefer setting <strong>Absolute path(full path)</strong> to Relative path
Because it’s more visible to track path of files and accessible anywhere.
But, If to use Relative Path, some settings should be done before using it in react
<em>(I’ll introduce how to set Craco, so please find other instructions if you’d like to select ejection)</em></p>
<br>
<br>

<h2 id="how-to-use-craco">How to use Craco</h2>
<h4 id="1-install-craco-library">1. Install craco library</h4>
<pre><code>Type **npm i @craco/craco** at terminal in your proejct</code></pre><p><a href="https://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=&amp;ved=2ahUKEwjAuaqoh8H8AhXfsFYBHYl8A9sQFnoECA8QAQ&amp;url=https%3A%2F%2Fwww.npmjs.com%2Fpackage%2F%40craco%2Fcraco&amp;usg=AOvVaw2bLYC1cXo6gus6P7xMfq-D">craco webpage</a></p>
<h4 id="2-make-new-file-named-cracoconfigjs-and-designate-path-alias">2. Make new file named <strong>craco.config.js</strong> and designate path alias</h4>
<pre><code class="language-jsx">// basic alias setting 

const path = require(&#39;path&#39;)

module.exports = {
    webpack : {
        alias : {
            &#39;@&#39; : path.resolve(__dirname, &#39;src/&#39;) // import Api from &quot;@/service/login&quot;;
        }
    }
}</code></pre>
<p>All the paths starts from ‘@’ whenver modules are imported </p>
<ul>
<li>craco.config.js file should be placed in roote path where the same location with package.json</li>
</ul>
<br>

<h4 id="3-change-scripts-command-to-craco-at-packagejson">3. Change scripts command to craco at <strong>package.json</strong></h4>
<pre><code class="language-jsx">&quot;scripts&quot;: {
    &quot;start&quot;: &quot;craco start&quot;, // originally &#39;react-scripts start&#39;
    &quot;build&quot;: &quot;craco build&quot;,
  },</code></pre>
<br>

<h4 id="4-run-react-app-in-your-browser">4. Run react app in your Browser</h4>
<br>
<br>

<hr>
<h3 id="reference">Reference</h3>
<p><a href="https://helloinyong.tistory.com/325">https://helloinyong.tistory.com/325</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] spread (...) 연산자]]></title>
            <link>https://velog.io/@violet_yang/TIL-spread-...-%EC%97%B0%EC%82%B0%EC%9E%90</link>
            <guid>https://velog.io/@violet_yang/TIL-spread-...-%EC%97%B0%EC%82%B0%EC%9E%90</guid>
            <pubDate>Mon, 02 Jan 2023 14:57:11 GMT</pubDate>
            <description><![CDATA[<h2 id="spread-연산자란">spread 연산자란?</h2>
<p>스프레드(전개) 연산자는 반복 가능한 데이터의 형태를 풀어서 0개 이상의 key-value 쌍의 객체 형태로 확장이 가능하여, 새로운 규격을 만들거나 기존 규격을 유지할 때 유용하게 사용되는 문법이다.
사용자 selectbox를 생각해보면 쉽게 이해할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/violet_yang/post/35b30c58-8f96-4e6f-ac3a-30729206db38/image.png" alt=""></p>
<br>

<h2 id="spread-적용-전">spread 적용 전</h2>
<p>검색한 시/도에 따라 이용할 택배사를 선택하는 selectbox가 있고 시/도를 선택해야만 택배사 selectbox의 클릭 이벤트가 활성화 된다. 
selectbox의 초기값은 아래와 같으며, 시/도를 선택하면 검색되는 택배사 리스트는 selectList 데이터에 추가된 후 보여져야 한다.</p>
<br>

<pre><code>&lt;template&gt;
    &lt;div&gt;
        &lt;comboBox v-model=&quot;state.combo&quot; @select=&quot;callNewList&quot;/&gt;
        &lt;selectBox v-model=&quot;state.select&quot; @click=&quot;select&quot;/&gt;
    &lt;/div&gt;
&lt;/template&gt;

&lt;script setup&gt;
import {reactive} from &#39;vue&#39;
import Api from &#39;@/https&#39;

const state = reactive({
    combo : {},
    select : [{id : null, name : &#39;선택해주세요&#39;}]
})

const callNewList = ({id}) =&gt; {
    // api call and get results from response
    const { data } = Api.get(&#39;test.search-delivery-list&#39;, id)
    console.log(data) // expected : [{id : 1, name : &#39;우체국&#39;}, {id : 2, name : &#39;gs택배&#39;}]
}
&lt;/script&gt;</code></pre><br>
state내부에 존재하는 select의 데이터에 서버에서 받아온 data 를 추가할 때 어떤 방법이 떠오르는가?
아마도 기존값의 맨 마지막에 데이터를 하나씩 쌓아올리는 stack 구조의 push()함수가 가장 흔하게 사용되었던 방법이 아닐까 싶다.
따라서 push() 함수로는 이렇게 구현할 수 있다.
<br>


<pre><code>const callNewList = () =&gt; {
    // api call and get results from response
    const { data } = Api.get(&#39;test.search-delivery-list&#39;, id)
    for(let i= 0; i &lt; data.length; i++){
        state.select.push(data[i])
    }
}

// select = [{id : null, name : &#39;선택해주세요&#39;}, {id : 1, name : &#39;우체국&#39;}, {id : 2, name : &#39;gs택배&#39;}]
</code></pre><br> 
아주 원초적인 방법으로 누구나 쉽게 접근이 가능할 것이다. 이 때, spread를 활용하면 어떻게 구현되는지 확인해보자.


<p><br><br></p>
<h2 id="spread-적용-후">spread 적용 후</h2>
<pre><code>const callNewList = () =&gt; {
    // api call and get results from response
    const { data } = Api.get(&#39;test.search-delivery-list&#39;, id)
    state.select = [...state.select, ...data]
}

// select = [{id : null, name : &#39;선택해주세요&#39;}, {id : 1, name : &#39;우체국&#39;}, {id : 2, name : &#39;gs택배&#39;}]
</code></pre><br>
push() 함수를 사용했을 때와 결과는 동일하지만 spread 연산자를 사용하므로써 간결한 코드스타일로 코드수가 줄어들었다. 

<pre><code>state.select = [...state.select, ...data]</code></pre><p>해당 구문에서 state.select 의 return 값은 [] 배열, 배열 안 데이터는 state.select와 data 데이터를 각각 풀어서 key-value 한쌍씩으로 나열하였다.
내부에서 데이터는 state.select = [...[{id : null, name : &#39;선택해주세요&#39;}, ...[{id : 1, name : &#39;우체국&#39;}]]]
따라서 &#39;...[]&#39; 구문이 =&gt; {} 객체로 확장됨을 알 수 있다.</p>
<p>이렇듯, spread 연산자를 활용하여 기존 함수의 한계를 개선하고, 더 나은 코드를 구현해보면 좋겠다.</p>
<p><br><br></p>
<hr>
<h4 id="참조">참조</h4>
<p><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Spread_syntax">mdn</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Restful] Get방식 요청 (Path Variable VS Query Parameter)]]></title>
            <link>https://velog.io/@violet_yang/Restful-Get%EB%B0%A9%EC%8B%9D-%EC%9A%94%EC%B2%AD-Path-Variable-VS-Query-Parameter</link>
            <guid>https://velog.io/@violet_yang/Restful-Get%EB%B0%A9%EC%8B%9D-%EC%9A%94%EC%B2%AD-Path-Variable-VS-Query-Parameter</guid>
            <pubDate>Tue, 27 Dec 2022 14:57:56 GMT</pubDate>
            <description><![CDATA[<h2 id="path-variable">Path Variable</h2>
<p>&#39;경로&#39;를 &#39;변수&#39;로 사용하며 path 를 통해 <strong>resource</strong>를 식별하는 방식으로, 
필요한 정보 반환을 위해 경로의 <strong>resource</strong>를 전달해야 하며, <strong>resource</strong> 가 없을 경우 _404 에러_가 발생한다. 
<br></p>
<pre><code>https://test.net:/board/detail/2</code></pre><br>
<br>

<h2 id="query-parameter">Query Parameter</h2>
<p>&#39;경로&#39; 뒤에 &#39;입력데이터&#39;를 함께 제공하고 &#39;?&#39; 이후 <em>key=value</em> 형태로 입력하며 여러개 일 때에는 <strong>&#39;&amp;&#39;</strong> 로 구분하는 방식으로, 정렬이나 필터링 또는 검색 기능에서 주로 사용한다.
필수 <strong>query parameter</strong>가 없다면 데이터를 보내지 않아도 에러는 발생하지 않으며, 결과를 빈값으로 반환하기 때문에 정렬이나 검색이 필요한 경우에 적용된다.
<br></p>
<pre><code>https://test.net:/board/list-search?title=&#39;velog&#39;&amp;page=1&amp;size=20</code></pre><br>
<br>

<hr>
<h2 id="path-variable-vs-query-parameter">Path Variable VS Query Parameter</h2>
<p><strong>Path Variable</strong> 은
resource 식별이 필요한 경우; 예를 들어 Selectbox 혹은 Combobox 에서, 특정 데이터를 물고 API 호출해야 하는 경우가 해당된다. 즉, 결과를 반환하기 위해 특정 데이터를 꼭 path의 resource로서 식별하게 되며 필수 Variable라고 말할 수 있다. </p>
<br>

<p><strong>Query Parameter</strong> 은</p>
<p>빈 데이터를 반환해도 문제가 없는 경우; 대표적으로 검색, 정렬기능이 예시가 될 수 있다. 
게시판에서 게시물을 찾을 때 검색조건에 &quot;작성자&quot;, &quot;제목&quot;, &quot;제목+작성자&quot; 등이 존재하고 아무 검색어를 입력하지 않아도 에러가 발생하지 않는다.</p>
<br>


]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] Array.from(배열형변환)-ES6]]></title>
            <link>https://velog.io/@violet_yang/TIL-Array.from%EB%B0%B0%EC%97%B4%ED%98%95%EB%B3%80%ED%99%98-ES6</link>
            <guid>https://velog.io/@violet_yang/TIL-Array.from%EB%B0%B0%EC%97%B4%ED%98%95%EB%B3%80%ED%99%98-ES6</guid>
            <pubDate>Thu, 01 Dec 2022 14:44:31 GMT</pubDate>
            <description><![CDATA[<p>JS의 기본을 단단히 하고자 &#39;코어 자바스크립트&#39; 도서를 읽고 있다.
&#39;실행컨텍스트&#39;나 &#39;THIS&#39; 개념 정리도 필요하지만 머릿속에 완전한 정립이 되지 않아 한번 더 정독한 뒤에 블로그 작성 예정이다.</p>
<p>그에 앞서, 새로 알게 된 &#39;Array.from&#39; 메서드 에 대해 기록해보겠다.</p>
<h2 id="1-개념">1. 개념</h2>
<p>ES6문법에 도입된 메서드로 유사배열객체 또는 반복 가능한 모든 종류의 데이터 타입을 배열로 전환해준다. </p>
<blockquote>
<p>Array.from(iterable obj, mapFn, thisValue)</p>
</blockquote>
<ol>
<li><p>iterable obj - essential
 → 배열로 변환 할 객체</p>
</li>
<li><p>mapFun - optional
 → 변환될 배열의 모든 요소에 호출될 콜백함수</p>
</li>
<li><p>thisValue - optional
 → mapFn 실행 시, this로 바인딩 되어 사용할 값</p>
</li>
</ol>
<p>iterable obj는 length가 존재하는 객체로 obj[1], obj[2]와 같이 접근이 가능하지만 배열이 아니기 때문에 obj.push(), obj.pop() 혹은 obj.sort() 로 활용이 불가능하다.</p>
<p>따라서, 순회가 가능한 객체의 배열화가 필요할 때 활용할 때 좋고 사용방법은 다음과 같다.</p>
<br>

<hr>
<h2 id="2-예시">2. 예시</h2>
<pre><code>const test1 = Array.from({length : 3}, (val, idx) ⇒ val)

console.log(test1) // expected : [undefined, undefined, undefined]</code></pre><ul>
<li>첫번째 인자로 value는 없고, length만 존재하는 이터러블 데이터를 변환할 객체로 전달한다.</li>
<li>두번째 인자로 mapFn함수의 콜백형태(ex : map((el, index, array)⇒){})를 정의하고, 각각의 요소를 지칭하는 val/순서를 나타내는 idx ; 2개의 인자를 세팅한 뒤 요소(val)를 콜백함수의 return값으로 써주면 총 3개의 undefined 이 존재하는 Array배열이 된다.</li>
<li>그 이유는 첫번째 인자(length:3)는 순회가 가능하지만, value값이 존재하지 않기 때문에 총 3번을 순회하여 undefined 를 return한다.</li>
</ul>
<br>

<pre><code>const test2 = Array.from({length : 3}, (val, idx) ⇒ idx)

console.log(test2) // expected : [0, 1, 2]</code></pre><ul>
<li>위의 예시와 다르게 각 요소의 순서를 나타내는 idx 를 콜백함수의 return값으로 전달한다.</li>
<li>value값과 별개로(첫번째 인자인 length:3은 여전히 value가 없음) index를 0부터 return 한다.</li>
</ul>
<br>

<pre><code>const test3 = Array.from(new Map([[1,3], [2,4], [3,5]]))

console.log(test3) // expected : [[1,3], [2,4], [3,5]]]</code></pre><ul>
<li>객체의 배열화뿐만 아니라 배열의 배열화도 가능하다.</li>
<li>Array.from() 메서드는 데이터를 복사하여 형태가 동일한 또 다른 배열을 return하기 때문에, 데이터 가공이 필요할 때 사용할 수 있다.</li>
</ul>
<hr>
<h4 id="참고">참고</h4>
<p><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/from">mdn</a>
<a href="https://perlpark.github.io/articles/array-from/">PerlPark</a></p>
]]></description>
        </item>
    </channel>
</rss>