<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발여행의 블로그</title>
    <link>https://developerntraveler.tistory.com/</link>
    <description>' 우리가 무슨 생각을 하느냐가 우리가 어떤 사람이 되는지 를 결정한다 ' 
( What we dwell on is who we become. )</description>
    <language>ko</language>
    <pubDate>Sat, 4 Jul 2026 13:36:49 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>개발 여행</managingEditor>
    <image>
      <title>개발여행의 블로그</title>
      <url>https://tistory1.daumcdn.net/tistory/3912658/attach/87800e5ea42a496abd37dd0834e5b1a8</url>
      <link>https://developerntraveler.tistory.com</link>
    </image>
    <item>
      <title>[leetcode]1561. Maximum Number of Coins You Can Get</title>
      <link>https://developerntraveler.tistory.com/151</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/maximum-number-of-coins-you-can-get/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212121;&quot;&gt;1561&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212121;&quot;&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212121;&quot;&gt;Maximum Number of Coins You Can Get&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/maximum-number-of-coins-you-can-get/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://leetcode.com/problems/maximum-number-of-coins-you-can-get/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1649636086991&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Maximum Number of Coins You Can Get - LeetCode&quot; data-og-description=&quot;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/maximum-number-of-coins-you-can-get/&quot; data-og-url=&quot;https://leetcode.com/problems/maximum-number-of-coins-you-can-get/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bn6DQG/hyN0qoxXUC/RI7KRPzJkW8K292osPzbVk/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/maximum-number-of-coins-you-can-get/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/maximum-number-of-coins-you-can-get/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bn6DQG/hyN0qoxXUC/RI7KRPzJkW8K292osPzbVk/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Maximum Number of Coins You Can Get - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[ 문제 풀이 ]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에도 문제 파악하는데 시간이 많이 소요되었다. 여러 숫자가 섞인 3n개의 동전 더미에서 내가 선택할 수 있는 수 중 가장 최대 합을 구하는 문제이다. 문제의 조건은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 각 단계에서 3개의 동전 더미 선택(연속적일 필요는 없음)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 3개의 동전 더미에서 Alice는 가장 최대 수를 고를 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 나는 그 다음 최대 수를 고를 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Bob이 마지막 것을 고를 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음엔 문제가 잘 이해되지 않아 sorting 한 후 중복되는 수는 다시 자리를 바꾸고, &lt;span&gt;3n개씩 잘라&lt;span&gt; 그 중 가운데 수를 누적하는 방식으로 구성했다. 하지만 생각해보니, [9, 8, 7, 6, 5, 1, 2, 3, 4]일 때 정렬를 하면 [9, 8, 7,&amp;nbsp; 6, 5, 4, 3, 2, 1]이 되고, 그 중 가운데 수만 모두 합하면 [8, 5, 2]의 합 15가 최댓값이 된다. [9, 8, 1], [7, 6, 2], [5, 4, 3]으로 나누면 [8, 6, 4] 즉 18이 최댓값이 된다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;따라서 아래 코드와 같이 정렬 후 [9, 8, 7, 6, 5, 4] (인덱스 5)까지만 반복되도록 범위를 설정하고 짝수 번호의 인덱스만 result에 누적하여 더해주었다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[ 코드 ]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1649636032517&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * @param {number[]} piles
 * @return {number}
 */
const maxCoins = function (piles) {
  const sorted = piles.slice().sort((a, b) =&amp;gt; b - a);
  let result = 0;

  for (let i = 0; i &amp;lt; sorted.length - sorted.length / 3; i += 2) {
    result += sorted[i + 1];
  }

  return result;
};

// maxCoins([9, 8, 7, 6, 5, 1, 2, 3, 4]);
// output: 18&lt;/code&gt;&lt;/pre&gt;</description>
      <category>개발/Algorithm</category>
      <category>1561. Maximum Number of Coins You Can Get</category>
      <category>1561. Maximum Number of Coins You Can Get javascript</category>
      <category>1561. Maximum Number of Coins You Can Get js</category>
      <category>1561. Maximum Number of Coins You Can Get js solution</category>
      <category>leetcode 1561</category>
      <category>leetcode 1561. Maximum Number of Coins You Can Get</category>
      <category>leetcode 1561. Maximum Number of Coins You Can Get js</category>
      <category>leetcode 1561. Maximum Number of Coins You Can Get solution</category>
      <category>leetcode Maximum Number of Coins You Can Get</category>
      <category>leetcode solution</category>
      <author>개발 여행</author>
      <guid isPermaLink="true">https://developerntraveler.tistory.com/151</guid>
      <comments>https://developerntraveler.tistory.com/151#entry151comment</comments>
      <pubDate>Mon, 11 Apr 2022 09:31:08 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]1557. Minimum Number of Vertices to Reach All Nodes</title>
      <link>https://developerntraveler.tistory.com/150</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/minimum-number-of-vertices-to-reach-all-nodes/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;1557.&amp;nbsp;Minimum&amp;nbsp;Number&amp;nbsp;of&amp;nbsp;Vertices&amp;nbsp;to&amp;nbsp;Reach&amp;nbsp;All&amp;nbsp;Nodes&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1648769966966&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Minimum Number of Vertices to Reach All Nodes - LeetCode&quot; data-og-description=&quot;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/minimum-number-of-vertices-to-reach-all-nodes/&quot; data-og-url=&quot;https://leetcode.com/problems/minimum-number-of-vertices-to-reach-all-nodes/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b57HAk/hyNR50odFU/jNe9PEd3lkWu469QqWAZU1/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260,https://scrap.kakaocdn.net/dn/clqEan/hyNRZ0aKPX/YTYMxVhxeC0guifkkGkPZ1/img.png?width=201&amp;amp;height=201&amp;amp;face=0_0_201_201&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/minimum-number-of-vertices-to-reach-all-nodes/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/minimum-number-of-vertices-to-reach-all-nodes/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b57HAk/hyNR50odFU/jNe9PEd3lkWu469QqWAZU1/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260,https://scrap.kakaocdn.net/dn/clqEan/hyNRZ0aKPX/YTYMxVhxeC0guifkkGkPZ1/img.png?width=201&amp;amp;height=201&amp;amp;face=0_0_201_201');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Minimum Number of Vertices to Reach All Nodes - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[ 문제 풀이 ]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프의 모든 노드에 도달할 수 있는 가장 작은 vertices 집합을 찾는 문제였다. 문제를 한참동안 분석해보아도 파악이 되지 않아 고민하는데에서 시간이 많이 초과되었다. 노드의 개수(n)와 from에서 to 방향을 나타내는 배열 (edges)가 주어질 때, 모든 노드에 도달할 수 있는 가장 작은 정점의 집합을 리턴해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;231&quot; data-origin-height=&quot;181&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGSyaE/btrx6HgR8Vg/3NB0KAhjBKcW8GhHG3VjS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGSyaE/btrx6HgR8Vg/3NB0KAhjBKcW8GhHG3VjS0/img.png&quot; data-alt=&quot;예제 1&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGSyaE/btrx6HgR8Vg/3NB0KAhjBKcW8GhHG3VjS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGSyaE%2Fbtrx6HgR8Vg%2F3NB0KAhjBKcW8GhHG3VjS0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;231&quot; height=&quot;181&quot; data-origin-width=&quot;231&quot; data-origin-height=&quot;181&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;예제 1&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;input: n = 6, edges&amp;nbsp;=&amp;nbsp;[[0,1],[0,2],[2,5],[3,4],[4,2]]&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;output: [0, 3]&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단일 정점에서 모든 노드에 도달하는 것은 불가능한 예시이다. 0에서 [0, 1, 2, 5]에 도달할 수 있고, 3에서 [3, 4, 2, 5]에 도달할 수 있다. 따라서 [0, 3]이 리턴되어야 한다. edges의 방향(from -&amp;gt; to)를 놓쳐서 고민하는 시간이 늘어났는데, 생각해보니 어떤 노드로부터 연결되어 있으면 도달할 수 있기 때문에 length 6의 배열을 하나 선언해두고, to에 해당하는 노드의 인덱스에 count를 계속 더해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;edges에서 [0, 1] 즉, 1은 0에서부터 도달할 수 있기 때문에 [0, 1, 0, 0, 0, 0]으로 인덱스 1의 원소를 1로 변경, [0, 2] 또한 0에서부터 도달할 수 있기 때문에 [0, 1, 1, 0, 0, 0]으로 업데이트 한다. [2, 5]일 때 [0, 1, 1, 0, 0, 1], [3, 4]일 때 [0, 1, 1, 0, 1, 1] 마지막 [4, 2]일 때 [0, 1, 2, 0, 1, 1]이 되어서 도달할 수 없는(원소가 0인) 노드 인덱스 0과 3이 최소의 정점이 되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[ 코드 ]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648770000312&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * @param {number} n
 * @param {number[][]} edges
 * @return {number[]}
 */
