<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Haron.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Sun, 19 Nov 2023 06:04:32 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Haron.log</title>
            <url>https://velog.velcdn.com/images/haron-lee/profile/113503a2-ca37-4bb0-812f-77f41be8a40b/image.PNG</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Haron.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/haron-lee" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[React] Twin Macro, Tailwind + Styled-Components 사용기]]></title>
            <link>https://velog.io/@haron-lee/React-Twin-Macro-Tailwind-Styled-Components-%EC%82%AC%EC%9A%A9%EA%B8%B0</link>
            <guid>https://velog.io/@haron-lee/React-Twin-Macro-Tailwind-Styled-Components-%EC%82%AC%EC%9A%A9%EA%B8%B0</guid>
            <pubDate>Sun, 19 Nov 2023 06:04:32 GMT</pubDate>
            <description><![CDATA[<h1 id="twin-macro-사용해보기">twin macro 사용해보기</h1>
<blockquote>
<p>tailwind + styled-components</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/haron-lee/post/6ad1e8f6-533f-4fa6-9383-b3c3f7ade2f5/image.png" alt=""></p>
<h2 id="계기">계기</h2>
<p>평상시 CSS in JS 방식인 styled-components를 선호하였지만 이번 프로젝트에선 빠르게 스타일링을 할 수 있는 tailwind를 사용하기로 했다. 하지만 스타일링을 하면서 불편한 점이 있었는데 바로 <strong>동적 스타일링</strong>이었다. props에 따라 스타일을 적용해야하는 경우에는 한계가 있었고 className에 작성하면서 길어질 수록 코드 가독성 또한 떨어졌다. 
그래서 tailwind와 평상시 사용하던 styled-components를 함께 사용하여 각자의 장점을 부각시킬 수 있는 방법을 찾았고 바로 <code>twin macro</code>였다.  </p>
<br/>
<br/>

<h2 id="📌준비하기">📌준비하기</h2>
<h3 id="1-tailwind-설치-및-설정">1. Tailwind 설치 및 설정</h3>
<pre><code>npm i -D tailwindcss
yarn add -D tailwindcss</code></pre><pre><code class="language-js">// tailwind.config.js 폴더 최상단에 생성 후 작성 
module.exports = {
  content: [&#39;./src/**/*.{js,jsx,ts,tsx}&#39;],
  darkMode: &#39;media&#39;,
  theme: {
    extend: {
      colors: {},
    },
  },
  plugins: [],
};</code></pre>
<br/>

<h3 id="2-twinmacro와-styled-components-설치-및-설정">2. twin.macro와 Styled-components 설치 및 설정</h3>
<pre><code>npm i twin.macro styled-components
yarn add twin.macro styled-components</code></pre><pre><code class="language-js">// package.json
&quot;babelMacros&quot;: {
  &quot;twin&quot;: {
    &quot;preset&quot;: &quot;styled-components&quot;
  }
}</code></pre>
<br/>

<h3 id="3-babel-설치-및-설정">3. babel 설치 및 설정</h3>
<pre><code>npm i -D babel-plugin-styled-components babel-plugin-macros
yarn add -D babel-plugin-styled-components babel-plugin-macros</code></pre><pre><code>// .babelrc
{
  &quot;plugins&quot;: [
    &quot;babel-plugin-macros&quot;,
    &quot;babel-plugin-styled-components&quot;
  ]
}</code></pre><p>본인은 Vite를 사용중이었기에 따로 <code>.babelrc</code>를 설정하지 않고 <code>vite.config.ts</code> 파일에 plugins을 넣어주었다.</p>
<pre><code class="language-ts">import { defineConfig } from &#39;vite&#39;;
import react from &#39;@vitejs/plugin-react&#39;;

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    react({
      babel: {
        plugins: [&#39;babel-plugin-macros&#39;, &#39;babel-plugin-styled-components&#39;],
      },
    }),
  ],
});
</code></pre>
<br/>

<h3 id="4-globalstyles-설정">4. GlobalStyles 설정</h3>
<p>기존의 index.css 파일의 tailwind 초기 설정은 twin.macro의 BaseStyles로 대신 해줄 수 있다. </p>
<pre><code>// 기존 tailwind 초기설정 
@tailwind base;
@tailwind components;
@tailwind utilities;</code></pre><pre><code class="language-jsx">// src/GlobalStyles.jsx 
import React from &#39;react&#39;
import { createGlobalStyle } from &#39;styled-components&#39;
import tw, { theme, GlobalStyles as BaseStyles } from &#39;twin.macro&#39;

const CustomStyles = createGlobalStyle`
  body {
    -webkit-tap-highlight-color: ${theme`colors.purple.500`};
    ${tw`antialiased`}
  }
`;

const GlobalStyles = () =&gt; (
  &lt;&gt;
    &lt;BaseStyles /&gt;
    &lt;CustomStyles /&gt;
  &lt;/&gt;
);

export default GlobalStyles;</code></pre>
<br/>

<p>원하는 곳에 GlobalStyles를 넣어주면된다.</p>
<pre><code class="language-jsx">// src/index.jsx
import React from &#39;react&#39;
import GlobalStyles from &#39;./styles/GlobalStyles&#39;
import App from &#39;./App&#39;
import { createRoot } from &#39;react-dom/client&#39;

const container = document.getElementById(&#39;root&#39;)
const root = createRoot(container)
root.render(
  &lt;React.StrictMode&gt;
    &lt;GlobalStyles /&gt;
    &lt;App /&gt;
  &lt;/React.StrictMode&gt;,
)

// 혹은
// src/App.jsx

import GlobalStyles from &#39;@/styles/GlobalStyles&#39;;
import Layout from &#39;@/styles/Layout&#39;;
import Header from &#39;components/header/Header&#39;;

function App() {
  return (
    &lt;&gt;
      &lt;GlobalStyles /&gt;
      &lt;Layout $opacityCtrl={opacityCtrl}&gt;
        &lt;Header /&gt;
      &lt;/Layout&gt;
    &lt;/&gt;
  );
}

export default App;
</code></pre>
<br/>

<h3 id="extension-추천">Extension 추천</h3>
<p>tailwind Extension처럼 twin.macro로 Extension이 있는데 설치하면 더 편하게 사용할 수 있다.</p>
<blockquote>
<p><a href="https://marketplace.visualstudio.com/items?itemName=lightyen.tailwindcss-intellisense-twin">https://marketplace.visualstudio.com/items?itemName=lightyen.tailwindcss-intellisense-twin</a></p>
</blockquote>
<br/>

<h2 id="설치방법-참고">설치방법 참고</h2>
<blockquote>
<p><a href="https://github.com/ben-rogerson/twin.examples/tree/master/cra-styled-components">https://github.com/ben-rogerson/twin.examples/tree/master/cra-styled-components</a></p>
</blockquote>
<br/>
<br/>

<h2 id="📌사용-방식">📌사용 방식</h2>
<p>사용 방식은 다양했다. 본인이 사용해 본 방식만 설명한다.</p>
<pre><code class="language-tsx">// 인라인 스타일
import tw from &#39;twin.macro&#39;

const Test = () =&gt; {
  return (
    &lt;div tw=&#39;flex flex-col gap-4 bg-white&#39;&gt;
      &lt;p tw=&#39;text-blue-400&#39;&gt;Test&lt;/p&gt;
    &lt;/div&gt;
  );
}

export default Test;
</code></pre>
<br/>

<pre><code class="language-jsx">// styled-components 방식
import tw from &#39;twin.macro&#39;

const Test = () =&gt; {
  return (
    &lt;Wrapper&gt;
      &lt;Text&gt;Test&lt;/Text&gt;
    &lt;/Wrapper&gt;
  );
}

const Wrapper = tw.div`
  flex
  flex-col
  gap-4
  bg-white
`

const Text = tw.p`
  text-blue-400
`

export default Test;</code></pre>
<br/>

<pre><code class="language-jsx">// styled-components와 함께 쓰기
// 중첩 문법을 사용할 때 편하게 사용했다. 
import tw from &#39;twin.macro&#39;
import styled from &#39;styled-components&#39;

const Test = () =&gt; {
  return (
    &lt;Wrapper&gt;
      &lt;p&gt;Test&lt;/p&gt;
    &lt;/Wrapper&gt;
  );
}

const Wrapper = styled.div`
  ${tw`flex flex-col gap-4 bg-white`}

  p {
    ${tw`text-blue-400`}
  }
`

export default Test;</code></pre>
<br/>

<pre><code class="language-jsx">// props 사용
import tw from &#39;twin.macro&#39;
import styled from &#39;styled-components&#39;

const Test = ({gray}) =&gt; {
  return (
    &lt;Wrapper&gt;
      &lt;p gray={gray}&gt;Test&lt;/p&gt;
    &lt;/Wrapper&gt;
  );
}

const Wrapper = styled.div`
  ${tw`flex flex-col gap-4 bg-white`}

  p {
    ${({ gray }) =&gt; gray ? tw`text-blue-500` : tw`text-red-500`}
  }
`

export default Test;</code></pre>
<br/>

<h2 id="📌사용-후기">📌사용 후기</h2>
<p>Tailwind 경험이 좋았던 만큼 twin.macro도 빠르게 스타일링을 할 수 있는 점에서 굉장히 만족도가 높았고 익숙한 styled-components 문법을 그대로 사용할 수 있고 또 함께 사용할 수 있음에 만족도가 높았다. Tailwind가 더 익숙해진다면 훨씬 더 빠르고 편하게 사용할 수 있을 듯 하다. </p>
<h2 id="twin-macro-github">Twin Macro GitHub</h2>
<blockquote>
<p><a href="https://github.com/ben-rogerson/twin.macro">https://github.com/ben-rogerson/twin.macro</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[useEffect 의존성배열 ESLint warning, React Hook useEffect has missing dependencies]]></title>
            <link>https://velog.io/@haron-lee/useEffect-%EC%9D%98%EC%A1%B4%EC%84%B1%EB%B0%B0%EC%97%B4-ESLint-warning-React-Hook-useEffect-has-missing-dependencies</link>
            <guid>https://velog.io/@haron-lee/useEffect-%EC%9D%98%EC%A1%B4%EC%84%B1%EB%B0%B0%EC%97%B4-ESLint-warning-React-Hook-useEffect-has-missing-dependencies</guid>
            <pubDate>Fri, 01 Sep 2023 16:07:59 GMT</pubDate>
            <description><![CDATA[<h2 id="useeffect-의존성배열">useEffect 의존성배열</h2>
<p>늘 아무 생각없이 썼었던 useEffect를 ESLint에게 크게 혼나면서 의존성 배열에 대해서 다시 생각해보게 되었다.
의존성 배열이란? useEffect에 두번째로 인자로 넘기는 배열이다. 두번째 인자가 없으면 effect는 매번 실행되고, 빈 배열이라면 렌더링시 최초 한 번만 실행 된다. 까지는 알고 있었던 이야기였지만, 왜 빈 배열 일때 <code>missing dependencies</code> 에러가 뜨는지는 정확하게 알지 못했다. </p>
<h3 id="에러-상황">에러 상황</h3>
<pre><code class="language-jsx">const { fetchFollowing } = FollowingListAPI(accountname);
const { getUserData } = MyInfoAPI();

useEffect(() =&gt; {
  const getData = async () =&gt; {
    const followingData = await fetchFollowing();
    const userData = await getUserData();
    followingData &amp;&amp; setMyFollowing(followingData.slice(0, 5));
    userData &amp;&amp; setUser(userData);
  };

  getData();
}, []);</code></pre>
<p>위 코드에서 빈배열에 <code>missing dependencies</code> 에러가 발생했다. </p>
<blockquote>
<p>React Hook useEffect has missing dependencies: &#39;fetchFollowing&#39; and &#39;getUserData&#39;. Either include them or remove the dependency array  react-hooks/exhaustive-deps</p>
</blockquote>
<p>useEffect에서 의존성 배열이란 &quot;effect 함수가 의존하고 있는 요소들의 모음&quot;이다. 즉, <strong>effect 함수가 사용하고 있는 외부의 값들의 의존성</strong>이다. </p>
<p>위 코드를 보면 외부에 있는 <code>fetchFollowing</code>과 <code>getUserData</code>를 useEffect 안에서 사용하고 있다. 그렇기 때문에 ESLint 경고가 뜨는 것이다. </p>
<pre><code class="language-jsx">const { fetchFollowing } = FollowingListAPI(accountname);
const { getUserData } = MyInfoAPI();

useEffect(() =&gt; {
  const getData = async () =&gt; {
    const followingData = await fetchFollowing();
    const userData = await getUserData();
    followingData &amp;&amp; setMyFollowing(followingData.slice(0, 5));
    userData &amp;&amp; setUser(userData);
  };

  getData();
}, [fetchFollowing, getUserData]); // 넣어주기</code></pre>
<p>그래서 의존성 배열안에 <code>fetchFollowing</code>과 <code>getUserData</code>를 넣어주었다. 그랬더니 일어난 일은 <code>무한 렌더링</code>이었다. 
왜그런지 알아보니 <code>fetchFollowing</code>과 <code>getUserData</code>는 비동기 함수로 데이터를 반환하고 있는 함수이다. useEffect가 실행될 때마다 매번 새로운 함수가 생성되어 무한렌더링이 발생하는 것이라고 한다. </p>
<h3 id="해결방법">해결방법</h3>
<p>해당 함수가 매번 새롭게 생성되지 않게 해주는 메모이제이션 방법을 사용한다. </p>
<p>먼저 <code>fetchFollowing</code>과 <code>getUserData</code> 코드를 useCallback을 사용하여 메모이제이션 한다. </p>
<pre><code class="language-jsx">const FollowingListAPI = (accountname) =&gt; {
  const token = useRecoilValue(userToken);

  // useCallback 사용
  const fetchFollowing = useCallback(async () =&gt; {
    try {
      const response = await fetch(`${URL}/profile/${accountname}/following`, {
        method: &#39;GET&#39;,
        headers: {
          Authorization: `Bearer ${token}`,
          &#39;Content-Type&#39;: &#39;application/json&#39;,
        },
      });

      const data = await response.json();
      return data;
    } catch (error) {
      console.error(&#39;API 응답에 실패하였습니다.&#39;, error);
    }
  }, [accountname, token]); // accountname, token 의존

  return { fetchFollowing };
};

export default FollowingListAPI;</code></pre>
<pre><code class="language-jsx">const { fetchFollowing } = FollowingListAPI(accountname);
const { getUserData } = MyInfoAPI();
const [myFollowing, setMyFollowing] = useState([]);
const [user, setUser] = useState();

useEffect(() =&gt; {
  const getData = async () =&gt; {
  const followingData = await fetchFollowing();
  const userData = await getUserData();
  followingData &amp;&amp; setMyFollowing(followingData.slice(0, 5));
  userData &amp;&amp; setUser(userData);
  };

  getData();
}, [fetchFollowing, getUserData]);
</code></pre>
<p>useCallback 의존성 배열에는 바뀔 수 있는 accountname과 token을 넣어서 accountname과 token이 바뀔 때만 함수를 새롭게 생성되게 한다. 그리고 사용하는 코드는 동일하게 작성한다. </p>
<p>드디어!! 무한렌더링에서 벗어날 수 있었다. 하지만, </p>
<blockquote>
<p>메모이제이션은 자주 사용하면 안되고 마지막 수단으로 남겨두어야한다</p>
</blockquote>
<p>그렇기 때문에 처음부터 고려하고 커스텀훅을 더 커스텀 훅답고 재사용가능하게 만들었어야 했다고 생각한다. 천천히 공부하면서 더 리팩토링을 해보기로..! </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Chore JS 06.프로토 타입] 메서드 오버라이드]]></title>
            <link>https://velog.io/@haron-lee/Chore-JS-06.%ED%94%84%EB%A1%9C%ED%86%A0-%ED%83%80%EC%9E%85-%EB%A9%94%EC%84%9C%EB%93%9C-%EC%98%A4%EB%B2%84%EB%9D%BC%EC%9D%B4%EB%93%9C</link>
            <guid>https://velog.io/@haron-lee/Chore-JS-06.%ED%94%84%EB%A1%9C%ED%86%A0-%ED%83%80%EC%9E%85-%EB%A9%94%EC%84%9C%EB%93%9C-%EC%98%A4%EB%B2%84%EB%9D%BC%EC%9D%B4%EB%93%9C</guid>
            <pubDate>Mon, 17 Jul 2023 15:28:31 GMT</pubDate>
            <description><![CDATA[<h2 id="프로토타입-체인">프로토타입 체인</h2>
<p>자바스크립트에서 프로토타입은 객체의 부모 역할을 하는 객체라고 설명했다. 모든 객체는 자신의 프로토타입을 가리키는 내부 링크인 <code>__proto__</code>를 가지고 있으며, 프로토 타입 체인을 통해 상위 프로토타입으로 부터 속성과 메서드를 상속받을 수 있다. </p>
<h3 id="메서드-오버라이드">메서드 오버라이드</h3>
<p>메서드 오버라이드는 상속받은 메서드를 자식 객체에서 재정의하여 사용하는 것을 말한다. 부모 객체에서 정의된 메서드를 자식 객체에서 동일한 이름의 메서드로 다시 정의하면, 자식 객체에서는 오버라이드된 메서드가 호출되어 실행된다. </p>
<pre><code class="language-js">// 부모 객체 정의
function Animal(name) {
  this.name = name;
}

// 부모 객체의 sayHello 메서드
Animal.prototype.sayHello = function() {
  console.log(`Hello, I&#39;m ${this.name}`);
};

// 자식 객체 정의
function Cat(name) {
  Animal.call(this, name);
}

// Cat 객체의 프로토타입 설정
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;

// Cat 객체에서 sayHello 메서드 오버라이드
Cat.prototype.sayHello = function() {
  console.log(`Meow, I&#39;m ${this.name}`);
};

// 객체 생성 및 메서드 호출
const animal = new Animal(&#39;Animal&#39;);
const cat = new Cat(&#39;Cat&#39;);

animal.sayHello(); // Hello, I&#39;m Animal
cat.sayHello(); // Meow, I&#39;m Cat
</code></pre>
<p>위의 예시에서 <code>Animal</code> 객체는 <code>sayHello</code> 메서드를 가지고 있다. 이 메서드는 부모 객체에서 정의 되었고, <code>Animal</code> 객체와 <code>Cat</code> 객체에서 모두 사용할 수 있다. 이후에 <code>Cat</code> 객체에서 <code>sayHello</code> 메서드를 오버라이드 하여서 다르게 출력하도록 재정의하였다. <code>Cat.prototype</code>을 <code>Animal.prototype</code>의 인스턴스로 설정함으로 <code>Cat</code> 객체는 <code>Animal</code> 객체의 메서드를 상속받을 수 있게 되었고 <code>Cat.prototype</code> 에서 <code>sayHello</code> 메서드를 오버라이드하여 자식 객체에서 변경할 수 있다. </p>
<p>결과적으로 <code>animal.sayHello()</code>는 부모 객체의 <code>sayHello</code> 메서드를 호출하여 &quot;Hello, I&#39;m Animal&quot;을 출력, <code>cat.sayHello()</code>는 자식 객체인 <code>Cat</code>의 오버라이드된 <code>sayHello</code>를 호출하여 &quot;Meow, I&#39;m Cat&quot;을 출력한다. 즉 메서드 위에 메서드를 덮어씌우게 되는 것이다. 원본을 제거하고 다른 대상으로 교체되는 것이 아닌 원본이 그대로 있는 상태에서 다른 대상을 그 위에 얹는 것이다. </p>
<p>자바스크립트 엔진이 메서드를 찾는 방식을 보면 가장 가까운 대상인 자신의 프로퍼티를 검색하고, 없으면 그 다음으로 가까운 대상인 <code>__proto__</code> 를 검색하는 순서로 이루어지기 때문에 덮어씌워진 메서드를 먼저 찾게된다. </p>
<p>prototype의 메서드 오버라이드를 사용하면 상속 구조에서 부모 객체의 동작을 자식 객체에서 수정하거나 확장할 수 있다. 이를 통해 코드의 재사용성과 유지보수성을 높일 수가 있다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] React does not recognize prop on a DOM element. 오류, styled-components props 오류, StyleSheetManager]]></title>
            <link>https://velog.io/@haron-lee/React-React-does-not-recognize-prop-on-a-DOM-element.-%EC%98%A4%EB%A5%98-styled-components-props-%EC%98%A4%EB%A5%98-StyleSheetManager</link>
            <guid>https://velog.io/@haron-lee/React-React-does-not-recognize-prop-on-a-DOM-element.-%EC%98%A4%EB%A5%98-styled-components-props-%EC%98%A4%EB%A5%98-StyleSheetManager</guid>
            <pubDate>Mon, 17 Jul 2023 14:37:54 GMT</pubDate>
            <description><![CDATA[<h2 id="문제발생">문제발생</h2>
<p><img src="https://velog.velcdn.com/images/haron-lee/post/b1935490-28aa-4467-bba8-2d2b5c9c1373/image.png" alt=""></p>
<p>위와 같은 오류가 한 세개정도 나왔는데, 모두 styled-components props 들이었다. 이 오류가 무엇인고 하니 GPT는 아래와 같이 설명했다. </p>
<blockquote>
<p>zIdx와 같은 컴포넌트 속성명을 사용할 때 경고가 발생하는 이유는 해당 속성들이 HTML의 표준 속성이 아니기 때문입니다. React는 HTML 요소에는 표준 속성만 인식하고 처리할 수 있습니다.</p>
</blockquote>
<h2 id="해결방법">해결방법</h2>
<p>여러가지 블로그를 보면서 해결하기 위해 노력했고, fragement를 사용도 해보았지만 해결되지 않았다. 당연히 에러 메세지에서 알려주는 소문자로도 바꿔보았지만 되지 않았다. 왜일까를 검색하다가 찾게된 두가지 방법으로 해결할 수 있었다. 2번을 추천한다! </p>
<h3 id="1-stylesheetmanager">1. StyleSheetManager</h3>
<pre><code class="language-tsx">import { StyleSheetManager } from &#39;styled-components&#39;;

function App() {
  return (
    &lt;RecoilRoot&gt;
      &lt;StyleSheetManager
        shouldForwardProp={(prop) =&gt;
          prop !== &#39;zIdx&#39;
        }
      &gt;
        &lt;GlobalStyle /&gt;
        &lt;Routes&gt;
          &lt;Route path=&#39;/&#39; element={&lt;Home /&gt;} /&gt;
          &lt;Route path=&#39;/login&#39; element={&lt;Login /&gt;} /&gt;
          &lt;Route path=&#39;/products/:id&#39; element={&lt;ProductDetail /&gt;} /&gt;
        &lt;/Routes&gt;
      &lt;/StyleSheetManager&gt;
    &lt;/RecoilRoot&gt;
  );
}
export default App;</code></pre>
<p>StyleSheetManager는 styled-components에서 제공하는 컴포넌트이다. styled-components가 동적으로 생성된 스타일 태그를 관리하는 역할을 하고 주로 서버 사이드 렌더링(SSR) 시나리오에서 적용된다. 서버와 클라이언트 간 스타일 일치를 위해 필요하다고 한다. </p>
<p>일부 HTML 속성은 React의 내장 속성과 충돌할 수 있는데 이러한 충돌을 방지하기 위해서 styled-components는 기본적으로 스타일이 적용된 컴포넌트에 사용되는 모든 속성을 DOM으로 전달하지 않는다고 한다. 대신에 스타일 태그에 해당 속성을 추가하여 스타일이 적용되도록 한다. 이로 인해 일부 속성은 React가 인식하지 못하게 되어서 경고가 발생한다. </p>
<p>StyleSheetManager를 사용하면 styled-components가 해당 속성을 DOM으로 전달하도록 설정할 수 있고, StyleSheetManager는 styled-components에서 생성된 모든 스타일 태그를 관리하고, 스타일이 적용된 컴포넌트에서 해당 속성을 정상적으로 사용할 수 있도록 한다. 따라서 StyleSheetManager를 사용하면 <code>zIdx</code> 속성을 컴포넌트에 전달하고 React가 인식할 수 있도록 한다. <code>shouldForwardProp</code> 속성을 사용하여 해당 속성을 DOM으로 전달한다. StyleSheetManager를 이용하면 styled-components의 속성 관리를 세밀하게 조정하면 충돌이나 경고를 처리할 수 있게 된다고 한다. </p>
<h3 id="2--달러-접두사">2. $ 달러 접두사</h3>
<p>사용예시</p>
<pre><code class="language-tsx">// in styled-components
z-index: ${(props) =&gt; (props.$zIdx ? 9999 : &#39;auto&#39;)};

// in other file
&lt;UserButtonStyle $zIdx={type === &#39;person&#39;} /&gt;</code></pre>
<p>styled-components에서의 <code>$</code> 접두사는 props의 이름을 커스텀 속성으로 지정할 때 사용된다. <code>zIdx</code>와 같이 대문자가 포함된 속성은 DOM 요소에 직접 적용되지 않기에 생긴 오류라 <code>$zIdx</code>와 같이 커스텀 속성으로 정의하는 것이 좋다고 한다. 이와 같이 <code>$</code>를 사용하여 커스텀 속성을 정의하면 코드에서 속성의 역할과 의도를 더 명확하게 표현할 수 있으며, 충돌이나 오류를 방지할 수 있다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React-TypeScript] TSX에서 svg, png import ]]></title>
            <link>https://velog.io/@haron-lee/TypeScript-TSX%EC%97%90%EC%84%9C-svg-png-import</link>
            <guid>https://velog.io/@haron-lee/TypeScript-TSX%EC%97%90%EC%84%9C-svg-png-import</guid>
            <pubDate>Tue, 11 Jul 2023 08:07:45 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/haron-lee/post/aa05880b-9eb8-4b14-91f5-e7a1f7bf931e/image.png" alt=""></p>
<p>기존의 jsx에 import 되어있던 이미지들이 tsx로 바꾸니 from 뒤로 오류가 생겼났다.</p>
<h2 id="문제-원인">문제 원인</h2>
<blockquote>
<p>its corresponding type declarations. </p>
</blockquote>
<p>TypeScript에게 해당 모듈이 어떤 타입을 가지는지 알려줘야한단다. 그래서 <code>declare module</code> 구문을 사용하여 따로 타입을 가지는지 알려주기위한 파일을 만들어야했다. </p>
<h2 id="해결-방법">해결 방법?</h2>
<p>svg와 png 파일을 모듈로 선언해야한다. 별도의 타입 선언 파일을 생성하고, tsconfig.json에서 include 부분에 해당 파일 경로를 추가해준다. 이렇게 하면 TypeScript는 .svg, .png 파일을 React 컴포넌트로 인식할 수 있게 된단다. 일반적으로 @types 폴더나 src 폴더 내에 타입 선언 파일을 작성한다. </p>
<ul>
<li>src/custom.d.ts 파일 생성<pre><code class="language-tsx">declare module &#39;*.svg&#39; {
const content: string;
export default content;
}
</code></pre>
</li>
</ul>
<p>declare module &#39;*.png&#39; {
  const content: string;
  export default content;
}</p>
<pre><code>
- tsconfig.json 변경
```json
&quot;include&quot;: [
    //컴파일할 폴더 입력. src의 모든파일 확인함
    &quot;src&quot;,
    &quot;src/@types/custom.d.ts&quot;
  ],</code></pre><p>폴더 구조 예시 </p>
<pre><code>- src/
  - components/
  - utils/
  - ...
  - @types/
    - custom.d.ts
- tsconfig.json
- package.json</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[React-TypeScript] React input common component 마이그레이션. jsx에서 tsx]]></title>
            <link>https://velog.io/@haron-lee/TypeScript-React-input-common-component-%EB%A7%88%EC%9D%B4%EA%B7%B8%EB%A0%88%EC%9D%B4%EC%85%98.-jsx%EC%97%90%EC%84%9C-tsx</link>
            <guid>https://velog.io/@haron-lee/TypeScript-React-input-common-component-%EB%A7%88%EC%9D%B4%EA%B7%B8%EB%A0%88%EC%9D%B4%EC%85%98.-jsx%EC%97%90%EC%84%9C-tsx</guid>
            <pubDate>Tue, 11 Jul 2023 07:31:26 GMT</pubDate>
            <description><![CDATA[<p>common components를 마이그레이션 하면서 여러가지 오류들을 맞이 했다. 오류에서 배워가는 와중에 궁금증이 들었던 부분이 있다.🤔 바로 <code>...props</code> 부분이었는데 작성한 컴포넌트와 스타일 컴포넌트의 타입들을 명시해주었을 때 <code>...props</code>로 들어오는 속성들의 타입은 명시를 해야하는 걸까? </p>
<h2 id="props에-타입을-미리-대응해야하는가">...Props에 타입을 미리 대응해야하는가?</h2>
<pre><code class="language-tsx">import React from &#39;react&#39;;
import styled from &#39;styled-components&#39;;

type LoginInputProps = React.HTMLAttributes&lt;HTMLInputElement&gt; &amp; {
  type?: &#39;button&#39; | &#39;submit&#39; | &#39;reset&#39; | undefined;
};

const LoginInput = (props: LoginInputProps) =&gt; {
  const { type } = props;
  return &lt;InputStyle type={type ? type : &#39;text&#39;} {...props} /&gt;;
};

const InputStyle = styled.input`
  padding: 20px 10px;
  border-bottom: 1px solid var(--border);

  &amp;::placeholder {
    font-size: 16px;
  }
`;

export default LoginInput;</code></pre>
<p>현재는 LoginInput컴포넌트의 type 부분에만 예상 type을 작성해주었는데, ...props 부분은 어떻게 해야할지 몰랐다. 그래서 gpt의 도움을 받아 찾아보았다. </p>
<pre><code class="language-tsx">type LoginInputProps = React.HTMLAttributes&lt;HTMLInputElement&gt; &amp; {
  type?: &#39;button&#39; | &#39;submit&#39; | &#39;reset&#39; | undefined;
  onChange?: (event: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; void;
};</code></pre>
<p>위의 코드 처럼 onChange에 대한 대응을 할 수 있지만 <code>...props</code>를 사용하여 모든 동적인 속성에 대해 타입을 지정하는 것은 어려울 수 있다고 한다. 따라서 일반적으로 <code>...props</code>를 사용하여 동적인 속성을 전달받을 때는 타입 체크를 생략하고, 필요한 경우 속성의 유효성을 직접 확인하거나 타입 단언(assertion)을 사용하여 타입을 강제하는 것이 일반적이라고 한다.</p>
<h2 id="속성의-유효성-타입-단언">속성의 유효성, 타입 단언</h2>
<p>그럼 속성의 유효성을 직접 확인하거나 타입단언을 사용하여 타입을 강제하는 방법은 어떤게 있을까?</p>
<pre><code class="language-tsx">type LoginInputProps = React.HTMLAttributes&lt;HTMLInputElement&gt; &amp; {
  type?: &#39;button&#39; | &#39;submit&#39; | &#39;reset&#39; | undefined;
  onChange?: (event: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; void;
};

const LoginInput = (props: LoginInputProps) =&gt; {
  const { type, onChange, ...rest } = props;

  if (onChange &amp;&amp; typeof onChange !== &#39;function&#39;) {
    console.error(&#39;onChange must be a function&#39;);
  }

  return &lt;InputStyle type={type ? type : &#39;text&#39;} {...rest} /&gt;;
};</code></pre>
<p>위 코드에서 onChange 속성을 확인하기 위해 조건문을 사용하여 함수 타입 여부를 확인할 수 있다. 만약 속성이 함수 타입이 아니라면 콘솔에 error가 찍히도록 말이다. </p>
<p>또한 타입 단언을 사용하여 속성의 타입을 강제할 수도 있다. 예를 들어 &#39;...props&#39;로 전달받은 속성 중에서 customProp이라는 속성을 사용하고자 한다면 다음과 같이 타입 단언을 사용하여 타입을 강제할 수 있다.</p>
<pre><code class="language-tsx">type LoginInputProps = React.HTMLAttributes&lt;HTMLInputElement&gt; &amp; {
  type?: &#39;button&#39; | &#39;submit&#39; | &#39;reset&#39; | undefined;
  customProp?: string;
};

const LoginInput = (props: LoginInputProps) =&gt; {
  const { type, customProp, ...rest } = props;

  // customProp 속성을 사용할 때 타입 단언을 사용하여 타입을 강제함
  const customValue = (customProp as string) || &#39;&#39;;

  return &lt;InputStyle type={type ? type : &#39;text&#39;} {...rest} /&gt;;
};</code></pre>
<p>위 코드에서는 customProps 속성을 사용할 때 (customProp as string)이렇게 타입단언을 사용하여 해당 속성을 string으로 강제할 수 있다. 이러한 방식으로 유효성을 직접 확인하거나 타입 단언을 사용하여 필요한 경우에 타입을 강제할 수 있다. 하지만 이것은 타입 시스템의 검사를 우회하는 것이기 때문에 주의해서 사용해야한단다. 올바른 타입을 사용하는 것이 좋고, 필요한 경우에만 직접확인하거나 타입 단언을 사용하기로 하자. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React-TypeScript] jsx에서 txs로 마이그레이션시 오류,  No overload matches this call.]]></title>
            <link>https://velog.io/@haron-lee/TypeScript-jsx%EC%97%90%EC%84%9C-txs%EB%A1%9C-%EB%A7%88%EC%9D%B4%EA%B7%B8%EB%A0%88%EC%9D%B4%EC%85%98%EC%8B%9C-%EC%98%A4%EB%A5%98</link>
            <guid>https://velog.io/@haron-lee/TypeScript-jsx%EC%97%90%EC%84%9C-txs%EB%A1%9C-%EB%A7%88%EC%9D%B4%EA%B7%B8%EB%A0%88%EC%9D%B4%EC%85%98%EC%8B%9C-%EC%98%A4%EB%A5%98</guid>
            <pubDate>Tue, 11 Jul 2023 06:01:59 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>No overload matches this call.Overload 1 of 2, &#39;(props: PolymorphicComponentProps&lt;&quot;web&quot;,FastOmitDetailedHTMLPropsButtonHTMLAttributesHTMLButtonElement&gt;,HTMLButtonElement&gt;, never&gt;, void, void, {}, {}&gt;): Element&#39;, gave the following error. </p>
</blockquote>
<h2 id="문제발생">문제발생</h2>
<p>기존의 진행하던 프로젝트를 jsx문법에서 tsx로 마이그레이션 하던 중 위의 오류가 생겼다. 오류가 나타난 코드는 아래와 같다.</p>
<pre><code class="language-jsx">const renderPages = () =&gt; {
    return Array.from({ length: pageNum }, (_, index) =&gt; (
      &lt;PageNums
        key={index + 1}
        onClick={() =&gt; handlePageClick(index + 1)}
        activePage={index + 1 === productPageNum}
      &gt;
        {index + 1}
      &lt;/PageNums&gt;
    ));
  };

const PageNums = styled.button`
  padding: 3px 8px;
  border: none;
  border-radius: 3px;
  background: transparent;
  font-size: 18px;

  ${(props) =&gt;
    props.activePage &amp;&amp;
    css`
      color: #fff;
      background-color: var(--primary);
    `}

`;</code></pre>
<p>renderPages 함수 부분의 <code>activePage</code> 부분과 PageNums 스타일 컴포넌트 안의 <code>activePage</code> 부분에 빨간선이 생겼다. </p>
<h2 id="원인은">원인은?</h2>
<p>No overload matches this call 오류가 발생하는 이유는 <code>activePage</code> 속성이 styled-components의 button 컴포넌트에 제대로 전달되지 않았기 때문이라고 한다. 즉, 타입 호환성의 문제였다. PageNums 컴포넌트를 타입 정의하는 부분에서 <code>activePage</code> 속성의 타입을 명시적으로 지정해주어야 한단다.</p>
<h2 id="해결방법">해결방법</h2>
<pre><code class="language-tsx">type PageNumsProps = {
  activePage?: boolean;
} &amp; ButtonHTMLAttributes&lt;HTMLButtonElement&gt;;

const PageNums = styled.button&lt;PageNumsProps&gt;`
  padding: 3px 8px;
  border: none;
  border-radius: 3px;
  background: transparent;
  font-size: 18px;

  ${(props) =&gt;
    props.activePage &amp;&amp;
    css`
      color: #fff;
      background-color: var(--primary);
    `}
`;</code></pre>
<p>먼저 PageNum 컴포넌트의 타입을 PageNumsProps라는 type으로 지정을 해준다. <code>ButtonHTMLAttributes&lt;HTMLButtonElement&gt;</code>는 HTML 버튼 요소에 적용되는 기본 속성을 상속받은 타입이다. 즉 <code>ButtonHTMLAttributes</code> generic을 <code>HTMLButtonElement</code>로 지정하여서 <code>&lt;button&gt;</code> 요소에 적용되는 속성들을 포함하게 한다. 이렇게 하면 PageNums 컴포넌트는 <code>&lt;button&gt;</code> 요소에 적용되는 모든 기본 속성을 가지게 된다. <code>activePage?: boolean</code>은 PageNumsProps에 새로운 속성인 <code>activePage</code>를 정의하는 부분이고 <code>activePage</code>는 optional 속성이므로 있을 수도 있고 없을 수도 있으며, boolean이기에 true와 false 값을 가진다. 따라서 PageNumsProps는 기본적 버튼 요소의 속성들을 상속 받으면서 추가적으로 <code>activePage</code>속성을 가지는 타입이 정의 된다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React-TypeScript] React useRef 사용할 때 Ref is possibly 'null', useRef Error]]></title>
            <link>https://velog.io/@haron-lee/TypeScript-React-useRef-%EC%82%AC%EC%9A%A9%ED%95%A0-%EB%95%8C-Ref-is-possibly-null-useRef-Error</link>
            <guid>https://velog.io/@haron-lee/TypeScript-React-useRef-%EC%82%AC%EC%9A%A9%ED%95%A0-%EB%95%8C-Ref-is-possibly-null-useRef-Error</guid>
            <pubDate>Mon, 10 Jul 2023 15:28:15 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/haron-lee/post/ba54b4ee-62ab-43fa-b0c2-63957c6e7275/image.png" alt=""></p>
<h2 id="문제">문제</h2>
<p><code>useRef</code>를 사용해서 scroll을 조정하기 위해서 jsx문법으로 작성된 코드를 tsx로 바꾸니 listReft.current 부분에 위 사진처럼 오류가 생겼다. 기존의 React 프로젝트를 typescript를 적용하면서 발생한 문제였다. </p>
<pre><code class="language-jsx">const listRef = useRef&lt;HTMLUListElement&gt;(null);

listRef.current.scrollTop = 0;</code></pre>
<p><code>useRef</code>는 초기값이 있든 없든 컴포넌트가 실행되고서 평가가 진행되는 시점에 current 객체는 null로 평가가 된다. 렌더링 완료 후에는 current 객체의 평가가 끝나고 제대로 만들어져있다. 이 이유와 초기값을 null로 넣었기 때문에 <code>is possibly null</code> null일 수도 있다는 오류가 뜨는 것 같았다.</p>
<h2 id="해결방법들">해결방법들</h2>
<p>첫번째 방법으로는 null이 아닐 경우 실행한다는 조건문을 넣어주는 것이다.</p>
<pre><code class="language-jsx">const listRef = useRef&lt;HTMLUListElement&gt;(null);

if(listRef.current !== null) {
  lisfRef.current.scrollTop = 0;
}</code></pre>
<p>두번째 방법으로는 any 타입을 넣어준다.</p>
<pre><code class="language-jsx">const listRef = useRef&lt;any&gt;(null);

listRef.current.scrollTop = 0;</code></pre>
<br>

<p><a href="https://velog.io/@rkio/Typescript-React-useRef-%EC%82%AC%EC%9A%A9%EC%8B%9C-%EA%B0%9C%EC%B2%B4%EA%B0%80-nullundefined%EC%9D%B8-%EA%B2%83-%EA%B0%99%EC%8A%B5%EB%8B%88%EB%8B%A4-%EC%97%90%EB%9F%AC">출처</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Warning: Each child in a list should have a unique "key" prop. 에러가 뜰 때]]></title>
            <link>https://velog.io/@haron-lee/Warning-Each-child-in-a-list-should-have-a-unique-key-prop.-%EC%97%90%EB%9F%AC%EA%B0%80-%EB%9C%B0-%EB%95%8C</link>
            <guid>https://velog.io/@haron-lee/Warning-Each-child-in-a-list-should-have-a-unique-key-prop.-%EC%97%90%EB%9F%AC%EA%B0%80-%EB%9C%B0-%EB%95%8C</guid>
            <pubDate>Sat, 27 May 2023 13:35:25 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/haron-lee/post/8d5395d0-7588-4f45-a833-8a1e9933468a/image.png" alt=""></p>
<p>React에서 map 함수를 이용해서 API에서 받아온 products list들의 정보를 카드 UI로 뿌려주는 상황에서 발생한 에러. 
화면은 정상적으로 잘 나왔지만 콘솔에 찍혀있는 에러가 거슬려서 구글링을 해보았다. 코드는 아래와 같다. </p>
<pre><code class="language-js">{products &amp;&amp; products.map((item) =&gt; {
return (
  &lt;Card&gt;
    &lt;img src={item.image} alt={item.product_info} /&gt;
    &lt;p className=&quot;title&quot;&gt;{item.product_name}&lt;/p&gt;
    &lt;p className=&quot;price&quot;&gt;&lt;strong&gt;{item.price}&lt;/strong&gt;원&lt;/p&gt;
  &lt;/Card&gt;
  );
})}</code></pre>
<h3 id="문제점">문제점</h3>
<p>React에서 리스트로 렌더링되는 요소들에 고유한 <code>key</code> prop이 제공되지 않아서 발생함. <code>key</code> prop은 React가 각 요소를 구별하고 업데이트를 효율적으로 수행하는데 도움을 주는 중요한 prop이라고 한다. </p>
<h3 id="해결방법">해결방법</h3>
<p>ProductItem 컴포넌트에서 map 함수를 사용하여 리스트를 렌더링 할 때 각 요소에 고유한 <code>key</code> prop을 제공하는 것이다. 아래는 key를 추가해준 코드이다.</p>
<pre><code class="language-js">{products &amp;&amp; products.map((item) =&gt; {
return (
  &lt;Card key={item.product_id}&gt;
    &lt;img src={item.image} alt={item.product_info} /&gt;
    &lt;p className=&quot;title&quot;&gt;{item.product_name}&lt;/p&gt;
    &lt;p className=&quot;price&quot;&gt;&lt;strong&gt;{item.price}&lt;/strong&gt;원&lt;/p&gt;
  &lt;/Card&gt;
  );
})}</code></pre>
<p>드디어 정상적으로 잘 작동한다!! </p>
<blockquote>
<p>메모
<code>map()</code> 호출 내부의 JSX 요소에는 항상 키가 필요합니다!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[JS] Function() constructor]]></title>
            <link>https://velog.io/@haron-lee/JS-Function-constructor</link>
            <guid>https://velog.io/@haron-lee/JS-Function-constructor</guid>
            <pubDate>Sat, 27 May 2023 11:30:26 GMT</pubDate>
            <description><![CDATA[<h1 id="function">Function()</h1>
<p>계산기 어플을 만들다가 계산식 부분을 해결해준 <code>new Function</code>이라는 생성자. 어떤친구인고 궁금해서 찾아보았다. </p>
<pre><code class="language-js">new Function()</code></pre>
<p>Function() 생성자는 Function 개체를 만든다. 생성자를 직접 호출하면 함수를 동적으로 생성할 수 있지만 보안 및 <code>eval()</code>과 유사한 성능 문제가 있다고 한다. 물론 <code>eval()</code> 함수만큼의 중요한 위험성은 아니라고 한다. </p>
<blockquote>
<p>eval() 문자로 표현된 JS 코드를 실행하는 함수
하지만 입력되는 코드가 위험한 코드 있으므로 절대 사용하지 말 것을 경고.
로컬 범위에 대한 액세스 권한이 있을 수 있다.</p>
</blockquote>
<p><code>new Function()</code>은 호출 될 때마다 새로운 함수를 생성하는 built-in 함수이다. 새로운 함수 객체를 만들어 내며, 생성된 함수 객체는 문자열로 전달된 JavaScript 코드를 실행할 수 있다고 한다. <code>new Function()</code> 생성자 함수는 하나 이상의 인수를 입력으로 받는다. 첫번째 인수는 생성할 함수의 전체 매개변수 목록을 포함하는 문자열이며, 그 뒤로는 함수의 바디(body)로 사용될 하나 이상의 문자열이 따라온다고 한다. </p>
<pre><code class="language-js">const sum = new Function(&#39;a&#39;, &#39;b&#39;, &#39;return a + b&#39;);
console.log(sum(2, 4)); // 6</code></pre>
<p><code>new Function()</code>을 사용하여 동적으로 새로운 함수를 생성하는 예시 코드이다. 위 코드에서 New Function 메서드에 전달된 매개변수는 문자열로 a, b를 정의하고 a와 b를 더한 값을 반환하여 sum 함수에 할당된다. 
<code>newFunction()</code>을 사용하면 문자열로 된 함수 코드를 받아들여 동적으로 함수를 생성하는 것이 가능하다. 특정 조건을 만족하지 않은 상황에서 코드를 작성하는 용도에 사용된다고 한다. 하지만 앞서 언급한 것처럼 <code>new Fucntion()</code>은 보안상의 문제가 발생할 가능성이 있기에 신중하게 사용되어야 한다고 한다. </p>
<pre><code class="language-js">const input = &#39;2 + 3&#39;;

const result = new Function(`return ${input}`)();
console.log(result); // 5</code></pre>
<p>계산기 구현에서 사용된 코드를 짧게 표현한 예시이다. 사용자가 숫자 버튼과 연산자 버튼을 누르면 input 변수에 저장이 되고, <code>=</code> 대입연산자 버튼을 클릭했을 때  new Function의 인자로 input이 들어가고 동적으로 새로움 함수를 생성하여 반환값이 result에 저장되고 저장된 result의 데이터가 화면에 표시된다. </p>
<blockquote>
<p>중요한 부분은 함수이기 때문에 꼭 <code>return</code> 작성해야한다는 것. </p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Core Js] 클로저와 메모리 관리]]></title>
            <link>https://velog.io/@haron-lee/Core-Js-%ED%81%B4%EB%A1%9C%EC%A0%80%EC%99%80-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B4%80%EB%A6%AC</link>
            <guid>https://velog.io/@haron-lee/Core-Js-%ED%81%B4%EB%A1%9C%EC%A0%80%EC%99%80-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B4%80%EB%A6%AC</guid>
            <pubDate>Sat, 27 May 2023 11:18:07 GMT</pubDate>
            <description><![CDATA[<h1 id="클로저와-메모리-관리">클로저와 메모리 관리</h1>
<h2 id="메모리-누수란">메모리 누수란?</h2>
<p>자바스크립트 에서는 가비지 컬렉션(Garbage Collection)이 동작하여 더이상 참조하지 않는 메모리를 해제한다. 근데 개발자의 의도와 달리 어떤 값이 참조 카운트가 0이 되지 않아 GC(Garbage Collector)의 수거 대상이 되지 않는 경우를 메모리 누수가 일어난다고 한다. 보통 참조 계층이 형성되면 가비지 컬렉션이 작동하지 못하고 발생하곤 한다. 그 외에도 비 객체를 참조하거나 서로를 참조하는 경우 메모리 누수가 발생하기도 한다. </p>
<br>

<h3 id="메모리-누수가-발생하는-경우">메모리 누수가 발생하는 경우</h3>
<pre><code class="language-js">function createLeak() {
  let element = document.createElement(&#39;div&#39;);

  // 아래의 코드에서 element를 참조하고 있다.
  // 아래의 코드가 존재하는 한 element는 가비지 컬렉션의 대상이 되지 않는다.
  element.onclick = function() {
     alert(&#39;클릭 된 엘리먼트: &#39; + element.id);
   }
  // element가 DOM에서 제거되어도 참조하고 있는 이벤트 핸들러 때문에 가비지 컬렉션 대상이 되지 않는다. 
  document.body.appendChild(element);
}

// createLeak 함수를 호출하면 div element를 생성하고 이벤트 처리를 위한 함수를 등록한다.
createLeak();
</code></pre>
<p>위 예시 코드에서 createLeak 함수는 element를 생성하고 이벤트 핸들러를 등록하고 있다. 등록한 이벤트 핸들러가 실행되면서 element를 참조하고 있다. 이 상황에서 해당 element를 삭제하면 이벤트 핸들러가 여전히 element를 참조하기 때문에 메모리 누수가 발생한다. </p>
<br>

<h3 id="메모리-누수를-차단하기">메모리 누수를 차단하기</h3>
<pre><code class="language-js">function createLeak() {
  let element = document.createElement(&#39;div&#39;);

  element.onclick = function() {
    alert(&#39;클릭 된 엘리먼트: &#39; + element.id);
  }
  // onclick 이벤트에 null을 추가 하여 참조를 제거하기 
  element.onclick = null;
 }

  createLeak();</code></pre>
<p>위 예시 코드와 같이 createLeak 함수를 호출하면 element를 생성한 후에 이벤트 핸들러에 대한 참조를 제거할 수 있다. </p>
<br>
<br>

<h2 id="클로저의-메모리-관리방법">클로저의 메모리 관리방법</h2>
<blockquote>
<p>클로저는 어떤 필요에 의해 의도적으로 함수의 지역변수를 메모리를 소모하도록 함으로써 발생한다. 그렇다면 그 필요성이 사라진 시점에는 더는 메모리를 소모하지 않게 해주면 된다. 참조 카운트를 0으로 만들면 언젠가 GC가 수거할 것이고, 이때 소모했던 메모리가 회수 된다. <code>참조 카운트를 0으로 만드는 방법은 식별자에 참조형이 아닌 기본형 데이터 (null, undefined)를 할당</code>하면 된다. </p>
</blockquote>
<br>

<h3 id="1-return에-의한-클로저의-메모리-해제">(1) return에 의한 클로저의 메모리 해제</h3>
<pre><code class="language-js">let outer = function () {
  let a = 1;
  let inner = function () {
    return ++a;
  };
  return inner;
};

let outer2 = outer1;
console.log(outer2()); // 2
console.log(outer2()); // 3</code></pre>
<p>위 코드 예제는 클로저를 이용하여 생성된 내부 함수에서 외부 변수를 참조하고 있다. </p>
<ul>
<li>먼저 outer함수가 실행될 때, a 변수와 inner 함수가 생성된다. </li>
<li>inner 함수는 a 변수를 참조하고 있으므로 inner 함수가 반환 되고 outer 함수가 종료되더라도 a 변수가 메모리에 살아있게 된다. 이것이 클로저에 의한 동작 방식이기도 하다.</li>
<li>outer 함수에서 생성한 inner 함수가 outer2 변수에 할당되어 참조된다.</li>
<li>즉, outer2 변수를 통해 inner 함수를 호출하면, 내부의 자유 변수 a가 증가한 뒤, 반환 된다.</li>
<li>이때 outer2 변수가 inner 함수를 참조하고 있으므로 inner 함수와 a 변수에 대한 참조가 지속된다.</li>
</ul>
<pre><code class="language-js">let outer = function () {
  let a = 1;
  let inner = function () {
    return ++a;
  };
  return inner;
};

let outer2 = outer1;
console.log(outer2()); // 2
console.log(outer2()); // 3

outer = null;</code></pre>
<p>마지막에 <code>outer = null</code>을 할당하여 outer 변수가 참조하고 있는 함수 객체와 그 안에서 참조하고 있는 변수들에 대한 참조가 모두 제거 된다. 이렇게 명시적으로 참조를 제거하면 더이상 해당 객체에 접근할 수 없게 된다. </p>
<br>

<h3 id="2-setinterval에-의한-클로저-메모리-해제">(2) setInterval에 의한 클로저 메모리 해제</h3>
<pre><code class="language-js">(function () {
  let a = 0;
  let intervalId = null;
  let inner = function () {
    if (++a &gt;= 10) {
      clearInterval(intervalId);
    }
    console.log(a);
  };
  intervalId = setInterval(inner, 1000);
})();</code></pre>
<p>위 예시 코드는 즉시 실행 함수(IIFE)를 활용하여 inner 함수를 1초마다 실행하면서 a 변수를 1씩 증가시키는 예제이다. </p>
<ul>
<li><code>(function() { ... })()</code> 즉시 실행 함수로 함수 내부에 a 변수, intervalId 변수, Inner 함수를 정의하고 setInterval 함수를 사용하여 inner 함수를 1초마다 실행한다.이때, 반환되는 intervalId 값을 intervalId 변수에 할당한다.</li>
<li>inner 함수 내부에 정의된 변수 a를 0으로 초기화한다.</li>
<li>intervalId 변수를 null로 초기화한다.</li>
<li>inner 함수를 정의한다. 함수 내부에서는 a 변수를 1씩 증가시키고, a 변수의 값이 10 이상이 되면 setInterval 함수로 반환된 intervalId 값을 사용하여 setInterval 타이머를 종료한다.</li>
<li>inner 함수를 1초마다 실행하는 타이머를 설정한다. setInterval 함수는 inner 함수의 실행 결과를 반환하지 않으므로, intervalId 변수를 사용하여 타이머를 중지 시킬 수 있도록 한다. </li>
</ul>
<pre><code class="language-js">(function () {
  let a = 0;
  let intervalId = null;
  let inner = function () {
    if (++a &gt;= 10) {
      clearInterval(intervalId);
      inner = null;
    }
    console.log(a);
  };
  intervalId = setInterval(inner, 1000);
})();</code></pre>
<p>a 변수의 값이 10 이상이 되면 setInterval 함수로 반환된 intervalId 값을 사용하여 setInterval 타이머를 종료하고 inner 함수가 가리키고 있는 a 변수에 대한 참조를 <code>inner = null</code>로 제거하여 메모리 누수를 방지할 수 있다. </p>
<br>

<h3 id="3-eventlistener에-의한-클로저의-메모리-해제">(3) eventListener에 의한 클로저의 메모리 해제</h3>
<pre><code class="language-js">(function () {
  let count = 0;
  let button = document.createElement(&#39;button&#39;);
  button.innerText = &#39;Click&#39;;

  let clickHandler = function () {
    console.log(++count, &#39;times clicked&#39;);
    if (count &gt;= 10) {
      button.removeEventListener(&#39;click&#39;, clickHandler);
    }
  };
  button.addEventListener(&#39;click&#39;, clickHandler)
  document.body.appendChild(button);
})();
</code></pre>
<p>위 예시 코드는 Click이라는 텍스트를 가진 button을 동적으로 생성하고, 클릭 이벤트 발생 시 클릭 횟수를 콘솔에 출력하고 클릭 횟수가 10 이상일 경우 클릭 이벤트 핸들러를 제거하는 즉시 실행 함수(IIFF)이다. </p>
<ul>
<li>즉시 실행 함수로 함수 내부에 count 변수, button 변수, clickHandler 함수를 정의한다.</li>
<li>count 변수를 0으로 초기화 한다. count 변수는 클릭 횟수 저장을 담당한다.</li>
<li>button element를 생성한다. </li>
<li>button에 &#39;Click&#39;이라는 텍스트를 할당한다.</li>
<li>클릭 이벤트를 처리하는 clickHandler 함수를 정의한다. 이 함수는 클릭 된 횟수를 콘솔에 출력하고, 클릭 횟수가 10 이상이 되면 button에 등록된 click 이벤트 핸들러를 제거한다.</li>
<li>clickHandler 함수를 클릭 이벤트의 콜백 함수로 등록하여 button이 클릭 될 때마다 클릭 수를 콘솔에 남긴다.</li>
</ul>
<pre><code class="language-js">(function () {
  let count = 0;
  let button = document.createElement(&#39;button&#39;);
  button.innerText = &#39;Click&#39;;

  let clickHandler = function () {
    console.log(++count, &#39;times clicked&#39;);
    if (count &gt;= 10) {
      button.removeEventListener(&#39;click&#39;, clickHandler);
      clickHandler = null;
    }
  };
  button.addEventListener(&#39;click&#39;, clickHandler)
  document.body.appendChild(button);
})();
</code></pre>
<p><code>clickHandler = null</code>은 clickHandler 함수를 참조하는 변수를 null로 설정하여 clickHandler 함수에 대한 참조를 제거한다. removeEventListener 함수가 호출되면서 현재 클릭 핸들러 함수가 해당 버튼에서 제거 된다. 그 후에 clickHandler 변수가 null로 설정되면 GC의 수거 대상이 되어 수거된다. 이렇게 함으로 메모리 누수를 방지할 수 있다. </p>
<blockquote>
<p>메모리 누수를 제거하는 것은 자원 이용에 있어서 가장 중요한 것 중 하나이다. 메모리 누수가 발생하면 시스템 자원에 한계에 이를 수 있고, 이는 system crash와 같은 치명적인 문제를 초래할 수 있다. 따라서 메모리 누수를 방지하고 지속적인 메모리 사용량을 모니터링 함으로써, 시스템의 안정성과 성능을 극대화 할 수 있다. </p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Core JS] 콜백 함수는 함수다]]></title>
            <link>https://velog.io/@haron-lee/Core-JS-%EC%BD%9C%EB%B0%B1-%ED%95%A8%EC%88%98%EB%8A%94-%ED%95%A8%EC%88%98%EB%8B%A4</link>
            <guid>https://velog.io/@haron-lee/Core-JS-%EC%BD%9C%EB%B0%B1-%ED%95%A8%EC%88%98%EB%8A%94-%ED%95%A8%EC%88%98%EB%8B%A4</guid>
            <pubDate>Sat, 20 May 2023 15:29:33 GMT</pubDate>
            <description><![CDATA[<h1 id="콜백-함수는-함수다">콜백 함수는 함수다</h1>
<p>콜백 함수는 인수로 다른 함수에 전달되어, 외부 함수에서 호출되는 함수이다.</p>
<pre><code class="language-js">// 콜백 함수 예시 
const btn = document.querySelector(&#39;button&#39;);

function handleLog () {
  return console.log(&#39;함수다!&#39;);
}

btn.addEventListener(&#39;click&#39;, handleLog)

// button 클릭시 콘솔에 &#39;함수다!&#39;가 출력.</code></pre>
<p>콜백 함수는 우리가 알게 모르게 많이 사용되고 있다. 코어 자바스크립트 4-3의 콜백 함수는 함수다에는 아래와 같은 문장이 나온다. </p>
<blockquote>
<p>콜백 함수로 어떤 객체의 메서드를 전달하더라도 그 메서드는 메서드가 아니라 함수로서 호출된다.</p>
</blockquote>
<p>어떤의미일까?
앞서 얘기했듯 콜백 함수는 다른 함수에 인자로 전달되어서 외부함수에서 호출 되는 함수라고 이야기 했었다. 외부함수에서 호출 될 때는 특정 이벤트 또는 조건에 따라 실행된다. 이때 콜백 함수를 객체의 메서드로 전달하면 해당 메서드를 함수로 전달하게 된다. 따라서 해당 메서드를 호출할 때는 해당 객체의 메서드가 아닌, 함수로서 실행된다.</p>
<p>아래는 메서드를 콜백 함수로 전달한 경우의 예시</p>
<pre><code class="language-js">const myObject = {
  number: [1, 2, 3],
  printNumber: function(n) {
    console.log(this, n);
  }
};

myObject.printNumber(10); 
// 출력 결과 
// {number: Array(3), printNumber: ƒ} 10

[10, 20, 30].forEach(myObject.printNumber);
// 출력 결과
// window{ ... } 10
// window{ ... } 20
// window{ ... } 30</code></pre>
<p><code>[10, 20, 30].forEach(myObject.printNumber);</code> 부분을 보면 myObject의 메서드를 콜백 함수로 전달하더라도 메서드가 아닌 함수로서 호출되는 것을 알 수 있다. 그런데 this의 출력 결과를 보면, 해당 함수 내부에서 this에 접근하면 객체 자체(myObject)가 아닌 전역 객체(window)를 참조하게 되어 window를 출력하는 것을 볼 수 있다. 점(.)으로 호출 되었기 때문에 메서드로서 호출되어 바로앞의 객체를 this가 가리킨다고 예상했지만 예상과는 다른 결과이다. </p>
<p><code>[10, 20, 30].forEach(myObject.printNumber)</code>에서 <code>myObject.printNumber</code>는 객체 myObject 내부의 메서드이지만, forEach() 메서드의 실행에 따라 메서드의 컨텍스트가 바뀌기 때문에 window 객체에서 실행된다. forEach() 메서드를 실행하는 동안, 내부에서 <code>myObject.printNumber</code> 메서드를 콜백 함수로 전달하면, 자바스크립트 엔진은 forEach() 메서드의 두 번째 인수인 thisArg를 컨텍스트로 사용한다. 따라서 별도로 컨텍스트를 지정하지 않으면, 전역 객체인 window 객체가 컨텍스트로 사용된다.</p>
<p>이를 방지하기 위해서는 함수를 호출할 때 this를 함께 전달하는 방법이 있거나, 함수 내부에서 this를 bind를 이용하여 객체로 바인딩하는 방법이 있다.</p>
<p>다음과 같이 코드를 작성할 수 있다.</p>
<pre><code class="language-js">[10, 20, 30].forEach(myObject.printNumber.bind(myObject));
</code></pre>
<p><code>bind()</code> 메서드를 사용하여 <code>myObject.printNumber()</code> 메서드의 컨텍스트를 항상 myObject로 설정하면, forEach() 메서드에서도 myObject 객체가 컨텍스트로 사용된다.</p>
<blockquote>
<p>결국 어떤 함수의 인자에 객체의 메서드를 전달하더라도 이는 결국 메서드가 아닌 함수일 뿐이다. 이 차이를 이해하는 것이 중요하다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[프로그래머스 0lv] 삼각형의 완성조건 (1)
]]></title>
            <link>https://velog.io/@haron-lee/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-0lv-%EC%82%BC%EA%B0%81%ED%98%95%EC%9D%98-%EC%99%84%EC%84%B1%EC%A1%B0%EA%B1%B4-1</link>
            <guid>https://velog.io/@haron-lee/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-0lv-%EC%82%BC%EA%B0%81%ED%98%95%EC%9D%98-%EC%99%84%EC%84%B1%EC%A1%B0%EA%B1%B4-1</guid>
            <pubDate>Thu, 20 Apr 2023 15:16:57 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-설명">문제 설명</h2>
<p>문제 설명
선분 세 개로 삼각형을 만들기 위해서는 다음과 같은 조건을 만족해야 합니다.</p>
<p>가장 긴 변의 길이는 다른 두 변의 길이의 합보다 작아야 합니다.
삼각형의 세 변의 길이가 담긴 배열 sides이 매개변수로 주어집니다. 세 변으로 삼각형을 만들 수 있다면 1, 만들 수 없다면 2를 return하도록 solution 함수를 완성해주세요.</p>
<br>

<h3 id="제한사항">제한사항</h3>
<p>sides의 원소는 자연수입니다.
sides의 길이는 3입니다.
1 ≤ sides의 원소 ≤ 1,000</p>
<br>

<h3 id="입력예시">입력예시</h3>
<pre><code class="language-js">const sides = [1, 2, 3]; // 2

const sides2 = [3, 6, 2]; // 2

const sides3 = [199, 72, 222]; // 2</code></pre>
<br>

<h3 id="나의-처음-풀이">나의 처음 풀이</h3>
<pre><code class="language-js">function solution(sides) {
  var answer = 0;
  let max = Math.max(...sides); // 가장 큰 수 저장

  answer = sides.filter((el) =&gt; el &lt; max).reduce((a, b) =&gt; a + b, 0);
    // 가장 큰 수 보다 작은 요소들 걸러서 더 해주기

  return answer &gt; max ? 1 : 2; // 비교하기 
}</code></pre>
<h3 id="입력예시-1">입력예시</h3>
<p>아래의 입력값은 통과 </p>
<pre><code class="language-js">const sides = [1, 2, 3];
solution(sides); // 2
const sides2 = [3, 6, 2];
solution(sides2); // 2
const sides3 = [199, 72, 222];
solution(sides3); // 1</code></pre>
<br>

<h3 id="반례">반례</h3>
<p>큰 수와 같은 수가 있을 경우 반례가 존재했다. 
출력 값은 1이 나와야하지만 2가 나오는 상황. </p>
<pre><code class="language-js">const sides4 = [3,3,2];
solution(sides4); // 2</code></pre>
<br>

<p>이유는 아래의 <code>filter</code> 에서 max보다 작은 값을 걸러 주었기 때문에, [3, 3, 2]의 경우 [2]만 반환 되었기 때문이다. </p>
<pre><code class="language-js">  answer = sides.filter((el) =&gt; el &lt; max).reduce((a, b) =&gt; a + b, 0);</code></pre>
<p>그래서 <code>filter</code>를 빼주기로 했다. </p>
<br>

<h3 id="수정-풀이">수정 풀이</h3>
<pre><code class="language-js">function solution(sides) {
  var answer = 0;
  let max = Math.max(...sides); // 가장 큰 수 저장

  answer = sides.reduce((a, b) =&gt; a + b, 0);
    // sides 배열 다 더해주기 

  return (answer - max) &gt; max ? 1 : 2; 
    // answer - max 값이 max보다 크다면 1, 작다면 2 
}</code></pre>
<p>max 값은 저장해두고, 입력되는 배열의 모든 값을 <code>reduce</code>로 다 더해 answer로 반환, answer - max가 max 보다 크다면 1, 작다면 2를 출력한다. </p>
<br>

<h3 id="프로그래머스-다른-풀이">프로그래머스 다른 풀이</h3>
<pre><code class="language-js">function solution(sides) {
    sides = sides.sort((a,b) =&gt; a-b)
    return sides[0]+sides[1] &gt; sides[2] ? 1 : 2;
}</code></pre>
<p>더 간단하게 풀 수 있었다! 외워두기</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Git] remote: fatal error in commit_refs]]></title>
            <link>https://velog.io/@haron-lee/Git-remote-fatal-error-in-commitrefs</link>
            <guid>https://velog.io/@haron-lee/Git-remote-fatal-error-in-commitrefs</guid>
            <pubDate>Mon, 27 Mar 2023 13:10:55 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/haron-lee/post/5ca5ce56-8b88-4c31-ade7-8d5dd0759ab4/image.png" alt=""></p>
<h2 id="문제발생">문제발생</h2>
<pre><code>remote: fatal error in commit_refs
! [remote rejected] main -&gt; main (failure)
error: failed to push some refs to blah blah</code></pre><h3 id="해결방안">해결방안</h3>
<p>전에도 비슷한 오류가 있었기 때문에 또 원격저장소에서 뭔가 변경이 있어서 <code>git pull</code> 을 하고 다시 <code>git push</code> 를 해보았지만 실패. 열심히 구글링 후에 찾은 결과이다. 20분이상 씨름했는데 생각보다 허탈했던 👀</p>
<pre><code>Gibhub 서버오류로 서버가 정상화 되면 다시 정상으로 동작</code></pre><p><a href="https://stackoverflow.com/questions/37341960/how-do-i-fix-remote-fatal-error-in-commit-refs-errors-trying-to-push-with-git">참고</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Git error] ! [rejected] main -> main (fetch first)]]></title>
            <link>https://velog.io/@haron-lee/Git-error-rejected-main-main-fetch-first</link>
            <guid>https://velog.io/@haron-lee/Git-error-rejected-main-main-fetch-first</guid>
            <pubDate>Wed, 08 Mar 2023 15:07:46 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/haron-lee/post/464104ea-5794-4e60-b668-4d35aa073ee5/image.png" alt=""></p>
<p>오늘 만난 아주 당황스러운 친구! 🥲
하지만 에러는 언제나 환영이다!! 싸우자 Git!!! </p>
<br>

<h3 id="에러가-일어난-과정">에러가 일어난 과정</h3>
<pre><code>git commit -m &quot;fix dkfjdkjfk&quot;
git push </code></pre><p>commit 메세지를 작성하고 push를 했더니 위의 그림과 같은 에러가 등장했다. 읽어보고 곰곰히 생각해보니 <code>git commit</code> 하기 전에 github에서 README.md를 수정했었다. 원격저장소와 로컬저장소의 동기화 되지않아 데이터 손실이 우려되어 막은 것이다. 방법은 찾아보니 두가지 정도가 있었다. </p>
<br>

<ol>
<li><p>데이터의 안전을 위해 <code>pull</code></p>
<pre><code>git pull --rebase origin main</code></pre><br>
</li>
<li><p>데이터 손상 상관없다! push 해! 강제로 push 하기</p>
<pre><code>git push origin +master</code></pre></li>
</ol>
<br>

<h3 id="해결은">해결은</h3>
<p>나의 경우는 <code>README.md</code>를 수정했기에 중요사항이 없어서 2번으로 강제로 Push 하려했지만 실패하였다. 그래서 pull을 하여야하는데 로컬에서 변경했던 사항이 변경됨으로 변경했던 코드 부분만 복사해놓고 pull하고 코드 붙여넣고 다시 push를 진행했다! </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CSS Flex로 Card 만들기]]></title>
            <link>https://velog.io/@haron-lee/CSS-Flex%EB%A1%9C-Card-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@haron-lee/CSS-Flex%EB%A1%9C-Card-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Wed, 08 Mar 2023 14:56:06 GMT</pubDate>
            <description><![CDATA[<h2 id="flex를-이용해-card-만들기">Flex를 이용해 Card 만들기</h2>
<p>간단한 카드라고 생각했지만 처음 어떻게 디자인 박스를 구상하고 배치를 어떻게 하느냐를 많이 고민했던 것 같다. 유저 타이틀이 보이는 부분은 생각처럼 간단하지 않았다.</p>
<h3 id="과제-예시">과제 예시</h3>
<p>아래의 예시처럼 card를 만드는 과제였다. 
<img src="https://velog.velcdn.com/images/haron-lee/post/739b7e6a-a87e-45f1-a46f-fcfad367dc0d/image.png" alt=""></p>
<h3 id="결과물">결과물</h3>
<p><img src="https://velog.velcdn.com/images/haron-lee/post/a6cb6055-7259-4b96-8d3c-db6f2de13a93/image.png" alt=""></p>
<br>

<h3 id="issue-및-해결">Issue 및 해결</h3>
<p>일단 figma를 참고하지 않고 눈으로만 보고 만들어서 figma를 참고하는 방식을 연습해야 할 것 같다. </p>
<ul>
<li>user title 부분의 사진 부분 사이즈 맞지 않음<ul>
<li>user title 부분의 width가 넓어서 flex를 줬을 때 사진이 찌그러졌다. 이후 user title width를 변경하여 해결 완료 </li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[CSS Flex로 Layout 만들기]]></title>
            <link>https://velog.io/@haron-lee/CSS-Flex%EB%A1%9C-Layout-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@haron-lee/CSS-Flex%EB%A1%9C-Layout-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Wed, 08 Mar 2023 14:14:02 GMT</pubDate>
            <description><![CDATA[<h2 id="flex로-layout을-만들어보자">Flex로 layout을 만들어보자</h2>
<p>처음에는 <code>float: right</code>와 같이 <code>float</code>로 만들어보고 같은 과제를 <code>flex</code> 로 만들어보는 과제였다. </p>
<h3 id="과제-예시">과제 예시</h3>
<p>아래의 예시처럼 레이아웃을 flex로 만들어본다. 브라우저 전체 면적을 사용했다. 
<img src="https://velog.velcdn.com/images/haron-lee/post/a574ab7c-35e0-409f-9a42-904758dffdc0/image.png" alt=""></p>
<pre><code class="language-html">&lt;body&gt;
    &lt;header&gt;header&lt;/header&gt;
    &lt;div class=&quot;wrap&quot;&gt;
      &lt;section&gt;section&lt;/section&gt;
      &lt;aside&gt;aside&lt;/aside&gt;
    &lt;/div&gt;
    &lt;footer&gt;footer&lt;/footer&gt;
  &lt;/body&gt;</code></pre>
<pre><code class="language-css">body {
        margin: 0;
        width: 100vw;
        height: 100vh;
        color: white;
        font-size: 2rem;
        box-sizing: border-box;
        display: flex;
        flex-direction: column;
        gap: 10px;
      }

      header,
      section,
      aside,
      footer {
        display: flex;
        justify-content: center;
        align-items: center;
      }

      header {
        background-color: blueviolet;
        height: 100px;
      }

      .wrap {
        display: flex;
        width: 100%;
        height: 100%;
        gap: 10px;
      }

      section {
        background-color: royalblue;
        flex-grow: 2;
      }

      aside {
        background-color: burlywood;
        flex-grow: 1;
      }

      footer {
        background-color: lightcoral;
        height: 100px;
      }</code></pre>
<br>

<h3 id="결과물">결과물</h3>
<p><img src="https://velog.velcdn.com/images/haron-lee/post/abd5d3a1-52b0-41fb-90ef-bfdbb16ec1df/image.png" alt=""></p>
<br>

<h3 id="issue-및-해결-방법">Issue 및 해결 방법</h3>
<p>body에 <code>width:100vw</code> <code>height:100vh</code>가 적용되어있는 상태에서 <code>margin:0</code> 을 주기전까지는 스크롤바가 생기는 현상이 발생했다. 기본 브라우저의 margin 값때문에 그런 것 같았다. 달리 다른 해결방법은 찾지 못했다. 다른 방법을 찾는다면 다시 기록하자! 지금은 <code>margin:0</code>으로 해결! </p>
<blockquote>
<ul>
<li>참고 stackoverflow
<a href="https://stackoverflow.com/questions/44645465/when-using-height-100vh-for-the-container-vertical-scrollbar-appears">https://stackoverflow.com/questions/44645465/when-using-height-100vh-for-the-container-vertical-scrollbar-appears</a></li>
</ul>
</blockquote>
<br>

<h3 id="몰랐던-것은">몰랐던 것은?</h3>
<p>flex에도 gap을 줄 수 있다는 건 처음 알게되었다. grid에서만 사용한다고 생각했는데 각 아이템에 마진을 따로 주지 않고도 손쉽게 gap으로 줄 수 있었다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CSS Flex 하게 ]]></title>
            <link>https://velog.io/@haron-lee/CSS-Flex-%ED%95%98%EA%B2%8C</link>
            <guid>https://velog.io/@haron-lee/CSS-Flex-%ED%95%98%EA%B2%8C</guid>
            <pubDate>Wed, 08 Mar 2023 14:00:36 GMT</pubDate>
            <description><![CDATA[<h1 id="flex란">Flex란?</h1>
<p><code>display: flex</code> 란 요소들을 유연하게 배치하기 위한 display 속성이다. flex를 사용하면, 부모 요소 안에서 자식 요소들이 차지하는 공간을 유동적으로 조정하고, 좌우나 상하, 가운데로 정렬할 수 있다. </p>
<h2 id="flex-속성">Flex 속성</h2>
<h3 id="flex-direction">flex-direction</h3>
<p>컨테이너 내에서 아이템의 주 축(main axis)를 설정한다. </p>
<ul>
<li>row: 기본값</li>
<li>row-reverse: 우에서 좌 방향</li>
<li>column: 세로, 위에서 아래</li>
<li>column-reverse: 아래에서 위로 </li>
</ul>
<pre><code class="language-css">div {
    display: flex;
    flex-direction: column;
}</code></pre>
<br>

<h3 id="flex-wrap">flex-wrap</h3>
<p>flex 안의 아이템들이 한 줄에 다 들어가지 않을 경우, 아이템들을 여러 줄로 나눌 것인지 결정한다.</p>
<ul>
<li>nowrap: 기본값, 한줄 배치</li>
<li>wrap: 여러 줄로 나누어 배치 </li>
</ul>
<pre><code class="language-css">div {
    display: flex;
    flex-wrap: wrap;
}</code></pre>
<br>

<h3 id="justify-content">justify-content</h3>
<p>컨테이너의 주 축을 기준으로 아이템들을 정렬한다. 가로 방향. </p>
<ul>
<li>flex-start: 기본값, 시작점에 정렬 </li>
<li>flex-end: 끝나는 지점에 정렬, 왼쪽이 시작점이면 오른쪽 끝으로 정렬</li>
<li>center: 가운데 정렬</li>
<li>space-between: 양쪽 끝 아이템들은 끝으로 배치, 그 가운데는 균등한 간격이 들어감</li>
<li>space-around: 아이템 주위에 균등한 가격을 둔다.</li>
<li>space-evenly: 아이템 사이와 주위 모두 균등한 간격을 둔다. </li>
</ul>
<pre><code class="language-css">div {
    display: flex;
    justify-content: center;
}</code></pre>
<br>

<h3 id="align-items">align-items</h3>
<p>flex 컨테이너의 교차 축(cross axis)를 기준으로 아이템들을 정렬한다. 세로 방향.</p>
<ul>
<li>flex-start: 기본값, 시작점에 정렬</li>
<li>flex-end: 끝나는 지점에 정렬, 왼쪽 위가 시작점이면 왼쪽 아래로 정렬</li>
<li>center: 중앙</li>
<li>baseline: 아이템의 기준선 </li>
<li>stretch: 교차 축을 채우기 위해 아이템을 그에 맞게 늘린다. </li>
</ul>
<pre><code class="language-css">div {
    display: flex;
    align-items: flex-end;
}</code></pre>
<br>

<h3 id="align-content">align-content</h3>
<p><code>flex-wrap: wrap</code> 이 적용 되었을 경우, flex 컨테이너 내에서 여러 줄들 사이의 간격을 조절한다. </p>
<ul>
<li>stretch: 기본값, 줄 사이의 간격을 늘린다.</li>
<li>flex-start</li>
<li>flex-end</li>
<li>center</li>
<li>space-between</li>
<li>space-around</li>
</ul>
<pre><code class="language-css">div {
    display: flex;
    align-content: space-between;
}</code></pre>
<br>

<h3 id="flex-grow">flex-grow</h3>
<p>아이템들이 컨테이너 내에서 차지하는 공간 비율을 정한다. 값이 클수록 많은 공간을 차지한다. 값을 0으로 줄 경우 늘어나지 않는다. 컨테이너 너비에 맞게 아이템들의 크기가 분배된다. </p>
<blockquote>
<p><code>flex-basis:0</code> 을 주게 되면 여백 공간이 아닌 전체 공간을 분할한다. </p>
</blockquote>
<pre><code class="language-css">.container {
  display: flex;
  width: 400px;
  height: 200px;
}

.item {
  height: 100px;
  background-color: gray;
  border: 1px solid black;
  flex-grow: 1;
}</code></pre>
<p>위의 경우 
<br></p>
<h3 id="flex-shrink">flex-shrink</h3>
<p>아이템의 크기를 고정하거나 축소할 때 사용한다. 값이 클수록 적은 공간을 사용한다. 값을 0을 줄경우 줄어들지 않는다. </p>
<pre><code class="language-css">.container {
  display: flex;
  flex-wrap: wrap;
  width: 300px; 
  height: 200px;
}

.item {
  width: 150px;
  height: 100px;
  background-color: gray;
  border: 1px solid black;
  flex-shrink: 1;
}</code></pre>
<p>위의 경우 너비가 300px로 아이템은 150px을 가지기에 2개가 한 줄 나열된다.만약 컨테이너의 너비가 250px로 줄경우 item의 크기는 shrink 속성이 적용 되어 item의 너비가 줄어든다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CSS Box Model 만들기]]></title>
            <link>https://velog.io/@haron-lee/CSS-Box-Model-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@haron-lee/CSS-Box-Model-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Sun, 05 Mar 2023 14:46:21 GMT</pubDate>
            <description><![CDATA[<h2 id="box를-직접-만들어보자">Box를 직접 만들어보자</h2>
<p>이전 글의 내용을 토대로 박스를 직접 만드는 과제를 받았다. 과제를 하면서 모르는 부분은 구글링하며 새로운 속성들도 알게 되는 시간이었다. </p>
<p><img src="https://velog.velcdn.com/images/haron-lee/post/7dd6f376-f431-4ee7-9ad5-fd7108e11095/image.png" alt=""></p>
<h3 id="만든-과정">만든 과정</h3>
<pre><code class="language-css">    &lt;style&gt;
        div {
            margin: 0 auto;
            padding: 4px 8px;
            width: 110px;
            height: 40px;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 1.2rem;
            font-weight: bold;
            margin-bottom: 20px;
        }

        div:hover {
            cursor: pointer;
        }

        /* 첫번째 박스 */
        div:first-child {
            color: white;
            background-color: #343f50;
            border-top: 1px solid #4a5568;
            border-left: 1px solid #4a5568;
            box-shadow: 0 0 0 1px #000;
        }

        /* 두번째 박스 */
        div:nth-child(2) {
            background: linear-gradient(to left,#824EEC, #4469E9); /* 그라디언트 */
            color: #fff;
            outline: 2px dashed #dfdfdf; /* 외곽선 사용 */
            border-radius: 20px;
        }

        /* 세번째 박스 */
        div:nth-child(3) {
            background-color: #fff;
            color: #222222;
            border: 1px solid #EEEEEE;
            border-radius: 0px 20px 20px 20px;
            box-shadow: 3px 3px 2px  rgba(0, 0, 0, 0.1);
        }

    &lt;/style&gt;</code></pre>
<br>

<h3 id="완성된-모습">완성된 모습</h3>
<p><img src="https://velog.velcdn.com/images/haron-lee/post/0b1e78f9-6c2c-46a5-9e9f-1b6c7a8a2e72/image.png" alt=""></p>
<br>

<h3 id="새로-알게-된-것">새로 알게 된 것</h3>
<ul>
<li><code>outline</code> 요소<ul>
<li>border와 달리 요소의 크기나 위치에 영향을 주지 않는다. 시각적인 표시를 나타내기 위해 사용.</li>
<li>outline-width : 외곽선 너비 지정. 기본값은 <code>midium</code></li>
<li>outline-style : 외곽선 스타일. <code>none</code>, <code>dotted</code>, <code>dashed</code>, <code>solid</code>, <code>double</code>, <code>groove</code>, <code>ridge</code>, <code>inset</code>, <code>outset</code> 등의 값이 있다. 기본값은 <code>none</code></li>
<li>outline-color : 외곽선의 색상 지정. 기본값은 현재 요소의 텍스트 색상</li>
<li>outline-offset : 외곽선의 거리를 지정. 기본값은 0</li>
</ul>
</li>
</ul>
<pre><code class="language-css">div {
    outline: 2px dotted blue;
    outline-offset: 10px;
 }</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[CSS Box Model ]]></title>
            <link>https://velog.io/@haron-lee/CSS-Box-Model</link>
            <guid>https://velog.io/@haron-lee/CSS-Box-Model</guid>
            <pubDate>Sun, 05 Mar 2023 14:22:42 GMT</pubDate>
            <description><![CDATA[<h2 id="css-box-model이란">CSS Box Model이란?</h2>
<p>웹 페이지의 레이아웃을 구성하는 핵심 개념 중 하나로, HTML요소가 화면에서 어떻게 위치하고 크기를 가지는 지를 결정한다. Box Model은 HTML 요소를 둘러싸고 있는 상자(Box)를 의미한다. 이 Box는 크게 네가지로 나눠볼 수 있다.</p>
<ul>
<li>Content : 요소의 실제 내용이 표기 </li>
<li>Padding : Content 영역과 Border 영역 사이</li>
<li>Border : Padding 영역과 Margin 영역 사이</li>
<li>Margin : 요소와 다른 요소 사이, 간격을 설정</li>
</ul>
<p><img src="https://velog.velcdn.com/images/haron-lee/post/30ccda57-b1e9-45f0-b91d-828e836bc476/image.png" alt=""></p>
<blockquote>
<p>CSS Box Model은 block에만 적용 된다. inline box는 일부 동작만 사용된다.
inline 요소는 width, height, 상하 margin 값이 적용되지 않는다. </p>
</blockquote>
<br>

<h3 id="width">width</h3>
<p>요소의 가로 크기를 지정한다. 기본값은 <code>auto</code>이다. <code>%</code>나 <code>px</code>,<code>rem</code>,<code>em</code> 등의 단위를 사용하여 크기를 지정할 수 있다. </p>
<ul>
<li><code>min-width</code> 최소 크기 </li>
<li><code>max-width</code> 최대 크기 </li>
</ul>
<pre><code class="language-css">body {
    width: 100vw;
    }</code></pre>
<br>

<h3 id="height">height</h3>
<p>요소의 세로 크기를 지정한다. width와 마찬가지로 기본값은 <code>auto</code>이다. <code>%</code>나 <code>px</code>,<code>rem</code>,<code>em</code> 등의 단위를 사용하여 크기를 지정할 수 있다. </p>
<br>

<h3 id="padding">padding</h3>
<p>요소의 내부 여백을 지정한다. 컨텐츠 영역과 border 영역 사이의 간격을 조절하는 데 사용
아래는 padding 작성방법이다. margin도 동일 하다. </p>
<pre><code class="language-css">div {
    padding: 10px; /* 상하좌우 전체 적용 */
    padding: 10px 5px; /* 상하, 좌우 적용 */
    padding: 5px 2px 3px 4px; /* 상, 우, 하, 좌 시계 방향 순서로 적용 */

    /* top,bottom,right,left 로 따로 적용시켜 줄 수 있다 */
    padding-top: 5px;
    padding-right: 2px;
    padding-bottom: 3px;
    padding-right: 4px; 
    }</code></pre>
<br>

<h3 id="margin">margin</h3>
<p>요소의 바깥쪽 여백을 지정한다. 요소와 주변 요소들 사이의 간격을 조정하는 데 사용된다. </p>
<ul>
<li>예시는 padding과 동일하다. </li>
</ul>
<h3 id="margin-병합-현상">margin 병합 현상</h3>
<p>요소와 요소 사이에 margin-top 혹은 margin-bottom의 공간이 있을 경우 더 높은 값의 마진 값이 적용 되는 현상</p>
<ol>
<li>형제 요소 간 상하 마진이 겹칠 때</li>
<li>빈 요소의 상하 마진이 겹칠 때</li>
<li>부모 박스 바로 밑 자식 박스의 상하 마진이 겹칠 때 </li>
</ol>
<p><img src="https://velog.velcdn.com/images/haron-lee/post/ebc26daa-2948-4dfa-b3cf-8e7fe256d8a4/image.png" alt=""></p>
<p>해결 방법은 </p>
<ul>
<li>부모 요소에 <code>overflow</code> 속성 값을 적용 한다. </li>
<li>부모 요소에 <code>display: inline-block</code> 값을 적용한다. </li>
<li>부모 요소에 <code>border</code> 값을 적용한다.</li>
<li>부모 요소에 <code>display:flow-root</code>를 사용한다.<blockquote>
<p>가장 마음편한 방법은 브라우저 랜더링의 규칙이라 생각하고 병합 현상을 인식하고 그대로 사용하는 것.</p>
</blockquote>
</li>
</ul>
<br>

<h3 id="border">border</h3>
<p>요소의 테두리를 지정한다. 요소의 경계선을 설정하는 데 사용된다. <code>border</code>는 아래의 속성을 합쳐서 쓸 때 사용된다. </p>
<ul>
<li>border-width : 테두리의 두께를 정한다. 단위는 <code>px</code>, <code>em</code> 등 혹은 <code>thin</code>, <code>medium</code>, <code>thick</code>을 사용할 수도 있다.</li>
<li>border-style : 테두리의 스타일을 지정한다. <code>solid</code>, <code>dotted</code>, <code>dashed</code>, <code>double</code></li>
<li>border-color: 테두리의 색상을 지정한다. 값으로는 색상 이름, HEX,RGB, RGBA 등의 값이 올 수 있다. </li>
</ul>
<pre><code class="language-css">div {
    border: 2px solid black;
    }</code></pre>
<ul>
<li>border-radius : 요소의 모서리를 둥글게 만든다. <pre><code class="language-css">div {
  border-radius: 10px; /* 전체 적용 */
  border-radius: 10px 3px 2px 4px /* 왼쪽 상단, 오른쪽 상단, 오른쪽 하단, 왼쪽 하단 */</code></pre>
</li>
</ul>
<br>

<h3 id="box-sizing">box-sizing</h3>
<p>CSS에서 요소의 크기를 계산하는 방법을 지정하는 속성이다. </p>
<ul>
<li>content-box : 기본값, 요소의 너비와 높이는 box 크기 기준으로 고정, padding과 border 미포함</li>
<li>border-box : 요소의 너비와 높이는 box+padding+border 크기를 기준으로 계산, 크기를 미리 예측할 수 있어서 레이아웃 설계할 때 용이하다.</li>
</ul>
<pre><code class="language-css">.box {
    width: 200px;
    height: 100px;
    padding: 10px;
    border: 1px solid black;
    box-sizing: border-box;
    }</code></pre>
<br>

<h3 id="overflow">overflow</h3>
<p>요소의 컨텐츠가 요소 자체의 크기를 벗어날 때 어떻게 처리할지 지정하는 속성이다. </p>
<ul>
<li>visible : 기본값, 요소가 경계를 벗어나도 잘리지 않는다.</li>
<li>hidden : 컨텐츠가 요소의 경계를 벗어날 때 잘리고, 그 이상은 표시하지 않는다.</li>
<li>scroll : 컨텐츠가 요소의 경계를 벗어날 때 스크롤바를 사용한다.</li>
<li>auto : 컨텐츠가 요소의 경계를 벗어날 때 필요한 경우에만 스크롤바를 표시한다.</li>
</ul>
<pre><code class="language-css">div {
    width: 200px;
    height: 100px;
    overflow: scroll;
    }</code></pre>
<br>

<h3 id="background">background</h3>
<p>요소의 배경을 스타일링하는데 사용된다. </p>
<ul>
<li>background-color : 배경색</li>
<li>background-image : 배경 이미지</li>
<li>background-repeat : 배경 이미지의 반복 여부</li>
<li>background-position : 배경 이미지의 위치 지정</li>
<li>bakcground-size : 배경 이미지의 크기를 지정</li>
<li>background-attachment : 배경 이미지의 스크롤 여부 </li>
<li>background : 위의 속성들을 줄여서 사용</li>
</ul>
<pre><code class="language-css">div {
    background: #fff url(&#39;img.png&#39;) no-repeat center/cover fixed;
    }

div {
    background-color: #fff;
    background-image: url(&#39;img.png&#39;)
    background-repeat: no-repeat;
    backgrond-position: center;
    background-size: cover;
    background-attachment: fixed;
    }</code></pre>
<blockquote>
<p>이미지를 넣는 방법으론 HTML의 <code>&lt;img&gt;</code>와 CSS 방법이 있다. HTML의 <code>&lt;img&gt;</code>태그 사용을 권장한다. 이미지가 별다른 정보 제공의 역할 없이 시각적인 스타일의 기능만을 하거나 최적화를 고려할 정도의 크기가 아니라면 배경을 넣는 것을 권장한다. </p>
</blockquote>
<br>

<h3 id="box-shadow">box-shadow</h3>
<p>box에 그림자 효과를 추가한다. </p>
<ul>
<li>offset-x | offset-y | blur-radius | spread-radius | color</li>
</ul>
<pre><code class="language-css">div {
    box-shadow: 2px 2px 0px 0px #efefef;
    }</code></pre>
]]></description>
        </item>
    </channel>
</rss>