const findSmallestSetOfVertices = function (n, edges) {
  const connections = Array(n).fill(0);
  const result = [];

  edges.forEach(([from, to]) =&amp;gt; connections[to] += 1);
  connections.forEach((num, index) =&amp;gt; num === 0 &amp;amp;&amp;amp; result.push(index));

  return result;
};&lt;/code&gt;&lt;/pre&gt;</description>
      <category>개발/Algorithm</category>
      <category>1557. Minimum Number of Vertices to Reach All Nodes js</category>
      <category>leetcode 1557. Minimum Number of Vertices to Reach All Nodes</category>
      <category>leetcode 1557. Minimum Number of Vertices to Reach All Nodes javascript</category>
      <category>leetcode 1557. Minimum Number of Vertices to Reach All Nodes 풀이</category>
      <category>leetcode graph</category>
      <category>leetcode JS 1557. Minimum Number of Vertices to Reach All Nodes</category>
      <category>leetcode solution Minimum Number of Vertices to Reach All Nodes</category>
      <author>개발 여행</author>
      <guid isPermaLink="true">https://developerntraveler.tistory.com/150</guid>
      <comments>https://developerntraveler.tistory.com/150#entry150comment</comments>
      <pubDate>Fri, 1 Apr 2022 08:57:58 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]1630. Arithmetic Subarrays</title>
      <link>https://developerntraveler.tistory.com/149</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/arithmetic-subarrays/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212121;&quot;&gt;leetcode 1630&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212121;&quot;&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212121;&quot;&gt;Arithmetic Subarrays&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1648515685307&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Arithmetic Subarrays - LeetCode&quot; data-og-description=&quot;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/arithmetic-subarrays/&quot; data-og-url=&quot;https://leetcode.com/problems/arithmetic-subarrays/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/GAIad/hyNQZrgJFr/8kNbkZhWB6W3pV6VWtTj80/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/arithmetic-subarrays/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/arithmetic-subarrays/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/GAIad/hyNQZrgJFr/8kNbkZhWB6W3pV6VWtTj80/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Arithmetic Subarrays - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #212121;&quot;&gt;[ 문제 풀이 ]&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212121;&quot;&gt;매개변수 nums, l, r가 주어질 때, 각 원소의 차이가 모두 일정한지 boolean형의 element가 담긴 list를 리턴하는 문제이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212121;&quot;&gt;nums는 숫자를 담고 있는 배열, l은 시작 인덱스를 담고 있는 배열, r은 끝 인덱스를 담고 있는 배열이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 매개변수가 아래와 같을 때,&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;nums = [4,6,5,9,3,7], l = [0,0,2], r = [2,3,5]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212121;&quot;&gt;nums 배열에서 0(l[0]) ~ 2(r[0])까지의 배열 [4, 6, 5]는 [6, 5, 4]로 재배열 할 수 있고, 각 원소는 1씩 차이나므로 true,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212121;&quot;&gt;nums 배열에서 &lt;span style=&quot;background-color: #ffffff; color: #212121;&quot;&gt;0(l[1]) ~ 3(r[1])까지의 배열 [4, 6, 5, 9]는 각 원소의 차이가 달라 재배치할 수 없으므로 false,&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212121;&quot;&gt;nums 배열에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212121;&quot;&gt;0(l[2]) ~ 3(r[5])까지의 배열 [5, 9, 3, 7]은 [3, 5, 7, 9]로 재배치 할 수 있고, 각 원소는 2씩 차이나므로 true,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212121;&quot;&gt;따라서 [true, false, true]를 리턴하면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #212121;&quot;&gt;[ 코드 ]&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648515340919&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * @param {number[]} nums
 * @param {number[]} l
 * @param {number[]} r
 * @return {boolean[]}
 */
const checkArithmeticSubarrays = function(nums, l, r) {
  const chechArithmetic = (arr) =&amp;gt; {
    const diff = arr[1] - arr[0];

    for (let i = 2; i &amp;lt; arr.length; i++) {
      const currentDiff = arr[i] - arr[i - 1];

      if (currentDiff !== diff) {
        return false;
      }

      return true;
    }
  };

  return l.map((_, i) =&amp;gt;
    chechArithmetic(nums.slice(l[i], r[i] + 1).sort((a, b) =&amp;gt; a - b))
  );
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Algorithm</category>
      <category>1630. Arithmetic Subarrays</category>
      <category>Arithmetic Subarrays</category>
      <category>Arithmetic Subarrays 풀이</category>
      <category>leetcode 1630. Arithmetic Subarrays</category>
      <category>leetcode 1630. Arithmetic Subarrays 풀이</category>
      <category>leetcode Arithmetic Subarrays solution</category>
      <category>leetcode array</category>
      <category>leetcode 알고리즘</category>
      <author>개발 여행</author>
      <guid isPermaLink="true">https://developerntraveler.tistory.com/149</guid>
      <comments>https://developerntraveler.tistory.com/149#entry149comment</comments>
      <pubDate>Tue, 29 Mar 2022 10:00:21 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]1252. Cells with Odd Values in a Matrix</title>
      <link>https://developerntraveler.tistory.com/148</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/cells-with-odd-values-in-a-matrix/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;leetcode1252. Cells with Odd Values in a Matrix&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1648430615769&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Cells with Odd Values in a Matrix - LeetCode&quot; data-og-description=&quot;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/cells-with-odd-values-in-a-matrix/&quot; data-og-url=&quot;https://leetcode.com/problems/cells-with-odd-values-in-a-matrix/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/UZOB1/hyNQ8uhC7Q/Tb5qbk5veKBcua9IKAIWk0/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260,https://scrap.kakaocdn.net/dn/cxaC17/hyNPEBzdhX/42yT2GpR8mKSE8cysBTGX1/img.png?width=1033&amp;amp;height=259&amp;amp;face=0_0_1033_259,https://scrap.kakaocdn.net/dn/lrykc/hyNQ0bWQYh/KduA00XPhc9Daj6z4J7nNk/img.png?width=1143&amp;amp;height=224&amp;amp;face=0_0_1143_224&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/cells-with-odd-values-in-a-matrix/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/cells-with-odd-values-in-a-matrix/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/UZOB1/hyNQ8uhC7Q/Tb5qbk5veKBcua9IKAIWk0/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260,https://scrap.kakaocdn.net/dn/cxaC17/hyNPEBzdhX/42yT2GpR8mKSE8cysBTGX1/img.png?width=1033&amp;amp;height=259&amp;amp;face=0_0_1033_259,https://scrap.kakaocdn.net/dn/lrykc/hyNQ0bWQYh/KduA00XPhc9Daj6z4J7nNk/img.png?width=1143&amp;amp;height=224&amp;amp;face=0_0_1143_224');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Cells with Odd Values in a Matrix - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[ 문제 풀이 ]&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;m(row의 수), n(cell의 수)와 2D array(indices)가 주어질 때,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;m * n 행렬에서 각 indices[i] = [ri, ci]가 행렬에서 일부 증가 연산을 수행하기 위한 인덱스 위치를 나타내는 배열을 활용하여 인덱스의 모든 위치에 증가 연산을 한 후 행렬에서 홀수 값의 cell 수를 반환해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 indices[i]는 아래를 모두 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. ri row의 모든 cell을 증가시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. ci column의 모든 cell을 증가시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[ 코드 ]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648433416373&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * @param {number} m
 * @param {number} n
 * @param {number[][]} indices
 * @return {number}
 */
const oddCells = function (row, col, indices) {
  const matrix = Array.from(Array(row), () =&amp;gt; Array(col).fill(0));

  for (let i = 0; i &amp;lt; indices.length; i++) {
    const [r, c] = indices[i];

    for (let j = 0; j &amp;lt; matrix[r].length; j++) {
      matrix[r][j] += 1;
    }

    for (let k = 0; k &amp;lt; matrix.length; k++) {
      matrix[k][c] += 1;
    }
  }

  const result = matrix.reduce(
    (result, current) =&amp;gt;
      result +
      current.reduce((sum, cell) =&amp;gt; {
        return cell % 2 !== 0 ? sum + 1 : sum;
      }, 0),
    0
  );

  return result;
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 배열에서 홀수의 개수를 카운트 하기 위해 reduce 안에 reduce를 사용하였다.&lt;/p&gt;</description>
      <category>개발/Algorithm</category>
      <category>1252. Cells with Odd Values in a Matrix</category>
      <category>2d array</category>
      <category>leetcode</category>
      <category>leetcode 1252 solution</category>
      <category>leetcode 1252 풀이</category>
      <category>leetcode Cells with Odd Values in a Matrix</category>
      <category>배열 알고리즘</category>
      <category>알고리즘</category>
      <author>개발 여행</author>
      <guid isPermaLink="true">https://developerntraveler.tistory.com/148</guid>
      <comments>https://developerntraveler.tistory.com/148#entry148comment</comments>
      <pubDate>Mon, 28 Mar 2022 11:13:07 +0900</pubDate>
    </item>
    <item>
      <title>[React] React Hooks의 장단점</title>
      <link>https://developerntraveler.tistory.com/146</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;React Hooks는 ReactConf 2018에서 발표된 새로운 기능으로 16.8 버전부터 새로 추가되었다. Hooks를 이용하면 class 없이 state와 여러 React의 기능을 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Hooks는 왜 필요한가?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hooks의 등장 배경은 기존 Class Component를 사용할 떄의 불편함과 문제점을 해결하기 위해 개발되었다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. Reusing logic (컴포넌트 간 상태가 있는 logic의 재사용성이 떨어짐)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Class component 기반의 React 코드를 작성할 때 어플리케이션을 구성하는 여러 컴포넌트의 재사용성을 위해 &lt;span style=&quot;background-color: #99cefa;&quot;&gt;Higher-Order Conmonents&lt;/span&gt;와 &lt;span style=&quot;background-color: #99cefa;&quot;&gt;Render props&lt;/span&gt;와 같은 패턴을 통해 문제를 해결하였다고 한다. 두 가지 패턴은 특정 상황에 적절하게 사용될 수 있지만,&amp;nbsp; &lt;b&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;구조적 제약&lt;/span&gt;&lt;/b&gt;이 생길 수 있고, 로직의 재활용을 위해 엄청난 양의 Wrapper Component가 생겨서 &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;Wrapper Hell&lt;/b&gt;&lt;/span&gt;을 초래한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;273&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcEZX5/btroWoXAVkn/6v1sCBu0FLYlBPKTRjxq1k/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcEZX5/btroWoXAVkn/6v1sCBu0FLYlBPKTRjxq1k/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcEZX5/btroWoXAVkn/6v1sCBu0FLYlBPKTRjxq1k/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bcEZX5/btroWoXAVkn/6v1sCBu0FLYlBPKTRjxq1k/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;273&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;273&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Higher Order Component란?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 정리하면, 화면에 재사용 가능한 로직을 분리하여 컴포넌트로 만들고, 재사용 불가능한 부분은 (ex. UI) 파라미터로 받아서 처리하는 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. Giant component (복잡한 컴포넌트는 이해하기 어려움)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 라이프 사이클 메서드에 관련 없는 로직이 혼합되어 있을 수 있다. componentDidMount 와 componentDidUpdate는 컴포넌트 안에서 데이터를 가져오는 작업을 수행할 때 사용되어야 하지만, componentDidMount에서 이벤트 리스너를 설정하는 것과 같은 관계없는 로직이 포함되기도 하며, componentWillUnmount에서 cleanup 로직을 수행하기도 할 것이다.&amp;nbsp; 이것은 버그를 발생시키고 무결성을 해칠 수 있다. 또한 각 라이프사이클에서 수행할 로직이 많아지면 많아질수록 어떤 것을 cleanup 해줘야 하는지, 수정해야 하는지 찾기 어려울 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Confusing classes (클래스는 개발자와 컴퓨터 모두에게 혼란을 줄 수 있다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;class를 사용하기 위해서는 this 키워드가 어떻게 작동하는지 정확히 알아야한다. this키워드는 함수 선언 시점에 결정되는 것이 아니라, 함수 실행 시점에 결정되는 값이므로 함수가 어떻게 실행되는지에 따라 값이 변경될 수 있다. 사이즈가 큰 프로젝트에서는 this를 예상하고 추적하는 것에 작은 실수가 발생할 수 있다. 또한, class 사용 시 컴파일 시점에서 모든 것이 정확히 일치하는 것이 어렵다. 메서드가 사용되지 않지만 해당 메서드는 익명의 메서드로 남아있을 수 있다. 컴파일 시점에서 정확히 판단할 수 없기 때문이다. class는 최적화하기 어려운 코드를 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Hooks의 장점&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 더 빠른 성능과 짧은 코드 양&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트에서 작성한 코드를 실행할 때 바벨을 이용해서 코드를 컴파일한 후 실행시키는데,&amp;nbsp; 클래스형 컴포넌트일 경우 코드의 양이 길어진다. (바벨을 사용하여 컴파일한 코드는 &lt;a href=&quot;https://babeljs.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;babal 홈페이지&lt;/a&gt;에서 실행해볼 수 있다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 클래스형 컴포넌트에서는 라이프 사이클을 이용할 때 componentDidMount, componentDidUpdate, componentWillUnmount 모두 다르게 처리하지만, react hook을 사용하면 useEffect 안에서 모두 처리 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 코드)&lt;/p&gt;
&lt;pre id=&quot;code_1640536144684&quot; class=&quot;javascript&quot; style=&quot;display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// class
componentDidMount() {
	this.updateList(this.props.id);
}

componentDidUpdate(prevProps) {
	if (prevProps.id !== this.props.id) {
    	this.updateList(this.props.id);
    }
}

updateList = () =&amp;gt; {
	feachList(id).then((list) =&amp;gt; this.setState({list}));
}

// hooks
useEffect(() =&amp;gt; {
	feachList(id).then((res) =&amp;gt; setRes(res));
}, [id]);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. Weapper 컴포넌트양 감소&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HOC 컴포넌트를 Custom React Hooks로 대체하면, Weapper 컴포넌트를 사용하지 않아도 간단하게 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 공통적으로 적용애햐 하는 코드가 있다(언어, 테마, 인증 설정 등) 아래와 같이 감싸서 작성해야 한다. 이럴 경우 Wrapper 컴포넌트의 양이 엄청나게 증가한다면, 데이터 흐름을 파악하기 어렵다.&lt;/p&gt;
&lt;pre id=&quot;code_1640536660321&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;LanguageHOC&amp;gt;
  &amp;lt;ThemeHOC&amp;gt;
    &amp;lt;AuthHOC&amp;gt;
      &amp;lt;MyPage /&amp;gt;
    &amp;lt;/AuthHOC&amp;gt;
  &amp;lt;/ThemeHOC&amp;gt;
&amp;lt;/LanguageHOC&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 hook을 사용하면 데이터를 내려줄 때 어떤 페이지이든 감싸지 않아도 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1640537080284&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function useAuth() {
  const [users, setUsers] = useState([]);

  useEffect(() =&amp;gt; {
  	fetchUsers().then(users =&amp;gt; setUsers(users));
  }, []);

  return [users];
}

function MyPage() {
  const [users] = useAuth();

  return (
    &amp;lt;div&amp;gt;
      My Page
      {users.map(({ name, url }) =&amp;gt; (
        &amp;lt;div key={name}&amp;gt;
          &amp;lt;h3&amp;gt;{name}, {url}&amp;lt;/h3&amp;gt;
        &amp;lt;/div&amp;gt;
      ))}
    &amp;lt;/div&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Hooks의 단점&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 호출되는 순서에 의존&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;hooks는 반복문, 조건문, 중첩된 함수 내에서 호출할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 클릭하면 페이징되는 버튼을 구현하기 위해 useFetch를 사용하려고 한다면, &lt;a href=&quot;https://github.com/slorber/react-async-hook&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;react-async-hook&lt;/a&gt; 라이브러리를 사용하거나 custom hook을 만들어서 해결해야 한다. hooks의 규칙을 따르기 위해 많은 리소스가 필요하고, 코드가 많아지면 복잡성이 증가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. useEffect의 빈틈&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useEffect는 두 번째 인수로 dependency list를 받고, 하나의 값이라도 변경됐을 때 useEffect 내부의 로직을 실행하여 라이프 사이클을 흉내 낸다. React에서 hooks' dependency array의 변경을 감지하기 위해 Object.is() 메서드를 사용하는데 대체로 원시 타입에 올바르게 작동한다고 한다. 참조형 데이터를 비교할 때는 렌더링 될 때마다 참조 메모리 주소가 다르기 때문에 매번 실행될 것이다. useMemo를 사용하여 동일한 객체가 전달될 수 있도록 처리할 수도 있지만, 개발자가 놓치고 넘어가기 쉬운 포인트인 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. hooks는 클로저에 의존적이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램이 커지면 커질수록 hooks가 많아지는데, 클로저는 복잡성을 증가시킨다. 최신상태가 아닌 클로저는 해결하기 어렵다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1640540737355&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function WatchCount() {
  const [count, setCount] = useState(0);

  useEffect(function() {
    setInterval(function log() {
      console.log(`Count is: ${count}`);
    }, 2000);
  }, []);

  return (
    &amp;lt;div&amp;gt;
      {count}
      &amp;lt;button onClick={() =&amp;gt; setCount(count + 1) }&amp;gt;
        Increase
      &amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 출력된 count는 항상 0 이다. console.log()는 생성될 때의 count (0)을 캡처하여 기억하고 있으므로, 계속 count는 0일 것이다. 물론 해결하기 위해 아래와 같이 변경할 수 있다. 하지만 클로저 역시 예상하기 어렵다.&lt;/p&gt;
&lt;pre id=&quot;code_1640540845736&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function WatchCount() {
  const [count, setCount] = useState(0);

  useEffect(
    function () {
      const id = setInterval(function log() {
        console.log(`Count is: ${count}`);
      }, 2000);
      return function () {
        clearInterval(id);
      };
    [count]
  );

  return (
    &amp;lt;div&amp;gt;
      {count}
      &amp;lt;button onClick={() =&amp;gt; setCount(count + 1)}&amp;gt;Increase&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://youtu.be/dpw9EHDh2bM&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;React Conf 2018&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://youtu.be/7umCiutiJ7M&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://youtu.be/7umCiutiJ7M&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://jong-hui.github.io/devlog/2021/01/08/(React)%ED%9B%85%EC%9D%B4-%EC%8B%A4%ED%8C%A8%ED%95%9C-%EC%84%A4%EA%B3%84%EC%9D%B8-%EC%9D%B4%EC%9C%A0-4%EA%B0%80%EC%A7%80/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;천종희 기술 블로그&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ui.toast.com/weekly-pick/ko_20200922&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ui.toast.com/weekly-pick/ko_20200922&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hewonjeong.github.io/deep-dive-how-do-react-hooks-really-work-ko/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://hewonjeong.github.io/deep-dive-how-do-react-hooks-really-work-ko/&lt;/a&gt;&lt;/p&gt;</description>
      <category>개발/React</category>
      <category>hooks 단점</category>
      <category>hooks 장점</category>
      <category>react hooks</category>
      <category>React hooks 장단점</category>
      <category>리액트 hook 장점</category>
      <category>리액트 훅 단점</category>
      <category>리액트 훅 장단점</category>
      <category>리액트 훅 장점</category>
      <category>훅 단점</category>
      <category>훅 장점</category>
      <author>개발 여행</author>
      <guid isPermaLink="true">https://developerntraveler.tistory.com/146</guid>
      <comments>https://developerntraveler.tistory.com/146#entry146comment</comments>
      <pubDate>Mon, 27 Dec 2021 02:53:38 +0900</pubDate>
    </item>
    <item>
      <title>[Redux] Redux 기본 개념 정리(action, reducer, store, dispatch...)</title>
      <link>https://developerntraveler.tistory.com/144</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #dddddd;&quot;&gt;&lt;b&gt;이 글은 Redux 공식 문서를 참고해서 정리한 글입니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;actions&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Actions&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;action은 type field를 가지고 있는 plain JavaScript object이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순하게 action은 어플리케이션에서 무언가 일어나는 것을 설명한 &lt;b&gt;이벤트&lt;/b&gt;라고 생각할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- type field&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;type field는 action을 묘사하는 이름(feature)을 가진 string이어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예) &lt;span style=&quot;background-color: #dadde1; color: #1c1e21;&quot;&gt;&quot;todos/todoAdded&quot;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 타입은 &lt;span style=&quot;background-color: #dadde1; color: #1c1e21;&quot;&gt;&quot;domain/eventName&quot;&lt;/span&gt;과 같은 형식으로 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째 부분은 &lt;u&gt;action이 속한 카테고리의 특징&lt;/u&gt;을 나타내고, 두 번째 부분은 &lt;u&gt;어떤 것이 발생했는지 구체적으로&lt;/u&gt; 나타낸 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;- playload&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;action은 무엇이 일어났는지에 대한 추가적인 정보를 담고있는 또 다른 fields를 가질 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;convention에 따라 payload라는 이름으로 해당 정보를 작성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예)&lt;/p&gt;
&lt;pre id=&quot;code_1639304024880&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const addTodoAction = {
  type: 'todos/todoAdded',
  payload: 'Buy milk'
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Action creators&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;action creators는 &lt;u&gt;action 객체를 생성&lt;/u&gt;하고 &lt;u&gt;반환&lt;/u&gt;하는 함수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 action creator를 사용하기 때문에 매번 action 객체를 작성하지 않아도 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1639304202907&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const addTodo = text =&amp;gt; {
  return {
    type: 'todos/todoAdded',
    payload: text
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Reducers&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리듀서는 변화를 일으키는 함수로, 현재 state와 action 객체를 받아 필요한 경우 상태를 업데이트하는 방법을 결정하고, 새로운 상태를 반환하는 함수이다. 리듀서는 받은 action(이벤트) 유형에 따라 이벤트를 처리하는 이벤트 리스너로 생각하면 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(state, action) =&amp;gt; newState.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리듀서 함수는 내부적으로 다음과 같이 작동한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 리듀서가 action의 type이 조건에 맞는지 체크&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1-1) 맞다면, state의 복사본을 생성하고, 복사본을 새로운 값으로 업데이트 하고, 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 그렇지 않다면 변경되지 않는 기존의 state를 반환한다.&lt;/p&gt;
&lt;pre id=&quot;code_1639310053224&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const initialState = { value: 0 }

function counterReducer(state = initialState, action) {
  // Check to see if the reducer cares about this action
  if (action.type === 'counter/increment') {
    // If so, make a copy of `state`
    return {
      ...state,
      // and update the copy with the new value
      value: state.value + 1
    }
  }
  // otherwise return the existing state unchanged
  return state
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Store&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 Redux 애플리케이션 상태는 store 라는 객체에 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;store는 리듀서를 전달하여 생성되고, 현재 state 값을 반환하는 getState라는 메서드가 있다. 그 외 몇 가지 중요한 내장 함수를 가지고 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1639310893365&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { configureStore } from '@reduxjs/toolkit'

const store = configureStore({ reducer: counterReducer })

console.log(store.getState())
// {value: 0}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Dispatch&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux store은 dispatch라는 메서드를 가지고 있다. 디스패치는 &lt;u&gt;&lt;b&gt;action을 발생시키는 것&lt;/b&gt;&lt;/u&gt;이라고 이해하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상태를 업데이트하는 유일한 방법은 store.dispatch() 메서드를 부르고 action 객체를 넘겨주는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;store는 reducer function을 실행시키고 새로운 state를 내부에 저장할 것이다. 그리고 우리는 getstate() 메서드를 호출하여 업데이트된 값을 가질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dispatch 작업은 이벤트 트리거라고 생각할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무언가 발생했을 때, store는 어떤 일이 발생하는지 알고 싶어한다.&amp;nbsp;reducer는 이벤트 리스너와 같은 역할을 하며 관련된 action을 받으면 response로 state를 업데이트한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1639311443962&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;store.dispatch({ type: 'counter/increment' })

console.log(store.getState())
// {value: 1}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 올바른 action을 전달하기 위해 action creators를 호출한다.&lt;/p&gt;
&lt;pre id=&quot;code_1639315660322&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const increment = () =&amp;gt; {
  return {
    type: 'counter/increment'
  }
}

store.dispatch(increment())

console.log(store.getState())
// {value: 2}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style8&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Selectors&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;selectors는 store의 state 값에서 특정 정보를 추출하는 방법을 알고있는 함수이다. 애플리케이션이 커지면 앱의 다른 부분이 동일한 데이터를 읽는 상황이 많아지는데 반복되는 로직을 줄이는 데 도움이 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1639315824405&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const selectCounterValue = state =&amp;gt; state.value

const currentValue = selectCounterValue(store.getState())
console.log(currentValue)
// 2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Redux의 data flow&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;app을 업데이트하는 일련의 단계의 단방향 data flow&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;요약 )&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- state는 특정 시점의 app의 상태를 나타낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- UI는 state를 기반으로 렌더링된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 어떤 일이 발생하면 (버튼을 클릭하는 것과 같은) state는 무엇이 발생했는지를 기반으로 업데이트 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- UI는 새로운 state에 의해 리렌더링 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 단계를 조금 더 &lt;b&gt;자세하게&lt;/b&gt; 나눠보자!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;초기 setup )&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- redux 저장소는 root reducer function을 사용하여 생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- store는 root reducer를 한 번 호출하고 반환된 초기 state 값을 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- UI가 처음 렌더링되면 UI 컴포넌트는 Redux store의 현재 state에 액세스할 수 있고, 해당 데이터를 사용해서 렌더링할 항목을 결정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 향후 store의 업데이트(future&amp;nbsp;store&amp;nbsp;updates)를 subscribe하여&amp;nbsp; state가 변경되었는지 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0593d3;&quot;&gt;&lt;b&gt;update )&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 사용자가 버튼을 클릭하는 것과 같이 앱에서 어떤 일이 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 앱의 코드는 action을 Redux store에 dispatch한다. (&lt;span style=&quot;background-color: #dadde1; color: #1c1e21;&quot;&gt;dispatch({type: 'counter/increment'})&lt;/span&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- store는 이전의 state와 현재 action으로 다시 reducer 함수를 실행시키고, 반환된 새로운 state를 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- store는 subscribe된 UI의 모든 부분에 store가 업데이트되었음을 알린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- store의 데이터를 필요로하는 각 UI의 컴포넌트는 필요한 state가 변경되었는지 확인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 데이터가 변경된 각각의 컴포넌트는 화면에 새로운 내용을 업데이트 할 수 있도록 새로운 데이터와 함께 강제로 리렌더링된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 시각적으로 확인해보자!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;ReduxDataFlowDiagram-49fa8c3968371d9ef6f2a1486bd40a26.gif&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/48psc/btrnCPCtZcS/R3pLS0bXmZsbvVSimayeA1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/48psc/btrnCPCtZcS/R3pLS0bXmZsbvVSimayeA1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/48psc/btrnCPCtZcS/R3pLS0bXmZsbvVSimayeA1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/48psc/btrnCPCtZcS/R3pLS0bXmZsbvVSimayeA1/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;540&quot; height=&quot;405&quot; data-filename=&quot;ReduxDataFlowDiagram-49fa8c3968371d9ef6f2a1486bd40a26.gif&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1080&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고 문서 - &lt;a href=&quot;https://redux.js.org/tutorials/essentials/part-1-overview-concepts&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://redux.js.org/tutorials/essentials/part-1-overview-concepts&lt;/a&gt;&lt;/p&gt;</description>
      <category>개발/React</category>
      <category>redux action</category>
      <category>redux action creators</category>
      <category>redux dispatch</category>
      <category>redux selectors</category>
      <category>redux state</category>
      <category>redux store</category>
      <category>redux 개념 정리</category>
      <category>redux 기초</category>
      <category>redux 용어 정리</category>
      <category>Redux란</category>
      <author>개발 여행</author>
      <guid isPermaLink="true">https://developerntraveler.tistory.com/144</guid>
      <comments>https://developerntraveler.tistory.com/144#entry144comment</comments>
      <pubDate>Sun, 12 Dec 2021 23:16:22 +0900</pubDate>
    </item>
    <item>
      <title>[바닐라코딩 Bootcamp] week6 feedback</title>
      <link>https://developerntraveler.tistory.com/143</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;styled-components에 대한 활용&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;react에만 집중해서 과제를 하다보니 styled-components는 단순히 컴포넌트의 스타일을 지정하는 정도로만 사용했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;역시나 멘토님께서 해당 부분에 대해 코멘트를 남겨주셨다. 더 찾아보고 적용해보았어야 했는데라는 생각이 들었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;u&gt;&lt;b&gt;글로벌 스타일 지정(createGlobalStyle), theme, styled-component의 확장&lt;/b&gt;&lt;/u&gt; 등등 활용법이 굉장히 많다는 것을 배웠다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1) 전역 스타일 지정&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;구현된 코드에는 HTML 파일에 style sheet를 지정해서 전역 스타일을 지정해주었는데, styled component를 사용하면 아래와 같이 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1639292980841&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { createGlobalStyle } from 'styled-components'

const GlobalStyle = createGlobalStyle`
  body {
    color: ${props =&amp;gt; (props.whiteColor ? 'white' : 'black')};
  }
`

// later in your app

&amp;lt;React.Fragment&amp;gt;
  &amp;lt;GlobalStyle whiteColor /&amp;gt;
  &amp;lt;Navigation /&amp;gt; {/* example of other top-level stuff */}
&amp;lt;/React.Fragment&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;GlobalStyle 컴포넌트 또한 ThemeProvider를 통해서 theming 전략을 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1639293072976&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { createGlobalStyle, ThemeProvider } from 'styled-components'

const GlobalStyle = createGlobalStyle`
  body {
    color: ${props =&amp;gt; (props.whiteColor ? 'white' : 'black')};
    font-family: ${props =&amp;gt; props.theme.fontFamily};
  }
`

// later in your app

&amp;lt;ThemeProvider theme={{ fontFamily: 'Helvetica Neue' }}&amp;gt;
  &amp;lt;React.Fragment&amp;gt;
    &amp;lt;Navigation /&amp;gt; {/* example of other top-level stuff */}
    &amp;lt;GlobalStyle whiteColor /&amp;gt;
  &amp;lt;/React.Fragment&amp;gt;
&amp;lt;/ThemeProvider&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;코드 출처 -&amp;nbsp;https://styled-components.com/docs/api#createglobalstyle&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;styled-components는&amp;nbsp;ThemeProvider를 통해서 강력한 theming 전략을 제공한다고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;ThemeProvider는 context를 활용해서 모든 리액트 컴포넌트에 theme 속성을 전달할 수 있다고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;특정 컴포넌트의 depth가 아무리 깊어도 root에 ThemeProvider이 있다면 모든 렌터 트리의 자식은 theme 속성을 갖게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2) 반복적으로 사용되는 스타일&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일관적인 UI를 보여주기 위해 반복적으로 사용되는 Hex코드나 스타일들은 styled components에서 theme으로 지정해서 사용할 수 있다고 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1639293741397&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const Main = styled.div`
  color: ${(props) =&amp;gt; props.theme.red};
`;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1639293798138&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// import styled, { ThemeProvider } from 'styled-components'

const Box = styled.div`
  color: ${props =&amp;gt; props.theme.color};
`

render(
  &amp;lt;ThemeProvider theme={{ color: 'mediumseagreen' }}&amp;gt;
    &amp;lt;Box&amp;gt;I'm mediumseagreen!&amp;lt;/Box&amp;gt;
  &amp;lt;/ThemeProvider&amp;gt;
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-sourcepos=&quot;3:1-3:248&quot; data-ke-size=&quot;size16&quot;&gt;theme을 사용하면 정해진 규칙 외의 스타일을 사용하게 되는 실수를 줄여주고 각 스타일에 네이밍을 해줄 수 있어서 컴포넌트 각 요소에 어떤 스타일이 사용되었는지 파악하기도 쉽다.&lt;/p&gt;
&lt;p data-sourcepos=&quot;3:1-3:248&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-sourcepos=&quot;3:1-3:248&quot; data-ke-size=&quot;size16&quot;&gt;styled-component 사용 예시&lt;/p&gt;
&lt;p data-sourcepos=&quot;3:1-3:248&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://react.vlpt.us/styling/03-styled-components.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://react.vlpt.us/styling/03-styled-components.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1639296876779&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;3. styled-components &amp;middot; GitBook&quot; data-og-description=&quot;03. styled-components 이번에 배워볼 기술은 CSS in JS 라는 기술입니다. 이 문구가 뜻하는 그대로, 이 기술은 JS 안에 CSS 를 작성하는 것을 의미하는데요, 우리는 이번 튜토리얼에서 해당 기술을 사용하&quot; data-og-host=&quot;react.vlpt.us&quot; data-og-source-url=&quot;https://react.vlpt.us/styling/03-styled-components.html&quot; data-og-url=&quot;https://react.vlpt.us/styling/03-styled-components.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://react.vlpt.us/styling/03-styled-components.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://react.vlpt.us/styling/03-styled-components.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;3. styled-components &amp;middot; GitBook&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;03. styled-components 이번에 배워볼 기술은 CSS in JS 라는 기술입니다. 이 문구가 뜻하는 그대로, 이 기술은 JS 안에 CSS 를 작성하는 것을 의미하는데요, 우리는 이번 튜토리얼에서 해당 기술을 사용하&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;react.vlpt.us&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Infinite Scroll을 Intersection Observer API를 이용해서 구현해보기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Intersection Observer를 사용하면 무한 스크롤을 구현할 때 사용하는 debounce 나 throttle을 사용하지 않아도 된다는 장점이 있고 무엇보다 offset 값을 구하기 위해 매번 레이아웃을 새로 그리는 reflow를 하지 않는다는 장점이 있다고 한다.&lt;/p&gt;
&lt;p data-sourcepos=&quot;5:1-5:240&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/swlh/what-the-heck-is-repaint-and-reflow-in-the-browser-b2d0fb980c08&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;reflow가 무엇인지, 왜 reflow를 하지 않는 것이 장점인지, reflow를 최소화하는 방법으로 어떤 것들이 있는지&lt;/a&gt; 알고 있는 것이 중요하다라고 조언을 해주셨다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h4 data-sourcepos=&quot;5:1-5:240&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;데이터를 받아올 때 에러가 발생하거나 데이터가 없을 시 대응하는 코드 필요&lt;/b&gt;&lt;/h4&gt;
&lt;p data-sourcepos=&quot;5:1-5:240&quot; data-ke-size=&quot;size16&quot;&gt;API를 호출해서 데이터를 받아올 때 에러가 발생하거나 비디오가 없을 때, 사용자가 어떤 상황인지 가늠할 수 없기 때문에 대응하는 코드가 필요할 것 같다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h4 data-sourcepos=&quot;5:1-5:240&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;컴포넌트의 재사용성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-sourcepos=&quot;5:1-5:240&quot; data-ke-size=&quot;size16&quot;&gt;어제 테스트 코드를 작성하다가 구현해둔 컴포넌트들이 재사용성도 좋지 않고, 테스트 하기도 불편하다는 생각이 들어서 컴포넌트를 분리해서 새롭게 구성해보았다. 하지만 다시 작성해서 push를 한 시점보다 리뷰하는 시점이 빨랐는지 이전 코드에 대한 리뷰가 남겨져있었는데 컴포넌트의 재사용성에 대해 고민해보면 좋을 것 같다는 의견을 주셨다. 해당 부분은 이미 리팩토링을 진행한 부분이지만 컴포넌트의 재사용성은 항상 깊게 고민하고 생각하면서 작성해야하기 때문에 블로그에 꼭 남겨두어야겠다는 생각이 들었다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h4 data-sourcepos=&quot;5:1-5:240&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;객체의 초기값 설정&lt;/b&gt;&lt;/h4&gt;
&lt;p data-sourcepos=&quot;5:1-5:240&quot; data-ke-size=&quot;size16&quot;&gt;하위의 컴포넌트에서 비구조화 할당으로 값을 활용하기 위해 state의 초기값에 각 key를 설정해주고 null을 초기값으로 설정했었다.&lt;/p&gt;
&lt;pre id=&quot;code_1639298404926&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  const [video, setVideo] = useState({
    id: null,
    snippet: {
      title: null,
      description: null,
      publishedAt: null
    },
  });&lt;/code&gt;&lt;/pre&gt;
&lt;p data-sourcepos=&quot;5:1-5:240&quot; data-ke-size=&quot;size16&quot;&gt;이 때 서버에서 기본값이 모두 null로 오지 않는다면 어떤 타입의 데이터가 올지 추측하기 쉽게 작성하는 방법도 있다고 알려주셨다.&lt;/p&gt;
&lt;pre id=&quot;code_1639298463248&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  const [video, setVideo] = useState({
    id: '',
    snippet: {
      title: '',
      description: '',
      publishedAt: ''
    },
  });&lt;/code&gt;&lt;/pre&gt;
&lt;p data-sourcepos=&quot;5:1-5:240&quot; data-ke-size=&quot;size16&quot;&gt;하지만 보통 객체 형태의 데이터가 들어오고 특별한 이유가 있는게 아니라면 초기값을 null로 설정해줄수도 있다고 추가로 피드백을 주셨다.&lt;/p&gt;
&lt;pre id=&quot;code_1639298510259&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const [video, setVideo] = useState(null);&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h4 data-sourcepos=&quot;5:1-5:240&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;그 외 코드 스타일, 네이밍에 대한 피드백&lt;/b&gt;&lt;/h4&gt;
&lt;p data-sourcepos=&quot;5:1-5:240&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) 인라인으로 작성한다면 중괄호를 생략할 수도 있다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1639297275580&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// before
&amp;lt;EntryWrapper onClick={() =&amp;gt; { onClick(id) }}&amp;gt;

// after
&amp;lt;EntryWrapper onClick={() =&amp;gt; onClick(id)}&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2) state 네이밍&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 페이지가 로드 되었을 때만 웰컴 모달을 보여주기 위해 state를 사용하였는데, 변수명을 isInitLoad라고 설정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;isInitLoad보다는 모달이 열렸는지 열리지 않았는지 확실하게 나타낼 수 있는 구체적인 변수명이 더 좋을 것 같다고 말씀해주셨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들면, isModalOpne, isModalShow 등&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) 함수 네이밍&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크롤 이벤트가 발생했을 때 다음 페이지의 비디오를 가져오는 기능을 하는 함수를 선언했는데 이 부분 역시 조금 더 자연스러운 네이밍을 고민하면 좋을 것 같다고 피드백을 주셨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;getVideosOnScroll -&amp;gt; getNextPageVideos&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4) props 네이밍&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 prop명은 on을, 핸들러 함수는 handle이라는 단어를 접두사로 사용한다. (onClick(prop) handleClick(handler))&lt;/p&gt;
&lt;p data-sourcepos=&quot;6:1-6:359&quot; data-ke-size=&quot;size16&quot;&gt;통상적으로 prop명을 짓는 규칙들이 있는데, 예를 들어 lower camel case를 사용하거나 이름을 50자 미만으로 지어 주는 방법 등이 있다. prop 네이밍을 잘 지으면 컴포넌트가 많아지거나 전달하는 prop이 많아질 때 혼란을 방지할 수 있으니 숙지해보는 것이 좋다라고 하셨다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-sourcepos=&quot;8:1-9:82&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-sourcepos=&quot;8:1-9:82&quot;&gt;&lt;a href=&quot;https://dlinau.wordpress.com/2016/02/22/how-to-name-props-for-react-components/&quot;&gt;How to name props for React components&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5) parameter destructuring&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;parameter destructuring을 사용하여 필요한 데이터만 가져오는 방법도 있다. 더 간결해 보인다는 장점이 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1639298734498&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// before
{videos.length &amp;gt; 0 &amp;amp;&amp;amp; videos.map((video, index) =&amp;gt; {

// after
{videos.length &amp;gt; 0 &amp;amp;&amp;amp; videos.map(({ id, snippet }, index) =&amp;gt; {&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6) 단축 평가 논리 연산자 사용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리 연산자를 사용하면 코드를 간결하게 나타낼 수 있을 것 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1639298814919&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// before
id: video.id.videoId ? video.id.videoId : video.id.playlistId,

// after
id: video.id.videoId || video.id.playlistId,&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;7) 시간과 관련된 값의 네이밍&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간과 관련된 값의 이름은 보통 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;~~edAt&lt;/span&gt;으로 작성한다.&lt;/p&gt;
&lt;p data-sourcepos=&quot;3:1-6:9&quot; data-ke-size=&quot;size16&quot;&gt;ex) publishedAt createdAt updatedAt&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8) self-closing&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;children이 없다면 self-closing을 할 수 있다. 이 부분은 알고 있었는데도 children이 없는지 확인을 못 한 것 같다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발 - 기록/Code Review</category>
      <author>개발 여행</author>
      <guid isPermaLink="true">https://developerntraveler.tistory.com/143</guid>
      <comments>https://developerntraveler.tistory.com/143#entry143comment</comments>
      <pubDate>Sun, 12 Dec 2021 17:50:53 +0900</pubDate>
    </item>
    <item>
      <title>[React] React에서 .env 환경변수 사용하기</title>
      <link>https://developerntraveler.tistory.com/142</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;React project 내에서 Github API를 사용하기 위해 개인 키를 넣어주여야 하는 상황이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React 앱에 개인 API키를 저장하면 누구나 앱 파일을 볼 수 있기 때문에 위험하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;환경 변수를 사용해서 키를 보안하는 방법에 대해 글을 남기고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;1) 먼저, 디렉토리의 root에 .env 파일을 생성한다.&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(개발용 환경변수, 테스트용 환경변수 등등 다양하지만 이번에는 .env로 사용해보겠다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2021-12-03 오후 5.29.20.png&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;92&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTFJVB/btrmYTRYwRH/AiTf5RDpGu98KuTPkHOCMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTFJVB/btrmYTRYwRH/AiTf5RDpGu98KuTPkHOCMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTFJVB/btrmYTRYwRH/AiTf5RDpGu98KuTPkHOCMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTFJVB%2FbtrmYTRYwRH%2FAiTf5RDpGu98KuTPkHOCMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;256&quot; height=&quot;56&quot; data-filename=&quot;스크린샷 2021-12-03 오후 5.29.20.png&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;92&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;2) 파일을 생성했다면 먼저 &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;.gitignore에 추가&lt;/span&gt;해주어야 원격저장소에 저장할 때 파일이 올라가지 않는다.&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2021-12-03 오후 5.31.15.png&quot; data-origin-width=&quot;1352&quot; data-origin-height=&quot;162&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfpRUq/btrmYcj8FaO/Y5cVIsClHcdckWzkbsuSL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfpRUq/btrmYcj8FaO/Y5cVIsClHcdckWzkbsuSL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfpRUq/btrmYcj8FaO/Y5cVIsClHcdckWzkbsuSL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfpRUq%2FbtrmYcj8FaO%2FY5cVIsClHcdckWzkbsuSL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;668&quot; height=&quot;80&quot; data-filename=&quot;스크린샷 2021-12-03 오후 5.31.15.png&quot; data-origin-width=&quot;1352&quot; data-origin-height=&quot;162&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;3) 이제 .env에 사용할 key를 저장해주어야 한다.&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(주의할 점은 &lt;b&gt;REACT_APP_&lt;/b&gt; 을 꼭 붙여주어야 한다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2021-12-03 오후 5.33.20.png&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;182&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Kxh1F/btrmYdJ2Cpt/E7QV6ds31n7AqHDvAzltP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Kxh1F/btrmYdJ2Cpt/E7QV6ds31n7AqHDvAzltP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Kxh1F/btrmYdJ2Cpt/E7QV6ds31n7AqHDvAzltP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKxh1F%2FbtrmYdJ2Cpt%2FE7QV6ds31n7AqHDvAzltP1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;404&quot; height=&quot;110&quot; data-filename=&quot;스크린샷 2021-12-03 오후 5.33.20.png&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;182&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 사진과 같이 key와 value를 설정해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;4) 실제 프로그램을 작성할 때 env 안에 있는 key를 사용해볼 것이다.&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1638520520153&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const GITHUB_CLIENT_ID = process.env.REACT_APP_GITHUB_CLIENT_ID;
const GITHUB_SECRET_ID = process.env.REACT_APP_GITHUB_SECRET_ID;
const GITHUB_TOKEN = process.env.REACT_APP_GITHUB_TOKEN;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;env 안의 key를 가져오기 위해 &lt;b&gt;process.env&lt;/b&gt;를 붙여주면 된다.&lt;/p&gt;</description>
      <category>React .env</category>
      <category>react .env key</category>
      <category>react env 파일 만들기</category>
      <category>react env 환경변수</category>
      <category>react 키값 환경변수</category>
      <category>react 환경변수 관리</category>
      <author>개발 여행</author>
      <guid isPermaLink="true">https://developerntraveler.tistory.com/142</guid>
      <comments>https://developerntraveler.tistory.com/142#entry142comment</comments>
      <pubDate>Fri, 3 Dec 2021 17:38:00 +0900</pubDate>
    </item>
    <item>
      <title>[Git Error] Git 중간 커밋 삭제 (git rebase --interactive 옵션)</title>
      <link>https://developerntraveler.tistory.com/141</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;자리가 변경되고 나서 다른 계정의 commit이 나의 commit내역으로 올라가 파일의 내용이 모두 지워지는 상황이 발생했다!&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;git&amp;nbsp;rebase&amp;nbsp;-i&amp;nbsp;&amp;lt;수정할&amp;nbsp;commit의&amp;nbsp;직전&amp;nbsp;commit&amp;gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;commit 히스토리를 수정하기 위해 검색을 해보았는데, rebase를 활용하면 해당 commit을 지울 수 있다고 해서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;질문을 남긴 후 바로 commit 삭제를 진행했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;--interactive는 말 그대로 git rebase 명령어를 대화형으로 실행하는 것을 뜻한다고 하는데, 아직 와닿지가 않는다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;내가 수정하고 싶은 commit의 바로 이전 commit&lt;/b&gt;&lt;/span&gt;을 알아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 gitlab에서 commit hash 값을 가지고 왔다. (수정할 commit의 hash가 아니라 바로 직전의 commit이어야 한다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2021-11-30 153322.png&quot; data-origin-width=&quot;197&quot; data-origin-height=&quot;94&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6Te4e/btrmwQwGmKQ/lTcAdL9hUdiDQ4E4MNR6xK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6Te4e/btrmwQwGmKQ/lTcAdL9hUdiDQ4E4MNR6xK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6Te4e/btrmwQwGmKQ/lTcAdL9hUdiDQ4E4MNR6xK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6Te4e%2FbtrmwQwGmKQ%2FlTcAdL9hUdiDQ4E4MNR6xK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;197&quot; height=&quot;94&quot; data-filename=&quot;화면 캡처 2021-11-30 153322.png&quot; data-origin-width=&quot;197&quot; data-origin-height=&quot;94&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1638254116688&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git rebase -i &amp;lt;수정할 commit의 직전 commit&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 명령어를 실행하면 터미널 화면에 commit 리스트와 사용할 수 있는 명령어 그리고 설명이 나온다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2021-11-30 153840.png&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2CNGj/btrmzjR9L1K/jW9HX5KkA6bqbR1KgBQOqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2CNGj/btrmzjR9L1K/jW9HX5KkA6bqbR1KgBQOqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2CNGj/btrmzjR9L1K/jW9HX5KkA6bqbR1KgBQOqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2CNGj%2FbtrmzjR9L1K%2FjW9HX5KkA6bqbR1KgBQOqk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;550&quot; height=&quot;490&quot; data-filename=&quot;화면 캡처 2021-11-30 153840.png&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 가지 명령어가 있지만 다른 계정으로 commit 된 내용을 지우고 싶기 때문에 drop 명령어만 정리하고 넘어가려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;drop(d도 가능)은 history에서 명시적으로 commit을 삭제하는 명령어이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 리스트 중 두 번째 commit을 지우고 싶다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1)&amp;nbsp;&amp;nbsp;&lt;span style=&quot;background-color: #dddddd;&quot;&gt; &lt;b&gt;i&amp;nbsp;&lt;/b&gt;&lt;/span&gt; key를 누르고 insert 모드로 변경한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) pick으로 되어있는 부분을 drop으로 변경한 후&amp;nbsp;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt; :wq&lt;/b&gt;&amp;nbsp;&lt;/span&gt; 로 저장하면 반영된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;나머지 명령어들은 아래의 블로그를 참고해보길 바란다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://wormwlrm.github.io/2020/09/03/Git-rebase-with-interactive-option.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://wormwlrm.github.io/2020/09/03/Git-rebase-with-interactive-option.html&lt;/a&gt;&lt;/p&gt;</description>
      <category>GIT/Git error</category>
      <category>git drop</category>
      <category>git rebase</category>
      <category>git rebase -i</category>
      <category>git rebase commit drop</category>
      <category>git rebase drop</category>
      <category>git rebase 커밋 삭제</category>
      <category>git 이전 commit 삭제</category>
      <category>git 이전 커밋 삭제</category>
      <category>git 중간 commit 삭제</category>
      <category>git 중간 커밋 삭제</category>
      <author>개발 여행</author>
      <guid isPermaLink="true">https://developerntraveler.tistory.com/141</guid>
      <comments>https://developerntraveler.tistory.com/141#entry141comment</comments>
      <pubDate>Tue, 30 Nov 2021 15:46:46 +0900</pubDate>
    </item>
    <item>
      <title>[React] 리액트 hooks</title>
      <link>https://developerntraveler.tistory.com/140</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Hooks의 등장 배경&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트 hook의 역사는 recompose 라이브러리에서 시작되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;recompose의 아이디어는 hook과 굉장히 흡사하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 프로그래밍을 적용하여 개발되었으며, state를 주는 방식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;끝내 recompose 라이브러리는 리액트 팀에 의해 인수되었다. 2018년 10월 25일 recompose의 업데이트는 중단되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Andrew Clark은 facebook 팀에 합류해서 hook을 릴리즈했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/acdlite/recompose&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/acdlite/recompose&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1638118669618&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - acdlite/recompose: A React utility belt for function components and higher-order components.&quot; data-og-description=&quot;A React utility belt for function components and higher-order components. - GitHub - acdlite/recompose: A React utility belt for function components and higher-order components.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/acdlite/recompose&quot; data-og-url=&quot;https://github.com/acdlite/recompose&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bBs77C/hyMv6yOHFp/cVi09RibdZtriwc4osEGv0/img.png?width=1200&amp;amp;height=600&amp;amp;face=993_123_1060_196&quot;&gt;&lt;a href=&quot;https://github.com/acdlite/recompose&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/acdlite/recompose&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bBs77C/hyMv6yOHFp/cVi09RibdZtriwc4osEGv0/img.png?width=1200&amp;amp;height=600&amp;amp;face=993_123_1060_196');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - acdlite/recompose: A React utility belt for function components and higher-order components.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A React utility belt for function components and higher-order components. - GitHub - acdlite/recompose: A React utility belt for function components and higher-order components.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;props&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;props (properties)는 컴포넌트 속성을 설정할 때 사용하는 요소이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;props 값은 해당 컴포넌트를 불러와 사용하는 부모 컴포넌트에서 설정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;state&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;state는 컴포넌트 내부에서 바뀔 수 있는 값을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;props는 컴포넌트가 사용되는 과정에서 부모 컴포넌트가 사용하는 값이며, 컴포넌트 자신은 해당 props를 읽기 전용으로만 사용할 수 있다는 것을 명심하자!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;useEffect&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;렌더링 직후에, 컴포넌트가 뭘 해야 하는지 명시하는 부분으로 react 컴포넌트가 렌더링 될 때 마다 특정 작업을 수행하도록 설정할 수 있는 hook이다. 렌더링 후에 useEffect에 작성한 함수들이 실행이 된다. (클래스형 컴포넌트의 componentDidMount와 componentDidUpdate를 합친 형태로 생각하면 쉽다. &lt;br /&gt;주로&amp;nbsp;API를&amp;nbsp;사용해서&amp;nbsp;data를&amp;nbsp;받거나,&amp;nbsp;event&amp;nbsp;listener와&amp;nbsp;같은&amp;nbsp;작업을&amp;nbsp;수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;useEffect 활용&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;1. 마운트될 때만 실행하고 싶을 때&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useEffect에서 설정한 함수를 컴포넌트가 화면에 맨 처음 렌더링될 때만 실행하고, 업데이트될 때는 실행하지 않으려면 함수의 두 번째 인수로 빈 배열을 넣어주면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1638120484512&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;useEffect(() =&amp;gt; {
	console.log('마운트 될 때만 실행');
}, []);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;2. 특정 값이 업데이트될 때만 실행하고 싶을 때&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 값이 변경될 때만 호출하고 싶은 경우에는 두 번째 인수로 전달되는 배열 안에 검사하고 싶은 값을 넣어주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열 안에는 useState로 관리하고 있는 상태를 넣어 주어도 되고, props로 전달받은 값을 넣어주어도 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1638120589575&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;useEffect(() =&amp;gt; {
	console.log(email);
}, [email]);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 뒷정리 함수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useEffect는 렌더링되고 난 직후마다 실행되고, 두 번째 인수 배열에 무엇을 넣는지에 따라 실행되는 조건이 달라진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트가 언마운트되기 전이나 업데이트되기 직전에 어떠한 작업을 수행하고 싶다면 useEffect에서 뒷정리(cleanup) 함수를 반환해주어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언마운트 될 때만 뒷정리 함수를 호출하고 싶다면 useEffect의 두 번째 인수에 비어있는 배열을 넣으면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1638120881852&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;useEffect(() =&amp;gt; {
	console.log('useEffect');
	console.log(email);
    
    return () =&amp;gt; {
    	console.log('cleanup');
        console.log(email);
    };
}, [email]);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;useReducer&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useState보다 더 다양한 컴포넌트 상황에 따라 상태를 다른 값으로 업데이트하고 싶을 때 사용하는 hook이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;reducer는 현재 상태, 그리고 업데이트를 위해 필요한 정보를 담은 action값을 전달받아 새로운 상태를 반환하는 함수이다. reducer 함수에서 새로운 상태를 만들 때는 반드시 불변성을 지켜 주어야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1638121101039&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function reducer(state, action) {
	return { ... };
}

// action 값 구성
{
	type: 'INCREMENT',
    // 또 다른 값...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;useMemo&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 컴포넌트 내부에서 발생하는 연산을 최적화할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;렌더링하는 과정에서 특정 값이 바뀌었을 때만 연산을 실행하고, 원하는 값이 바뀌지 않았다면 이전에 연산했던 결과를 다시 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;useCallback&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useMemo와 비슷한 함수로, 주로 렌더링 성능을 최적화해야 할 때 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useCallback을 사용하면 이벤트 핸들러 함수를 필요할 때만 생성할 수 있다.&lt;/p&gt;</description>
      <category>개발/React</category>
      <author>개발 여행</author>
      <guid isPermaLink="true">https://developerntraveler.tistory.com/140</guid>
      <comments>https://developerntraveler.tistory.com/140#entry140comment</comments>
      <pubDate>Mon, 29 Nov 2021 02:51:46 +0900</pubDate>
    </item>
  </channel>
</rss>