<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>connecting dots</title>
    <link>https://diveintodevworld.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 25 Aug 2026 02:47:26 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>dearsuhyun</managingEditor>
    <image>
      <title>connecting dots</title>
      <url>https://tistory1.daumcdn.net/tistory/7090113/attach/0a39d764cdc249759f24882819c76706</url>
      <link>https://diveintodevworld.tistory.com</link>
    </image>
    <item>
      <title>영상공유 SNS 플랫폼 개발 프로젝트 - MAZI</title>
      <link>https://diveintodevworld.tistory.com/80</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;742&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m7LWi/btsJSNJ9MCd/E25yPO9aW1qMCykoKvk7AK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m7LWi/btsJSNJ9MCd/E25yPO9aW1qMCykoKvk7AK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m7LWi/btsJSNJ9MCd/E25yPO9aW1qMCykoKvk7AK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm7LWi%2FbtsJSNJ9MCd%2FE25yPO9aW1qMCykoKvk7AK%2Fimg.jpg&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;1280&quot; height=&quot;742&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;742&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;h2 data-ke-size=&quot;size26&quot;&gt;1. 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패스트캠퍼스 데브캠프: 김민태의 프론트엔드 개발 1기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비기너반 프로젝트로써 진행한 영상공유 SNS 플랫폼 개발 프로젝트 소개 및 회고를 해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 깃허브 주소&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/Dev-FE-1/Toy_Project_3_BeginAgain&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/Dev-FE-1/Toy_Project_3_BeginAgain&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1727913548861&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 - Dev-FE-1/Toy_Project_3_BeginAgain&quot; data-og-description=&quot;Contribute to Dev-FE-1/Toy_Project_3_BeginAgain development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/Dev-FE-1/Toy_Project_3_BeginAgain&quot; data-og-url=&quot;https://github.com/Dev-FE-1/Toy_Project_3_BeginAgain&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bmDY08/hyXd95a1kQ/0pxKCGddJe7sPVECjmvk31/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/RgKME/hyXaGXTKMi/R1oL8PNPTDTR0s4Que9qY1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/Dev-FE-1/Toy_Project_3_BeginAgain&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/Dev-FE-1/Toy_Project_3_BeginAgain&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bmDY08/hyXd95a1kQ/0pxKCGddJe7sPVECjmvk31/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/RgKME/hyXaGXTKMi/R1oL8PNPTDTR0s4Que9qY1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&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 - Dev-FE-1/Toy_Project_3_BeginAgain&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to Dev-FE-1/Toy_Project_3_BeginAgain development by creating an account on GitHub.&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 팀원소개 및 역할분담&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;1076&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHnpqr/btsJUZaJ8Wr/icwrl1UeiJfXf0M6lIGIw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHnpqr/btsJUZaJ8Wr/icwrl1UeiJfXf0M6lIGIw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHnpqr/btsJUZaJ8Wr/icwrl1UeiJfXf0M6lIGIw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHnpqr%2FbtsJUZaJ8Wr%2Ficwrl1UeiJfXf0M6lIGIw0%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;1538&quot; height=&quot;1076&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;1076&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;처음에는 7명으로 시작했던 비기너반이 최종적으로는 4명이 되어 프로젝트를 진행하였습니다. 특히나 프로젝트가 시작되고 기획 및 디자인 단계에서 두 분이나 개인 사정으로 부트캠프를 하차하게 되면서 충분하지 않은 시간 동안 완성할 수 있을지 걱정이 많이 되었지만 팀원 모두가 추석이나 정규 프로그램을 따라가야하는 우여곡절 속에서도 최선의 노력을 해주셨기에 프로젝트 완성을 할 수 있었습니다.&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;처음으로 팀장이라는 자리에서 프로젝트를 진행해보았는데 제가 실력이 좋다거나 프로젝트 경험이 많은 상태가 아니었기 때문에 어떻게 하면 역할을 잘 수행할 수 있을지 고민이 많았습니다. 저희는 비기너반으로써 개발 경험이 적은, 또 프론트엔드 개발을 이 부트캠프에서 처음 배워보는 수강생들이 모였던 상황이라 Git 사용이라던지 필수 컨벤션, 프로젝트 초기 세팅과 같은 부분에 익숙하지 않았습니다. 따라서 제가 Git Wiki에 이슈 생성법, PR 생성 및 리뷰법, 팀 컨벤션 등을 정리하여 팀원분들이 Git을 사용할 때 최대한 불편함이 없도록 조치를 해 두었습니다. 회의 전에는 정해야 할 부분 중에 너무 어렵거나 처음 접해보는 내용은 빼고 정말 필수적으로 정해야 하는 rule이나 코드 컨벤션 등을 간결하게 정리해보았고 노션 템플릿 등을 이용하여 기획이나 문서 작성 시 예시를 제시하여 시행착오를 최대한 줄이고자 했습니다.&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;- Git Wiki에 정리해둔  가이드 일부 발췌&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2284&quot; data-origin-height=&quot;1432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CPKil/btsJTRkBQ33/eRgtnsoQhWoJ7HZIqYin41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CPKil/btsJTRkBQ33/eRgtnsoQhWoJ7HZIqYin41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CPKil/btsJTRkBQ33/eRgtnsoQhWoJ7HZIqYin41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCPKil%2FbtsJTRkBQ33%2FeRgtnsoQhWoJ7HZIqYin41%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;2284&quot; height=&quot;1432&quot; data-origin-width=&quot;2284&quot; data-origin-height=&quot;1432&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rjSEv/btsJSGxECkv/qgjwiFklmeTXeYMc8P4VRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rjSEv/btsJSGxECkv/qgjwiFklmeTXeYMc8P4VRk/img.png&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;600&quot; data-is-animation=&quot;false&quot; style=&quot;width: 42.0342%; margin-right: 10px;&quot; data-widthpercent=&quot;42.53&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rjSEv/btsJSGxECkv/qgjwiFklmeTXeYMc8P4VRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrjSEv%2FbtsJSGxECkv%2FqgjwiFklmeTXeYMc8P4VRk%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;1206&quot; height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uvIK1/btsJSGj6GnW/U9ghbswYaLIG0QkVthaAzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uvIK1/btsJSGj6GnW/U9ghbswYaLIG0QkVthaAzK/img.png&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;444&quot; data-is-animation=&quot;false&quot; style=&quot;width: 56.803%;&quot; data-widthpercent=&quot;57.47&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uvIK1/btsJSGj6GnW/U9ghbswYaLIG0QkVthaAzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuvIK1%2FbtsJSGj6GnW%2FU9ghbswYaLIG0QkVthaAzK%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;1206&quot; height=&quot;444&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;&lt;br /&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;- Notion에 정리한 것 일부 발췌&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4IPB0/btsJUjntI1o/zNu4sjMBHklIxH6nMlNFJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4IPB0/btsJUjntI1o/zNu4sjMBHklIxH6nMlNFJ0/img.png&quot; data-origin-width=&quot;1206&quot; data-origin-height=&quot;924&quot; data-is-animation=&quot;false&quot; style=&quot;width: 58.177%; margin-right: 10px;&quot; data-widthpercent=&quot;58.86&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4IPB0/btsJUjntI1o/zNu4sjMBHklIxH6nMlNFJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4IPB0%2FbtsJUjntI1o%2FzNu4sjMBHklIxH6nMlNFJ0%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;1206&quot; height=&quot;924&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/U4ozq/btsJUFjnjfT/lUWK4od11FkgEe3YODUCEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/U4ozq/btsJUFjnjfT/lUWK4od11FkgEe3YODUCEk/img.png&quot; data-origin-width=&quot;1330&quot; data-origin-height=&quot;1458&quot; data-is-animation=&quot;false&quot; style=&quot;width: 40.6602%;&quot; data-widthpercent=&quot;41.14&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/U4ozq/btsJUFjnjfT/lUWK4od11FkgEe3YODUCEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FU4ozq%2FbtsJUFjnjfT%2FlUWK4od11FkgEe3YODUCEk%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;1330&quot; height=&quot;1458&quot;/&gt;&lt;/span&gt;&lt;/div&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;h2 data-ke-size=&quot;size26&quot;&gt;4. 프로젝트 진행 방식&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;-&amp;nbsp; 프로젝트 일정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2024.09.02 - 2024.09.27&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;- 온라인 진행&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부트캠프 역시 온라인으로 진행되며 각자 거주하는 지역이 상이한 이유로 오프라인으로 모여 프로젝트를 진행하기 힘든 상황이었습니다. 따라서 프로젝트 역시 온라인으로 진행하였습니다. Zoom, Zep을 이용하여 정기 회의와 긴급 회의 등 팀원 모두가 공유해야 할 상황이 생겼고 구두로 설명하는 것이 좋겠다고 판단할 시 즉각적으로 모일 수 있었습니다. 회의록이나 트러블 기록 및 문서화하여 공유하면 좋을 내용은 Notion을 통해 정리했습니다. 수정해야 할 버그 등도 문서화하여 공유하고 해결한 버그는 지워나가는 식으로 진행하였더니 팀원 모두가 진행 상황을 파악하기 쉬웠고 해당 부분을 맡았던 팀원도 한 눈에 문제를 파악할 수 있었습니다. 또한 Slack을 통해 기타 공지나 멘토님과의 소통 등을 진행했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;- 문서화&lt;/h3&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-origin-width=&quot;1390&quot; data-origin-height=&quot;1076&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbwTTT/btsJUWyq9Sz/KYrNG2doHIal3cfT8vKqW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbwTTT/btsJUWyq9Sz/KYrNG2doHIal3cfT8vKqW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbwTTT/btsJUWyq9Sz/KYrNG2doHIal3cfT8vKqW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbwTTT%2FbtsJUWyq9Sz%2FKYrNG2doHIal3cfT8vKqW0%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;1390&quot; height=&quot;1076&quot; data-origin-width=&quot;1390&quot; data-origin-height=&quot;1076&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;* 트러블 슈팅&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희 팀이 프로젝트를 진행하면서 가장 힘들었던 부분은 Git 활용이었습니다. 토이프로젝트 1으로 프로젝트 경험이 있는 분과 개인프로젝트 진행으로 협업 프로젝트는 처음인 분이 섞여있었고, 이론 강의를 들었을 때와는 또 다르게 직접 버전관리를 하려니 혼란한 부분이 많았습니다. 예시로 저희는 회의를 통해 개발 기간에는 develop에 merge를 하여 진행하고 마지막에 모든 것이 완성되었을 때 main으로 한번에 merge하기로 규칙을 정했었습니다. 기획 및 디자인을 끝내고 기능 개발에 들어가는 날, 팀원 분이 main으로 병합하는 PR을 올리셨고 승인한 팀원들도 그 부분을 유념히 검토하지 않고 병합이 되는 실수가 발생했습니다. 이를 되돌리려고 저희끼리 노력해보았지만 역부족이라 부트캠프 다른 수강생 분들도 와서 도와주시다가 나중에는 멘토님과 매니저님까지 달려와 장장 8시간의 회의가 되어버린 상황을 겪게 되었습니다. 결국 너무 꼬여버려 본질적인 해결은 하지 못하고 repository를 하나 더 생성하는 걸로 결론을 내렸습니다.&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2678&quot; data-origin-height=&quot;524&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IOA75/btsJTUVSWp9/3grJJm0140DLagtkd8BLLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IOA75/btsJTUVSWp9/3grJJm0140DLagtkd8BLLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IOA75/btsJTUVSWp9/3grJJm0140DLagtkd8BLLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIOA75%2FbtsJTUVSWp9%2F3grJJm0140DLagtkd8BLLK%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;2678&quot; height=&quot;524&quot; data-origin-width=&quot;2678&quot; data-origin-height=&quot;524&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&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;첫 번째, GitHub 자체에서 설정할 수 있는 Rulesets를 활용했습니다. 규칙을 설정함에 있어서 서윤님이 많이 기여해주셨는데, 서윤님이 제안해주신 방법은 main에 합병하는 PR의 경우 승인을 받아야 하는 팀원의 수를 3명으로, develop에 합병하는 PR의 경우에는 승인을 받아야 하는 팀원의 수를 2명으로 차이를 두어 혹시나 모를 상황을 미연에 방지하는 방법이었습니다. 실제로 이 규칙을 설정해 놓은 덕분에 한 두번정도 main으로 합병을 시도한 PR이 승인 과정에서 발견되었고 main에 합병되는 상황을 보호할 수 있었습니다.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1456&quot; data-origin-height=&quot;694&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rxnjU/btsJUu964Sl/r5FlJUIRwxfqcij0HkInWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rxnjU/btsJUu964Sl/r5FlJUIRwxfqcij0HkInWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rxnjU/btsJUu964Sl/r5FlJUIRwxfqcij0HkInWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrxnjU%2FbtsJUu964Sl%2Fr5FlJUIRwxfqcij0HkInWk%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;1456&quot; height=&quot;694&quot; data-origin-width=&quot;1456&quot; data-origin-height=&quot;694&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;두 번째, 노션에 트러블 상황을 정리하기 시작했습니다. 하단에 첨부된 사진과 같이 어떤 문제가 발생한 상황을 구체적으로 설명하고 어떻게 해결했는지를 정리해두어 추후 비슷한 상황이 발생했을 때 당황하지 않고 빠른 대응이 가능하도록 해보았습니다. 또한 혜진님께서 도움을 주신 부분인데, Git을 사용하면서 특히 버그가 발생했을 때, 개발 중 develop 브랜치가 업데이트 되었을때, 로컬에서 브랜치 생성하는 방법 등을 명령어와 함께 설명해주셔서 이를 정리하여 팀원들께 공유할 수 있었습니다. 이는 Git을 사용할 때 매우 유용한 참고자료로 사용할 수 있었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1390&quot; data-origin-height=&quot;700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chqZ9Z/btsJUGbwNfd/KgXFZcwzqkpYM5KbZeYwpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chqZ9Z/btsJUGbwNfd/KgXFZcwzqkpYM5KbZeYwpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chqZ9Z/btsJUGbwNfd/KgXFZcwzqkpYM5KbZeYwpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchqZ9Z%2FbtsJUGbwNfd%2FKgXFZcwzqkpYM5KbZeYwpk%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;1390&quot; height=&quot;700&quot; data-origin-width=&quot;1390&quot; data-origin-height=&quot;700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dDZxFo/btsJUkUeYGl/hK37zDTfnskvMEkW1ydgj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dDZxFo/btsJUkUeYGl/hK37zDTfnskvMEkW1ydgj0/img.png&quot; data-origin-width=&quot;1456&quot; data-origin-height=&quot;812&quot; data-is-animation=&quot;false&quot; style=&quot;width: 43.4148%; margin-right: 10px;&quot; data-widthpercent=&quot;43.93&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dDZxFo/btsJUkUeYGl/hK37zDTfnskvMEkW1ydgj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdDZxFo%2FbtsJUkUeYGl%2FhK37zDTfnskvMEkW1ydgj0%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;1456&quot; height=&quot;812&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baqI93/btsJTphJwbq/WyhRvOvT6uZeMwRJVoXkiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baqI93/btsJTphJwbq/WyhRvOvT6uZeMwRJVoXkiK/img.png&quot; data-origin-width=&quot;1378&quot; data-origin-height=&quot;602&quot; data-is-animation=&quot;false&quot; style=&quot;width: 55.4224%;&quot; data-widthpercent=&quot;56.07&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baqI93/btsJTphJwbq/WyhRvOvT6uZeMwRJVoXkiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaqI93%2FbtsJTphJwbq%2FWyhRvOvT6uZeMwRJVoXkiK%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;1378&quot; height=&quot;602&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;- 팀 컨벤션&lt;/h3&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;git flow&lt;/h4&gt;
&lt;a id=&quot;user-content-git-flow&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/Dev-FE-1/Toy_Project_3_BeginAgain/wiki/Rule#git-flow&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;main: 개발 완료 후, 마지막에 사용할 브랜치&lt;/li&gt;
&lt;li&gt;develop: 개발 중 사용할 브랜치(프로젝트 기간 중 이 곳에 merge 해 주세요)&lt;/li&gt;
&lt;li&gt;feature: 각 기능 개발 시 사용할 브랜치&lt;/li&gt;
&lt;li&gt;bugfix: 버그 수정 시 사용할 브랜치&lt;/li&gt;
&lt;li&gt;style: 스타일 관련 변경사항이 있을 경우 사용할 브랜치&lt;/li&gt;
&lt;li&gt;help: 도움이 필요할 경우 사용할 브랜치&lt;/li&gt;
&lt;li&gt;test: 테스트 코드 추가 시 사용할 브랜치&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;PR규칙&lt;/h4&gt;
&lt;a id=&quot;user-content-pr규칙&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/Dev-FE-1/Toy_Project_3_BeginAgain/wiki/Rule#pr%EA%B7%9C%EC%B9%99&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PR을 올린 자신 이외에 2명의 승인이 있어야 merge할 수 있습니다&lt;/li&gt;
&lt;li&gt;승인을 한 사람이 머지와 브랜치 삭제까지 함께 진행합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;commit 규칙&lt;/h4&gt;
&lt;a id=&quot;user-content-commit-규칙&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/Dev-FE-1/Toy_Project_3_BeginAgain/wiki/Rule#commit-%EA%B7%9C%EC%B9%99&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커밋은 다음과 같은 형태로 작성합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1727917812390&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;keyword: 설명&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예시&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1727917806104&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git commit -m &quot;feature: 다크모드 라이트모드 기능 개발&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #1f2328; text-align: start;&quot;&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;- 코드 컨벤션&lt;/h4&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴포넌트 이름: PascalCase 사용&lt;/li&gt;
&lt;li&gt;폴더 이름: 소문자 사용&lt;/li&gt;
&lt;li&gt;이벤트 핸들러: 'on'으로 시작&lt;/li&gt;
&lt;li&gt;함수 및 변수명: camelCase 사용&lt;/li&gt;
&lt;li&gt;상수: 모두 대문자로 작성하고 단어 사이에&lt;span&gt;&amp;nbsp;&lt;/span&gt;_&lt;span&gt;&amp;nbsp;&lt;/span&gt;사용 ex)&lt;span&gt;&amp;nbsp;&lt;/span&gt;API_URL&lt;/li&gt;
&lt;li&gt;커스컴 훅(Custom Hook):&lt;span&gt;&amp;nbsp;&lt;/span&gt;use로 시작 ex)&lt;span&gt;&amp;nbsp;&lt;/span&gt;useInput&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;- 기술스택&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Front : React, Typescript, Vite, emotion, Zustand, TanStack Query, Playwright&lt;/li&gt;
&lt;li&gt;Back-end : Firebase&lt;/li&gt;
&lt;li&gt;버전 및 이슈관리 : Github, Github Issues&lt;/li&gt;
&lt;li&gt;협업 툴 : Slack, Notion, Zoom, ZEP&lt;/li&gt;
&lt;li&gt;서비스 배포 환경 : Netlify&lt;/li&gt;
&lt;li&gt;디자인 : Figma&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 주제와 목표&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희가 이번에 진행한 프로젝트는 영상공유 SNS 플랫폼 개발 프로젝트입니다. 사용자들이 만든 자신만의 영상 링크 기반(유튜브, Vimeo, Dailymotion, Twitch 등) 플레이 리스트를 공유하고, 구독하여 자신만의 타임 라인을 만들고 네트워킹 할 수 있는 SNS 서비스 구현을 해보는 것을 프로젝트 목표로 설정했습니다. 저희는 이에 그치지 않고 영상 공유에서 조금 더 주제를 좁혀보자는 의견에 따라 '운동 영상'을 공유하는 SNS 플랫폼으로 최종 결정하였습니다.&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;영상 링크를 사용자로부터 입력 받아 복수의 플레이리스트 작성 기능 개발&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;RESTful API를 설계하고 API 상태를 관리하며 다양한 UI 구성&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래 두 가지 중 선택
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;입력 받은 데이터를 전역 상태에만 추가해 UI 구성&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로그인 정보도 JSON 데이터로 관리&lt;/li&gt;
&lt;li&gt;RESTful API를 설계하여 API 통신으로 데이타를 불러와 다양한 UI를 구성하는 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공개된 플레이리스트를 구독하여 자신만의 플레이리스트 타임라인 기능 개발&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;영상에 좋아요, 댓글 기능 구현&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;React로 프로젝트 개발&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;React를 이용하여 프로젝트 내 모델의 타입 시스템을 설계, 구축하여 개발 생산성 및 안정성향상&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컴포넌트 아키텍처 모델 설계 필수&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;폴더 구분, 공통 컴포넌트, 함수 컴포넌트, 컨테이너 컴포넌트 등&lt;/li&gt;
&lt;li&gt;데이터와 UI(뷰) 역할을 적절히 분리하고 적절히 제어할 수 있는 컴포넌트 기반 프론트앤드 웹앱 아키텍처를 설계 및 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;전역 상태 관리자를 이용해 상태관리 아키텍처를 설계 구현&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴포넌트 기반 웹 앱 개발 구조에서 컴포넌트 상태와 전역 상태에 대한 이해를 바탕으로 적절한 상태 관리 아키텍처 설계 및 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;playwright, cypress 등 활용한 구축&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코드 기반 테스트에 대한 기술적 이해를 바탕으로 단위 테스트 및 종단 테스트를 적절히 활용한 구축&lt;/li&gt;
&lt;/ul&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;저희 팀은 아래 3가지 정도를 목표로 설정하여 프로젝트를 진행하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 다양한 기능 구현해보며 React + TypeScript에 익숙해지기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 개발 전반의 프로세스를 이해해가며 진행해보기&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 내가 맡은 파트 소개&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;- 프로젝트 초기 세팅&lt;/h3&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;figure id=&quot;og_1728258740795&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;React 프로젝트 시작하기 w. Vite&quot; data-og-description=&quot;Vite.js 빌드 도구를 사용해 React 프로젝트를 시작하는 방법을 살펴보며, 자바스크립트와 타입스크립트 프로젝트에서의 구성을 구분해 설명합니다.&quot; data-og-host=&quot;www.heropy.dev&quot; data-og-source-url=&quot;https://www.heropy.dev/p/6iFzkB&quot; data-og-url=&quot;https://www.heropy.dev/p/6iFzkB&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/kZ7tn/hyXegKEGEP/xCCwwxeWXv3U5MplfDRpk0/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=403_181_485_263,https://scrap.kakaocdn.net/dn/eGveW/hyXax1mtl4/sVCl7YIYoKJnyJpwxFsK80/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=403_181_485_263,https://scrap.kakaocdn.net/dn/cvdgTu/hyXeaKo9cd/klpfblJ8azL0dZsIpHKqkK/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=403_181_485_263&quot;&gt;&lt;a href=&quot;https://www.heropy.dev/p/6iFzkB&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.heropy.dev/p/6iFzkB&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/kZ7tn/hyXegKEGEP/xCCwwxeWXv3U5MplfDRpk0/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=403_181_485_263,https://scrap.kakaocdn.net/dn/eGveW/hyXax1mtl4/sVCl7YIYoKJnyJpwxFsK80/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=403_181_485_263,https://scrap.kakaocdn.net/dn/cvdgTu/hyXeaKo9cd/klpfblJ8azL0dZsIpHKqkK/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=403_181_485_263');&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;React 프로젝트 시작하기 w. Vite&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Vite.js 빌드 도구를 사용해 React 프로젝트를 시작하는 방법을 살펴보며, 자바스크립트와 타입스크립트 프로젝트에서의 구성을 구분해 설명합니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.heropy.dev&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;h3 data-ke-size=&quot;size23&quot;&gt;- 깃허브 위키 세팅&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깃허브로 상태 관리 및 협업을 진행하는 것에 익숙하지 않은 팀원들을 위해 이용 가이드를 업로드 하였습니다. 서윤님이 공유해주신 내용을 기반으로 설명 등을 약간 추가하여 저희 팀에 맞도록 수정하며 진행하였고, PR 생성 및 리뷰 방법, 이슈 및 브랜치 생성법, 기타 팀 규칙을 문서화하여 헷갈릴 때 편하게 확인할 수 있게 해보았습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1652&quot; data-origin-height=&quot;1000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/drn2wE/btsJV1A4esm/dBsPkDRqhBYaleN58CLg2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/drn2wE/btsJV1A4esm/dBsPkDRqhBYaleN58CLg2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/drn2wE/btsJV1A4esm/dBsPkDRqhBYaleN58CLg2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdrn2wE%2FbtsJV1A4esm%2FdBsPkDRqhBYaleN58CLg2K%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;1652&quot; height=&quot;1000&quot; data-origin-width=&quot;1652&quot; data-origin-height=&quot;1000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;1186&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5xUVf/btsJVV8HsuA/EYC6XdTDhtM0L5kLrXzFhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5xUVf/btsJVV8HsuA/EYC6XdTDhtM0L5kLrXzFhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5xUVf/btsJVV8HsuA/EYC6XdTDhtM0L5kLrXzFhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5xUVf%2FbtsJVV8HsuA%2FEYC6XdTDhtM0L5kLrXzFhk%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;1568&quot; height=&quot;1186&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;1186&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;- 공통 컴포넌트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공통 컴포넌트로는 Header, Navbar, Button, Layout, BottomSheet, EmptyInfo 컴포넌트를 만들어 보았습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Header와 Navbar&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lfWkx/btsJWySo3Q3/J2DiUgtFjBWLwDNxurDHHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lfWkx/btsJWySo3Q3/J2DiUgtFjBWLwDNxurDHHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lfWkx/btsJWySo3Q3/J2DiUgtFjBWLwDNxurDHHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlfWkx%2FbtsJWySo3Q3%2FJ2DiUgtFjBWLwDNxurDHHK%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;862&quot; height=&quot;1482&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LongButton과 ShortButton&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-10-07 at 9.16.45 AM.png&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;651&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GGMrh/btsJV96GHDC/EbW0XhNdhqFgvFu3Kl0h60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GGMrh/btsJV96GHDC/EbW0XhNdhqFgvFu3Kl0h60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GGMrh/btsJV96GHDC/EbW0XhNdhqFgvFu3Kl0h60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGGMrh%2FbtsJV96GHDC%2FEbW0XhNdhqFgvFu3Kl0h60%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;861&quot; height=&quot;651&quot; data-filename=&quot;Screenshot 2024-10-07 at 9.16.45 AM.png&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;651&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5G1cA/btsJW77TkwP/PXbbYn8k8jSuk14wz2yHFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5G1cA/btsJW77TkwP/PXbbYn8k8jSuk14wz2yHFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5G1cA/btsJW77TkwP/PXbbYn8k8jSuk14wz2yHFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5G1cA%2FbtsJW77TkwP%2FPXbbYn8k8jSuk14wz2yHFK%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;862&quot; height=&quot;1482&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;EmptyInfo: 데이터가 없을 때 보여줄 문구를 컴포넌트로 제작하여 조건에 부합할 때만 화면에 뜨도록 구현했습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4D1Jx/btsJW1mkgf1/RNdRJGTOF2ogp2UEAUrL1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4D1Jx/btsJW1mkgf1/RNdRJGTOF2ogp2UEAUrL1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4D1Jx/btsJW1mkgf1/RNdRJGTOF2ogp2UEAUrL1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4D1Jx%2FbtsJW1mkgf1%2FRNdRJGTOF2ogp2UEAUrL1k%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;862&quot; height=&quot;1482&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ButtomSheet: framer-motion으로 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screen Recording 2024-10-07 at 9.20.55 AM.gif&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WaGzi/btsJWovL9K2/e8Jxk8DbTW9BQgM2o2Dck1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WaGzi/btsJWovL9K2/e8Jxk8DbTW9BQgM2o2Dck1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WaGzi/btsJWovL9K2/e8Jxk8DbTW9BQgM2o2Dck1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/WaGzi/btsJWovL9K2/e8Jxk8DbTW9BQgM2o2Dck1/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;862&quot; height=&quot;1482&quot; data-filename=&quot;Screen Recording 2024-10-07 at 9.20.55 AM.gif&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&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;h3 data-ke-size=&quot;size23&quot;&gt;- 플레이리스트 페이지&lt;/h3&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;또한 카테고리에 따라 버튼을 눌러 필터 기능 역시 가능합니다. 해당 카테고리에 맞는 영상만 띄울 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2O7oX/btsJWqNTMyG/5K2XwV8tEoVK1Q8gZpMxdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2O7oX/btsJWqNTMyG/5K2XwV8tEoVK1Q8gZpMxdK/img.png&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2O7oX/btsJWqNTMyG/5K2XwV8tEoVK1Q8gZpMxdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2O7oX%2FbtsJWqNTMyG%2F5K2XwV8tEoVK1Q8gZpMxdK%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;862&quot; height=&quot;1482&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cg9RKc/btsJV3lbeJi/HNbC2Miu8gWydTrmFCsQbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cg9RKc/btsJV3lbeJi/HNbC2Miu8gWydTrmFCsQbk/img.png&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cg9RKc/btsJV3lbeJi/HNbC2Miu8gWydTrmFCsQbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcg9RKc%2FbtsJV3lbeJi%2FHNbC2Miu8gWydTrmFCsQbk%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;862&quot; height=&quot;1482&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OrXjc/btsJWjBiZCg/8W7zvnXPd5kZN4ZZUJGTMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OrXjc/btsJWjBiZCg/8W7zvnXPd5kZN4ZZUJGTMK/img.png&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OrXjc/btsJWjBiZCg/8W7zvnXPd5kZN4ZZUJGTMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOrXjc%2FbtsJWjBiZCg%2F8W7zvnXPd5kZN4ZZUJGTMK%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;862&quot; height=&quot;1482&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Jxn11/btsJW3xIprN/DxWNGNOKbY5THTIw1pBYY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Jxn11/btsJW3xIprN/DxWNGNOKbY5THTIw1pBYY1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&quot; data-filename=&quot;Screenshot 2024-10-07 at 9.29.44 AM.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Jxn11/btsJW3xIprN/DxWNGNOKbY5THTIw1pBYY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJxn11%2FbtsJW3xIprN%2FDxWNGNOKbY5THTIw1pBYY1%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;862&quot; height=&quot;1482&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;- 플레이리스트 상세페이지&lt;/h3&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;맨 위 부분에서 실제로 동영상 재생이 가능하고 재생 목록에 각 영상 썸네일을 클릭하여 재생하고 싶은 영상을 선택할 수 있습니다. 또한 드래그 앤 드롭 기능을 추가하여 영상 재생 순서를 바꿀 수 있고, 동영상 재생 부분은 재생 목록의 제일 첫 영상으로 설정되게끔 구현하였습니다. 재생목록 옆에는 포함된 영상의 개수를 표시하도록 하였고 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이는 삭제 시 자동으로 반영됩니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;4개 이상의 영상이 포함된 경우 스크롤을 통해 동영상을 확인할 수 있습니다. 각 영상의 오른쪽에 마련된 버튼을 클릭하면 동영상 삭제를 위한 바텀시트가 구현되고, 삭제 버튼을 누르면 영상을 삭제할 수 있습니다.&amp;nbsp;&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screen Recording 2024-10-07 at 9.33.02 AM.gif&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pCLVa/btsJVYEmh9G/xSZ4SWRocmYhNLkJX9LFRK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pCLVa/btsJVYEmh9G/xSZ4SWRocmYhNLkJX9LFRK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pCLVa/btsJVYEmh9G/xSZ4SWRocmYhNLkJX9LFRK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/pCLVa/btsJVYEmh9G/xSZ4SWRocmYhNLkJX9LFRK/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;862&quot; height=&quot;1482&quot; data-filename=&quot;Screen Recording 2024-10-07 at 9.33.02 AM.gif&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&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;h3 data-ke-size=&quot;size23&quot;&gt;- 플레이리스트 편집페이지&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;플레이리스트 상세 페이지에 있는 수정 버튼을 누르면 플레이리스트 편집 페이지로 이동하게 됩니다. 이 페이지로 넘어가게 되면 플레이리스트 제목, 설명, 카테고리, 공개 비공개 설정이 처음에 해당 플레이리스트를 생성했던 데이터 그대로 저장이 되어 수정할 수 있도록 구현했습니다. 또한 변경사항은 곧바로 플레이리스트 상세페이지와 플레이리스트 페이지에 반영됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screen Recording 2024-10-07 at 9.39.42 AM.gif&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dcEBug/btsJWU8PPn2/0mRqamF8GJpbRNKdduLxNK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dcEBug/btsJWU8PPn2/0mRqamF8GJpbRNKdduLxNK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dcEBug/btsJWU8PPn2/0mRqamF8GJpbRNKdduLxNK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/dcEBug/btsJWU8PPn2/0mRqamF8GJpbRNKdduLxNK/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;862&quot; height=&quot;1482&quot; data-filename=&quot;Screen Recording 2024-10-07 at 9.39.42 AM.gif&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;플레이리스트 페이지에도 바로 반영된 모습&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbewzh/btsJV6B8grb/4nWP99I33hejK9UgLHbTv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbewzh/btsJV6B8grb/4nWP99I33hejK9UgLHbTv0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;741&quot; data-filename=&quot;edited_Screenshot 2024-10-07 at 9.26.54 AM.png&quot; style=&quot;width: 49.347%; margin-right: 10px;&quot; data-widthpercent=&quot;49.93&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbewzh/btsJV6B8grb/4nWP99I33hejK9UgLHbTv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcbewzh%2FbtsJV6B8grb%2F4nWP99I33hejK9UgLHbTv0%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;862&quot; height=&quot;741&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpcyjl/btsJWTIPVNJ/FfRjSnrIQFKntAJraSonbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpcyjl/btsJWTIPVNJ/FfRjSnrIQFKntAJraSonbK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;738&quot; data-filename=&quot;Screenshot 2024-10-07 at 9.42.54 AM.png&quot; data-widthpercent=&quot;50.07&quot; style=&quot;width: 49.4902%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpcyjl/btsJWTIPVNJ/FfRjSnrIQFKntAJraSonbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbpcyjl%2FbtsJWTIPVNJ%2FFfRjSnrIQFKntAJraSonbK%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;861&quot; height=&quot;738&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;- 테스트 코드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트는 playwright를 사용하여 진행하였습니다. 시간이 넉넉하지 않아 로그인 화면 정도 테스트 코드를 구현해보았습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1446&quot; data-origin-height=&quot;1192&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m2vQA/btsJVs62iBu/eiurG6rTG1HB89jRbUvzmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m2vQA/btsJVs62iBu/eiurG6rTG1HB89jRbUvzmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m2vQA/btsJVs62iBu/eiurG6rTG1HB89jRbUvzmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm2vQA%2FbtsJVs62iBu%2FeiurG6rTG1HB89jRbUvzmK%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;1446&quot; height=&quot;1192&quot; data-origin-width=&quot;1446&quot; data-origin-height=&quot;1192&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;h2 data-ke-size=&quot;size26&quot;&gt;7. 더 많은 페이지들&lt;/h2&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;h3 data-ke-size=&quot;size23&quot;&gt;- 로그인 페이지&lt;/h3&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-origin-width=&quot;862&quot; data-origin-height=&quot;1482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dq5Dfu/btsJXsxi002/xw3LQrktz1V843YyYnlRnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dq5Dfu/btsJXsxi002/xw3LQrktz1V843YyYnlRnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dq5Dfu/btsJXsxi002/xw3LQrktz1V843YyYnlRnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdq5Dfu%2FbtsJXsxi002%2Fxw3LQrktz1V843YyYnlRnk%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;862&quot; height=&quot;1482&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&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;h3 data-ke-size=&quot;size23&quot;&gt;- 홈페이지&lt;/h3&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;해당 플레이리스트를 생성한 유저의 사진과 닉네임이 보이며 이는 네트워킹 페이지에도 반영됩니다. 이 페이지와 무한 스크롤은 난아님이 구현해주셨고 특히 무한 스크롤 부분은 멘토님께서도 고민한 흔적이 보이신다고 하면서 좋은 피드백을 주셨습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/V6WUv/btsJV3rRkXG/WuVnm7zBNToCb6nxPJpc8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/V6WUv/btsJV3rRkXG/WuVnm7zBNToCb6nxPJpc8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/V6WUv/btsJV3rRkXG/WuVnm7zBNToCb6nxPJpc8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FV6WUv%2FbtsJV3rRkXG%2FWuVnm7zBNToCb6nxPJpc8K%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;862&quot; height=&quot;1482&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;무한 스크롤 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screen Recording 2024-10-07 at 10.04.13 AM.gif&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bT89Ge/btsJVCaJo7w/S41iD9YDFCdtvO2P3mrVek/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bT89Ge/btsJVCaJo7w/S41iD9YDFCdtvO2P3mrVek/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bT89Ge/btsJVCaJo7w/S41iD9YDFCdtvO2P3mrVek/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bT89Ge/btsJVCaJo7w/S41iD9YDFCdtvO2P3mrVek/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;862&quot; height=&quot;1482&quot; data-filename=&quot;Screen Recording 2024-10-07 at 10.04.13 AM.gif&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&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;h3 data-ke-size=&quot;size23&quot;&gt;- 네트워킹 페이지&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 페이지에서는 영상 시청 및 댓글을 통해 다른 유저와 소통하는 것이 중심 역할입니다. 다른 유저의 플레이리스트를 시청하는 것이기 때문에 플레이리스트 상세페이지와 달리 공개 비공개 설정이나 정보 수정 및 삭제 기능은 넣지 않았습니다. 모션 효과 이외의 댓글 섹션은 난아님이 구현해주셨습니다. 댓글 부분을 누르면 바텀시트가 나와 댓글을 작성할 수 있고 댓글 삭제가 가능합니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oEba2/btsJVrmMfcY/JEz8wBFGTKosW12fbplfyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oEba2/btsJVrmMfcY/JEz8wBFGTKosW12fbplfyK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&quot; data-filename=&quot;Screenshot 2024-10-07 at 10.09.12 AM.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oEba2/btsJVrmMfcY/JEz8wBFGTKosW12fbplfyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoEba2%2FbtsJVrmMfcY%2FJEz8wBFGTKosW12fbplfyK%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;862&quot; height=&quot;1482&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dvnCnD/btsJVX6vLOB/mWeC801qW3NbnnqAeNP6W1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dvnCnD/btsJVX6vLOB/mWeC801qW3NbnnqAeNP6W1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&quot; data-filename=&quot;Screenshot 2024-10-07 at 10.09.38 AM.png&quot; data-widthpercent=&quot;50&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dvnCnD/btsJVX6vLOB/mWeC801qW3NbnnqAeNP6W1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdvnCnD%2FbtsJVX6vLOB%2FmWeC801qW3NbnnqAeNP6W1%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;862&quot; height=&quot;1482&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;- 플레이리스트 추가 페이지&lt;/h3&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-origin-width=&quot;948&quot; data-origin-height=&quot;1472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nQSwm/btsJWAbGeqm/JpjEG3o46Pd4VpyHvpKYIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nQSwm/btsJWAbGeqm/JpjEG3o46Pd4VpyHvpKYIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nQSwm/btsJWAbGeqm/JpjEG3o46Pd4VpyHvpKYIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnQSwm%2FbtsJWAbGeqm%2FJpjEG3o46Pd4VpyHvpKYIk%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;948&quot; height=&quot;1472&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;1472&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;h3 data-ke-size=&quot;size23&quot;&gt;- 북마크 페이지&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;북마크 페이지는 연지님이 작업해주셨습니다. 특히 드롭앤 드롭 기능과 북마크 기능, 토스트 기능은 여러 페이지를 연결하는 것이라 까다로운 작업인데 성공적으로 수행해주셨습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmPFRt/btsJVqOVa57/ouRCvTkSK1aorPSdCq6iK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmPFRt/btsJVqOVa57/ouRCvTkSK1aorPSdCq6iK1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&quot; data-filename=&quot;Screenshot 2024-10-07 at 9.57.23 AM.png&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmPFRt/btsJVqOVa57/ouRCvTkSK1aorPSdCq6iK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmPFRt%2FbtsJVqOVa57%2FouRCvTkSK1aorPSdCq6iK1%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;862&quot; height=&quot;1482&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfMn9g/btsJWwtFqGO/kAzjyNpzCJwhjSj4jkab2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfMn9g/btsJWwtFqGO/kAzjyNpzCJwhjSj4jkab2k/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&quot; data-filename=&quot;Screenshot 2024-10-07 at 9.57.35 AM.png&quot; data-widthpercent=&quot;33.33&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfMn9g/btsJWwtFqGO/kAzjyNpzCJwhjSj4jkab2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfMn9g%2FbtsJWwtFqGO%2FkAzjyNpzCJwhjSj4jkab2k%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;862&quot; height=&quot;1482&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWy32M/btsJV6Wq4R0/tiN5ULj9Gn3Ifm49TLqY3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWy32M/btsJV6Wq4R0/tiN5ULj9Gn3Ifm49TLqY3k/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&quot; data-filename=&quot;Screenshot 2024-10-07 at 9.57.45 AM.png&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWy32M/btsJV6Wq4R0/tiN5ULj9Gn3Ifm49TLqY3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWy32M%2FbtsJV6Wq4R0%2FtiN5ULj9Gn3Ifm49TLqY3k%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;862&quot; height=&quot;1482&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;- 프로필 페이지&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 페이지에서는 닉네임과 이메일을 확인할 수 있고 수정 페이지에서는 닉네임과 사진을 수정할 수 있습니다. 영은님이 작업해주셨고 정보 수정 시 바로 다른 페이지에 반영됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cY0l3M/btsJWs5NF7R/KWdesybVTGoJ1kjWsddYV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cY0l3M/btsJWs5NF7R/KWdesybVTGoJ1kjWsddYV1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&quot; data-filename=&quot;edited_Screenshot 2024-10-07 at 9.54.29 AM.png&quot; data-widthpercent=&quot;50&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cY0l3M/btsJWs5NF7R/KWdesybVTGoJ1kjWsddYV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcY0l3M%2FbtsJWs5NF7R%2FKWdesybVTGoJ1kjWsddYV1%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;862&quot; height=&quot;1482&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1ofIr/btsJWtwUsRp/tVSlBsoTJgQcip1Aw6Utq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1ofIr/btsJWtwUsRp/tVSlBsoTJgQcip1Aw6Utq0/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&quot; data-filename=&quot;edited_Screenshot 2024-10-07 at 9.54.35 AM.png&quot; data-widthpercent=&quot;50&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1ofIr/btsJWtwUsRp/tVSlBsoTJgQcip1Aw6Utq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1ofIr%2FbtsJWtwUsRp%2FtVSlBsoTJgQcip1Aw6Utq0%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;862&quot; height=&quot;1482&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;- 오류 페이지&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;난아님이 구현해주신 페이지로, 잘못된 경로로 접근했을 때 뜨는 404 화면입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q3mTy/btsJVUIHzcM/KjH7IKTG5pLf2dNVk9gavk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q3mTy/btsJVUIHzcM/KjH7IKTG5pLf2dNVk9gavk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q3mTy/btsJVUIHzcM/KjH7IKTG5pLf2dNVk9gavk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ3mTy%2FbtsJVUIHzcM%2FKjH7IKTG5pLf2dNVk9gavk%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;862&quot; height=&quot;1482&quot; data-origin-width=&quot;862&quot; data-origin-height=&quot;1482&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;h2 data-ke-size=&quot;size26&quot;&gt;8. 리팩토링&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리팩토링은 프로젝트가 끝난 뒤 '9/30 - 10/4'에 진행하였습니다. 코드리뷰용 PR을 올리고 멘토님이 코드 리뷰를 하는 식으로 진행하였습니다. 추가 설명이 필요한 부분은 Zoom에서 진행한 실시간 멘토링을 통해 해결하였습니다. 이 과정에서 onError를 사용하는 것과 에러를 throw 했을 때의 장단점과 차이점, 옵셔널 체이닝 사용 시 주의점 그리고 유닛 테스트에 대한 중요성을 알게 되었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;1316&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cteota/btsJVpiclSL/taUvOcjuGKWFMJ7QPsc3TK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cteota/btsJVpiclSL/taUvOcjuGKWFMJ7QPsc3TK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cteota/btsJVpiclSL/taUvOcjuGKWFMJ7QPsc3TK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcteota%2FbtsJVpiclSL%2FtaUvOcjuGKWFMJ7QPsc3TK%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;948&quot; height=&quot;1316&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;1316&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;1182&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3QGHa/btsJXu2XlkA/pPkMkZ6nbiiP8W5sW5HENk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3QGHa/btsJXu2XlkA/pPkMkZ6nbiiP8W5sW5HENk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3QGHa/btsJXu2XlkA/pPkMkZ6nbiiP8W5sW5HENk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3QGHa%2FbtsJXu2XlkA%2FpPkMkZ6nbiiP8W5sW5HENk%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;948&quot; height=&quot;1182&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;1182&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;1084&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCjkYI/btsJV0PJNKA/OkMarTAtXGgr85wOPrhky0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCjkYI/btsJV0PJNKA/OkMarTAtXGgr85wOPrhky0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCjkYI/btsJV0PJNKA/OkMarTAtXGgr85wOPrhky0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCjkYI%2FbtsJV0PJNKA%2FOkMarTAtXGgr85wOPrhky0%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;948&quot; height=&quot;1084&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;1084&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;h2 data-ke-size=&quot;size26&quot;&gt;9. 회고&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Keep: 이번 프로젝트에서 잘 한 점&lt;/h3&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;h3 data-ke-size=&quot;size23&quot;&gt;Problem: 문제가 있었거나 개선해야 할 점&lt;/h3&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;h3 data-ke-size=&quot;size23&quot;&gt;Try: 다음 프로젝트에서 시도해볼 점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 리팩토링 때 E2E 테스트 뿐만 아니라 유닛 테스트의 중요성도 알게되어 다음 프로젝트에서는 유닛 테스트를 진행해보고 싶습니다.&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;</description>
      <category>Project</category>
      <category>부트캠프</category>
      <category>웹개발</category>
      <category>토이프로젝트3</category>
      <category>프로젝트</category>
      <category>프론트엔드개발</category>
      <category>회고</category>
      <author>dearsuhyun</author>
      <guid isPermaLink="true">https://diveintodevworld.tistory.com/80</guid>
      <comments>https://diveintodevworld.tistory.com/80#entry80comment</comments>
      <pubDate>Mon, 7 Oct 2024 10:51:42 +0900</pubDate>
    </item>
    <item>
      <title>서비스 기획 특강</title>
      <link>https://diveintodevworld.tistory.com/79</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;User Story(사용자 스토리)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Team의 컨센서스(합의)를 맞추기 위해서 필요, 모두가 다른 생각을 할 수 있기 때문&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 스프린트에 여러 유저 스토리가 있을 수 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IPM (iteration/sprint planning meeting) = weekly meeting, 다음주에 뭐 할지에 대한 회의 ?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유저스토리(예: 사용자는 ~~할 수 있다)에 대한 피드백을 잘 주는 것이 필요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2주 단위로 회의를 하는 것은 프로덕트 팀의 생산성을 측정하면서 스토리 포인트라는 것을 준다 !&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;884&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JziXT/btsJQKffEot/CaVdMAwrRJWFuUwaq2YVB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JziXT/btsJQKffEot/CaVdMAwrRJWFuUwaq2YVB0/img.png&quot; data-alt=&quot;프로젝트에 적용해보기, 점수가 5,6 넘어간다면 더 작게 쪼개기 !&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JziXT/btsJQKffEot/CaVdMAwrRJWFuUwaq2YVB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJziXT%2FbtsJQKffEot%2FCaVdMAwrRJWFuUwaq2YVB0%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;1512&quot; height=&quot;884&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;884&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;프로젝트에 적용해보기, 점수가 5,6 넘어간다면 더 작게 쪼개기 !&lt;/figcaption&gt;
&lt;/figure&gt;
&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;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스모크 테스트: PM이 진행, 결제나 회원가입 중 중요한 기능 테스트&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;패스트캠퍼스.jpeg&quot; data-origin-width=&quot;1369&quot; data-origin-height=&quot;779&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dcc3ZY/btsJSuhAW80/DLktMCvJArUShIJvqjmAV0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dcc3ZY/btsJSuhAW80/DLktMCvJArUShIJvqjmAV0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dcc3ZY/btsJSuhAW80/DLktMCvJArUShIJvqjmAV0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdcc3ZY%2FbtsJSuhAW80%2FDLktMCvJArUShIJvqjmAV0%2Fimg.jpg&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;1369&quot; height=&quot;779&quot; data-filename=&quot;패스트캠퍼스.jpeg&quot; data-origin-width=&quot;1369&quot; data-origin-height=&quot;779&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;h4 data-ke-size=&quot;size20&quot;&gt;회의 방식&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- daily scrum (stand up)&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 포인트는 avoid big loss --&amp;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;- IPM(Iteration Planning Meeting)&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;/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;- weekly retro&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;* PRD(product requirement Doc)&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;/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;h4 data-ke-size=&quot;size20&quot;&gt;팀 협업 사례&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex. 사용자 리서치: 디자인적인 엣지가 필요한 프로젝트인가 ? 서비스적인 탄탄함이 필요한 프로젝트인가 ?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-09-30 at 3.35.42 PM.jpeg&quot; data-origin-width=&quot;1174&quot; data-origin-height=&quot;625&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brE811/btsJRPGP5Xz/zmy29ySFFCUkiflKJBfpt1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brE811/btsJRPGP5Xz/zmy29ySFFCUkiflKJBfpt1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brE811/btsJRPGP5Xz/zmy29ySFFCUkiflKJBfpt1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrE811%2FbtsJRPGP5Xz%2Fzmy29ySFFCUkiflKJBfpt1%2Fimg.jpg&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;1174&quot; height=&quot;625&quot; data-filename=&quot;Screenshot 2024-09-30 at 3.35.42 PM.jpeg&quot; data-origin-width=&quot;1174&quot; data-origin-height=&quot;625&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;h4 data-ke-size=&quot;size20&quot;&gt;Retrospective 회고&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;회고는 서로를 탓하기 위해서 하는 것이 아니라, 앞으로 더 나은 방향으로 나아가기 위한 회의 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 지속할 것(keep)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 해결할 것(problem)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 시도할 것(try)&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;- 4Ls&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1742&quot; data-origin-height=&quot;770&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XdWxN/btsJQXlixkZ/tW0d47w0u5qPSQ2jkJrcw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XdWxN/btsJQXlixkZ/tW0d47w0u5qPSQ2jkJrcw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XdWxN/btsJQXlixkZ/tW0d47w0u5qPSQ2jkJrcw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXdWxN%2FbtsJQXlixkZ%2FtW0d47w0u5qPSQ2jkJrcw1%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;1742&quot; height=&quot;770&quot; data-origin-width=&quot;1742&quot; data-origin-height=&quot;770&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- sail boats (그림 활용)&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;lt; 다음 프로젝트에서 해보기 &amp;gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 작업에 대한 스토리 포인트 매겨보기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 회고해보기&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;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://trello.com/?campaign=18422680943&amp;amp;adgroup=142052238135&amp;amp;targetid=kwd-3609071462&amp;amp;matchtype=p&amp;amp;network=g&amp;amp;device=c&amp;amp;device_model=&amp;amp;creative=672183050151&amp;amp;keyword=trello&amp;amp;placement=&amp;amp;target=&amp;amp;ds_eid=700000001557344&amp;amp;ds_e1=GOOGLE&amp;amp;gad_source=1&amp;amp;gclid=CjwKCAjw9eO3BhBNEiwAoc0-jbH8nzHGgXz1K4zwNO707P9pVXsYLYgCqN1DlxL4SWd_svlymGUxiRoCi4EQAvD_BwE&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://trello.com/?campaign=18422680943&amp;amp;adgroup=142052238135&amp;amp;targetid=kwd-3609071462&amp;amp;matchtype=p&amp;amp;network=g&amp;amp;device=c&amp;amp;device_model=&amp;amp;creative=672183050151&amp;amp;keyword=trello&amp;amp;placement=&amp;amp;target=&amp;amp;ds_eid=700000001557344&amp;amp;ds_e1=GOOGLE&amp;amp;gad_source=1&amp;amp;gclid=CjwKCAjw9eO3BhBNEiwAoc0-jbH8nzHGgXz1K4zwNO707P9pVXsYLYgCqN1DlxL4SWd_svlymGUxiRoCi4EQAvD_BwE&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1727674238320&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;Manage Your Team&amp;rsquo;s Projects From Anywhere | Trello&quot; data-og-description=&quot;Task management Use Trello to track, manage, complete, and bring tasks together like the pieces of a puzzle, and make your team&amp;rsquo;s projects a cohesive success every time.&quot; data-og-host=&quot;trello.com&quot; data-og-source-url=&quot;https://trello.com/?campaign=18422680943&amp;amp;adgroup=142052238135&amp;amp;targetid=kwd-3609071462&amp;amp;matchtype=p&amp;amp;network=g&amp;amp;device=c&amp;amp;device_model=&amp;amp;creative=672183050151&amp;amp;keyword=trello&amp;amp;placement=&amp;amp;target=&amp;amp;ds_eid=700000001557344&amp;amp;ds_e1=GOOGLE&amp;amp;gad_source=1&amp;amp;gclid=CjwKCAjw9eO3BhBNEiwAoc0-jbH8nzHGgXz1K4zwNO707P9pVXsYLYgCqN1DlxL4SWd_svlymGUxiRoCi4EQAvD_BwE&quot; data-og-url=&quot;https://trello.com/?adgroup=142052238135&amp;amp;campaign=18422680943&amp;amp;creative=672183050151&amp;amp;device=c&amp;amp;device_model=&amp;amp;ds_e1=GOOGLE&amp;amp;ds_eid=700000001557344&amp;amp;gad_source=1&amp;amp;gclid=CjwKCAjw9eO3BhBNEiwAoc0-jbH8nzHGgXz1K4zwNO707P9pVXsYLYgCqN1DlxL4SWd_svlymGUxiRoCi4EQAvD_BwE&amp;amp;keyword=trello&amp;amp;matchtype=p&amp;amp;network=g&amp;amp;placement=&amp;amp;target=&amp;amp;targetid=kwd-3609071462&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/g859B/hyXaAP5KCV/wyIgqLtELJeHRnl0zPqcf1/img.png?width=540&amp;amp;height=476&amp;amp;face=0_0_540_476,https://scrap.kakaocdn.net/dn/puF1G/hyXaF4Vc0z/SHEKHIcQLL7c4sAb3LSJEk/img.png?width=540&amp;amp;height=292&amp;amp;face=0_0_540_292,https://scrap.kakaocdn.net/dn/biRxYZ/hyXaxeLGKl/HUV0Yl6jMy1U0lITGqQfLK/img.png?width=540&amp;amp;height=292&amp;amp;face=0_0_540_292&quot;&gt;&lt;a href=&quot;https://trello.com/?campaign=18422680943&amp;amp;adgroup=142052238135&amp;amp;targetid=kwd-3609071462&amp;amp;matchtype=p&amp;amp;network=g&amp;amp;device=c&amp;amp;device_model=&amp;amp;creative=672183050151&amp;amp;keyword=trello&amp;amp;placement=&amp;amp;target=&amp;amp;ds_eid=700000001557344&amp;amp;ds_e1=GOOGLE&amp;amp;gad_source=1&amp;amp;gclid=CjwKCAjw9eO3BhBNEiwAoc0-jbH8nzHGgXz1K4zwNO707P9pVXsYLYgCqN1DlxL4SWd_svlymGUxiRoCi4EQAvD_BwE&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://trello.com/?campaign=18422680943&amp;amp;adgroup=142052238135&amp;amp;targetid=kwd-3609071462&amp;amp;matchtype=p&amp;amp;network=g&amp;amp;device=c&amp;amp;device_model=&amp;amp;creative=672183050151&amp;amp;keyword=trello&amp;amp;placement=&amp;amp;target=&amp;amp;ds_eid=700000001557344&amp;amp;ds_e1=GOOGLE&amp;amp;gad_source=1&amp;amp;gclid=CjwKCAjw9eO3BhBNEiwAoc0-jbH8nzHGgXz1K4zwNO707P9pVXsYLYgCqN1DlxL4SWd_svlymGUxiRoCi4EQAvD_BwE&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/g859B/hyXaAP5KCV/wyIgqLtELJeHRnl0zPqcf1/img.png?width=540&amp;amp;height=476&amp;amp;face=0_0_540_476,https://scrap.kakaocdn.net/dn/puF1G/hyXaF4Vc0z/SHEKHIcQLL7c4sAb3LSJEk/img.png?width=540&amp;amp;height=292&amp;amp;face=0_0_540_292,https://scrap.kakaocdn.net/dn/biRxYZ/hyXaxeLGKl/HUV0Yl6jMy1U0lITGqQfLK/img.png?width=540&amp;amp;height=292&amp;amp;face=0_0_540_292');&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;Manage Your Team&amp;rsquo;s Projects From Anywhere | Trello&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Task management Use Trello to track, manage, complete, and bring tasks together like the pieces of a puzzle, and make your team&amp;rsquo;s projects a cohesive success every time.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;trello.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.atlassian.com/ko/software/jira?campaign=19324540289&amp;amp;adgroup=143040571645&amp;amp;targetid=kwd-1419570311017&amp;amp;matchtype=e&amp;amp;network=g&amp;amp;device=c&amp;amp;device_model=&amp;amp;creative=642069034929&amp;amp;keyword=%EC%A7%80%EB%9D%BC%20%EC%82%AC%EC%9A%A9%EB%B2%95&amp;amp;placement=&amp;amp;target=&amp;amp;ds_eid=700000001558501&amp;amp;ds_e1=GOOGLE&amp;amp;gad_source=1&amp;amp;gclid=CjwKCAjw9eO3BhBNEiwAoc0-jV6db50068Q52VMdCa88dzG2ltqp7g6pgqxIKuUZHL7sjcYVQTNvPBoCZKAQAvD_BwE&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.atlassian.com/ko/software/jira?campaign=19324540289&amp;amp;adgroup=143040571645&amp;amp;targetid=kwd-1419570311017&amp;amp;matchtype=e&amp;amp;network=g&amp;amp;device=c&amp;amp;device_model=&amp;amp;creative=642069034929&amp;amp;keyword=%EC%A7%80%EB%9D%BC%20%EC%82%AC%EC%9A%A9%EB%B2%95&amp;amp;placement=&amp;amp;target=&amp;amp;ds_eid=700000001558501&amp;amp;ds_e1=GOOGLE&amp;amp;gad_source=1&amp;amp;gclid=CjwKCAjw9eO3BhBNEiwAoc0-jV6db50068Q52VMdCa88dzG2ltqp7g6pgqxIKuUZHL7sjcYVQTNvPBoCZKAQAvD_BwE&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1727674267875&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;Jira | 이슈 및 프로젝트 추적 소프트웨어 | Atlassian&quot; data-og-description=&quot;Jira에서 불가능을 가능으로 바꾸세요. 애자일 팀을 위한 최고의 프로젝트 관리 도구로 세계적인 수준의 소프트웨어를 계획, 추적 및 릴리스하세요.&quot; data-og-host=&quot;www.atlassian.com&quot; data-og-source-url=&quot;https://www.atlassian.com/ko/software/jira?campaign=19324540289&amp;amp;adgroup=143040571645&amp;amp;targetid=kwd-1419570311017&amp;amp;matchtype=e&amp;amp;network=g&amp;amp;device=c&amp;amp;device_model=&amp;amp;creative=642069034929&amp;amp;keyword=%EC%A7%80%EB%9D%BC%20%EC%82%AC%EC%9A%A9%EB%B2%95&amp;amp;placement=&amp;amp;target=&amp;amp;ds_eid=700000001558501&amp;amp;ds_e1=GOOGLE&amp;amp;gad_source=1&amp;amp;gclid=CjwKCAjw9eO3BhBNEiwAoc0-jV6db50068Q52VMdCa88dzG2ltqp7g6pgqxIKuUZHL7sjcYVQTNvPBoCZKAQAvD_BwE&quot; data-og-url=&quot;https://www.atlassian.com/ko/software/jira&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bdpxvp/hyXay5NfZ9/qDQaaEfGqQQ5K4KPOpEkXK/img.png?width=1168&amp;amp;height=153&amp;amp;face=0_0_1168_153,https://scrap.kakaocdn.net/dn/nM5Up/hyXaC1s2Wo/RN6ucKYDkkJ9MDF1BWZ6e0/img.png?width=147&amp;amp;height=153&amp;amp;face=0_0_147_153,https://scrap.kakaocdn.net/dn/cS1Kg1/hyXaBaoy6Z/BHag5HLcoa5q8Q530kjJbK/img.png?width=2880&amp;amp;height=1720&amp;amp;face=0_0_2880_1720&quot;&gt;&lt;a href=&quot;https://www.atlassian.com/ko/software/jira?campaign=19324540289&amp;amp;adgroup=143040571645&amp;amp;targetid=kwd-1419570311017&amp;amp;matchtype=e&amp;amp;network=g&amp;amp;device=c&amp;amp;device_model=&amp;amp;creative=642069034929&amp;amp;keyword=%EC%A7%80%EB%9D%BC%20%EC%82%AC%EC%9A%A9%EB%B2%95&amp;amp;placement=&amp;amp;target=&amp;amp;ds_eid=700000001558501&amp;amp;ds_e1=GOOGLE&amp;amp;gad_source=1&amp;amp;gclid=CjwKCAjw9eO3BhBNEiwAoc0-jV6db50068Q52VMdCa88dzG2ltqp7g6pgqxIKuUZHL7sjcYVQTNvPBoCZKAQAvD_BwE&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.atlassian.com/ko/software/jira?campaign=19324540289&amp;amp;adgroup=143040571645&amp;amp;targetid=kwd-1419570311017&amp;amp;matchtype=e&amp;amp;network=g&amp;amp;device=c&amp;amp;device_model=&amp;amp;creative=642069034929&amp;amp;keyword=%EC%A7%80%EB%9D%BC%20%EC%82%AC%EC%9A%A9%EB%B2%95&amp;amp;placement=&amp;amp;target=&amp;amp;ds_eid=700000001558501&amp;amp;ds_e1=GOOGLE&amp;amp;gad_source=1&amp;amp;gclid=CjwKCAjw9eO3BhBNEiwAoc0-jV6db50068Q52VMdCa88dzG2ltqp7g6pgqxIKuUZHL7sjcYVQTNvPBoCZKAQAvD_BwE&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bdpxvp/hyXay5NfZ9/qDQaaEfGqQQ5K4KPOpEkXK/img.png?width=1168&amp;amp;height=153&amp;amp;face=0_0_1168_153,https://scrap.kakaocdn.net/dn/nM5Up/hyXaC1s2Wo/RN6ucKYDkkJ9MDF1BWZ6e0/img.png?width=147&amp;amp;height=153&amp;amp;face=0_0_147_153,https://scrap.kakaocdn.net/dn/cS1Kg1/hyXaBaoy6Z/BHag5HLcoa5q8Q530kjJbK/img.png?width=2880&amp;amp;height=1720&amp;amp;face=0_0_2880_1720');&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;Jira | 이슈 및 프로젝트 추적 소프트웨어 | Atlassian&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Jira에서 불가능을 가능으로 바꾸세요. 애자일 팀을 위한 최고의 프로젝트 관리 도구로 세계적인 수준의 소프트웨어를 계획, 추적 및 릴리스하세요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.atlassian.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kinghong.notion.site/2dcd479ea6d341fe9ff383f9f4b8fded&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kinghong.notion.site/2dcd479ea6d341fe9ff383f9f4b8fded&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1727674341421&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;프로젝트 매니지먼트 | Notion&quot; data-og-description=&quot;Trello board :&quot; data-og-host=&quot;kinghong.notion.site&quot; data-og-source-url=&quot;https://kinghong.notion.site/2dcd479ea6d341fe9ff383f9f4b8fded&quot; data-og-url=&quot;https://kinghong.notion.site/2dcd479ea6d341fe9ff383f9f4b8fded&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/kMVkj/hyXaH9uWYV/VkCHKmAlR87XkZKuiZuaBK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cvmEWI/hyXaIHmhhA/Eh64pKNKQMhElBgFT0U8v0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://kinghong.notion.site/2dcd479ea6d341fe9ff383f9f4b8fded&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kinghong.notion.site/2dcd479ea6d341fe9ff383f9f4b8fded&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/kMVkj/hyXaH9uWYV/VkCHKmAlR87XkZKuiZuaBK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cvmEWI/hyXaIHmhhA/Eh64pKNKQMhElBgFT0U8v0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;프로젝트 매니지먼트 | Notion&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Trello board :&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kinghong.notion.site&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;</description>
      <category>Live Class</category>
      <author>dearsuhyun</author>
      <guid isPermaLink="true">https://diveintodevworld.tistory.com/79</guid>
      <comments>https://diveintodevworld.tistory.com/79#entry79comment</comments>
      <pubDate>Mon, 30 Sep 2024 16:00:36 +0900</pubDate>
    </item>
    <item>
      <title>Beginner 17회차 (8/27) | json-server, HMR (Hot Module Replacement), Tanstack Query</title>
      <link>https://diveintodevworld.tistory.com/77</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;json-server&lt;/h2&gt;
&lt;pre id=&quot;code_1724721798375&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i -D json-server concurrently

// json-server랑 vite 서버 동시에 켜기 위해서 concurrently&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;pakage.json&lt;/p&gt;
&lt;pre id=&quot;code_1724722414691&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;scripts&quot;: {
    &quot;watch:json-server&quot;: &quot;json-server db.json --port 1234&quot;,
    // db.json 파일을 실행
    &quot;watch:vite&quot;: &quot;vite&quot;,
    &quot;dev&quot;: &quot;concurrently npm:watch:*&quot;,&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;db.json&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 베이스 직접 만들기&lt;/p&gt;
&lt;pre id=&quot;code_1724722763886&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;todos&quot;: [
    {
      &quot;id&quot;: &quot;abc&quot;,
      &quot;title&quot;: &quot;hello world&quot;,
      &quot;done&quot;: false
    }
  ],
  &quot;users&quot;: [],
  &quot;posts&quot;: []
}&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;main.tsx&lt;/p&gt;
&lt;pre id=&quot;code_1724724072095&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 즉시 실행 함수
(async () =&amp;gt; {
  // 기본값 = GET
  const res = await fetch(&quot;http://localhost:1234/todos&quot;);
  const data = await res.json();
  console.log(data);
})();&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;npm run dev 하면 콘솔에 이렇게 내가 만든 데이터가 뜬다&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;1110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0Wik0/btsJgfT260K/xexU0rQXSBroIC2WKvr6W1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0Wik0/btsJgfT260K/xexU0rQXSBroIC2WKvr6W1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0Wik0/btsJgfT260K/xexU0rQXSBroIC2WKvr6W1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0Wik0%2FbtsJgfT260K%2FxexU0rQXSBroIC2WKvr6W1%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;844&quot; height=&quot;1110&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;1110&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;h3 data-ke-size=&quot;size23&quot;&gt;요청 메소드&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GET 조회 (read) &lt;b&gt;default,&amp;nbsp; &lt;/b&gt;&lt;b&gt;body 부분을 첨부할 수 없음 (안하는게 아니라 못함)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;POST 생성 (create)&lt;/li&gt;
&lt;li&gt;PUT 전체 수정 (update)&lt;/li&gt;
&lt;li&gt;PATCH 일부 수정 (json-server에서는 일부 수정으로 사용 ! api 마다 다름)&lt;/li&gt;
&lt;li&gt;DELETE 삭제 (delete)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RESTful 하다 --&amp;gt; CRUD의 쓰임에 맞게 api를 사용한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;json-server 사용 실습&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;POST&lt;/h4&gt;
&lt;pre id=&quot;code_1724724917715&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 즉시 실행 함수
(async () =&amp;gt; {
  // 기본값 = GET
  const res = await fetch(&quot;http://localhost:1234/todos&quot;, {
    method: &quot;POST&quot;,
    body: JSON.stringify({
      title: &quot;아침 먹기&quot;,
      done: true,
    }),
  });
  const data = await res.json();
  console.log(data);
})();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screen Recording 2024-08-27 at 11.14.12 AM.gif&quot; data-origin-width=&quot;2940&quot; data-origin-height=&quot;1912&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbLuCd/btsJhgka5s1/Rk4SZUliznzromTHdEItw1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbLuCd/btsJhgka5s1/Rk4SZUliznzromTHdEItw1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbLuCd/btsJhgka5s1/Rk4SZUliznzromTHdEItw1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bbLuCd/btsJhgka5s1/Rk4SZUliznzromTHdEItw1/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;2940&quot; height=&quot;1912&quot; data-filename=&quot;Screen Recording 2024-08-27 at 11.14.12 AM.gif&quot; data-origin-width=&quot;2940&quot; data-origin-height=&quot;1912&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;PATCH&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1164&quot; data-origin-height=&quot;724&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgJUbk/btsJfbkK4Uq/8ooeKLPBEccNSeWKEGKAv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgJUbk/btsJfbkK4Uq/8ooeKLPBEccNSeWKEGKAv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgJUbk/btsJfbkK4Uq/8ooeKLPBEccNSeWKEGKAv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgJUbk%2FbtsJfbkK4Uq%2F8ooeKLPBEccNSeWKEGKAv0%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;1164&quot; height=&quot;724&quot; data-origin-width=&quot;1164&quot; data-origin-height=&quot;724&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screen Recording 2024-08-27 at 11.19.13 AM.gif&quot; data-origin-width=&quot;2940&quot; data-origin-height=&quot;1912&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eupN8z/btsJhCgdyf7/WxEK4wd9s0ofnsNWqTCsxk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eupN8z/btsJhCgdyf7/WxEK4wd9s0ofnsNWqTCsxk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eupN8z/btsJhCgdyf7/WxEK4wd9s0ofnsNWqTCsxk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/eupN8z/btsJhCgdyf7/WxEK4wd9s0ofnsNWqTCsxk/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;2940&quot; height=&quot;1912&quot; data-filename=&quot;Screen Recording 2024-08-27 at 11.19.13 AM.gif&quot; data-origin-width=&quot;2940&quot; data-origin-height=&quot;1912&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screen Recording 2024-08-27 at 11.22.23 AM.gif&quot; data-origin-width=&quot;2940&quot; data-origin-height=&quot;1912&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ciZ48s/btsJfdiBquE/bIwbOLgaQ1lrJw5FKwpKcK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ciZ48s/btsJfdiBquE/bIwbOLgaQ1lrJw5FKwpKcK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ciZ48s/btsJfdiBquE/bIwbOLgaQ1lrJw5FKwpKcK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/ciZ48s/btsJfdiBquE/bIwbOLgaQ1lrJw5FKwpKcK/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;2940&quot; height=&quot;1912&quot; data-filename=&quot;Screen Recording 2024-08-27 at 11.22.23 AM.gif&quot; data-origin-width=&quot;2940&quot; data-origin-height=&quot;1912&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;h3 data-ke-size=&quot;size23&quot;&gt;GET&lt;/h3&gt;
&lt;pre id=&quot;code_1724725510198&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 즉시 실행 함수
(async () =&amp;gt; {
  // 기본값 = GET
  const res = await fetch(&quot;http://localhost:1234/users&quot;, {
    method: &quot;GET&quot;,
  });
  const data = await res.json();
  console.log(data);
})();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pW5Y6/btsJgxf23IY/P7BTaMD8jyf6xtOEnqWVB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pW5Y6/btsJgxf23IY/P7BTaMD8jyf6xtOEnqWVB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pW5Y6/btsJgxf23IY/P7BTaMD8jyf6xtOEnqWVB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpW5Y6%2FbtsJgxf23IY%2FP7BTaMD8jyf6xtOEnqWVB1%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;844&quot; height=&quot;690&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;690&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;60세 이하만 가져오고 싶다면 ?&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;쿼리스트링 사용&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1250&quot; data-origin-height=&quot;616&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGPsKg/btsJgCarABC/ANFp7bur2AskKaHpfUF0KK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGPsKg/btsJgCarABC/ANFp7bur2AskKaHpfUF0KK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGPsKg/btsJgCarABC/ANFp7bur2AskKaHpfUF0KK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGPsKg%2FbtsJgCarABC%2FANFp7bur2AskKaHpfUF0KK%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;1250&quot; height=&quot;616&quot; data-origin-width=&quot;1250&quot; data-origin-height=&quot;616&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qh7GM/btsJgRLRjeE/UBy2gELOidJ6ti8m0t5muK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qh7GM/btsJgRLRjeE/UBy2gELOidJ6ti8m0t5muK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qh7GM/btsJgRLRjeE/UBy2gELOidJ6ti8m0t5muK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqh7GM%2FbtsJgRLRjeE%2FUBy2gELOidJ6ti8m0t5muK%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;844&quot; height=&quot;690&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;690&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;h4 data-ke-size=&quot;size20&quot;&gt;range&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2~3번째 데이터만 가지고 오고 싶으면 ?&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;쿼리스트링 사용, start/end&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1322&quot; data-origin-height=&quot;580&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BzWgn/btsJgegB81t/ISxNAvxOk1yjd4z3RXlab1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BzWgn/btsJgegB81t/ISxNAvxOk1yjd4z3RXlab1/img.png&quot; data-alt=&quot;zerobased numbering 사용 (slice method랑 같음)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BzWgn/btsJgegB81t/ISxNAvxOk1yjd4z3RXlab1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBzWgn%2FbtsJgegB81t%2FISxNAvxOk1yjd4z3RXlab1%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;1322&quot; height=&quot;580&quot; data-origin-width=&quot;1322&quot; data-origin-height=&quot;580&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;zerobased numbering 사용 (slice method랑 같음)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/61WSL/btsJgxAkT7i/QTPXbwTkqq1Bp10tQygjHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/61WSL/btsJgxAkT7i/QTPXbwTkqq1Bp10tQygjHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/61WSL/btsJgxAkT7i/QTPXbwTkqq1Bp10tQygjHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F61WSL%2FbtsJgxAkT7i%2FQTPXbwTkqq1Bp10tQygjHK%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;844&quot; height=&quot;690&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;690&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;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;쿼리스트링 사용, start/limit&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1352&quot; data-origin-height=&quot;580&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cROkRh/btsJfSkBayR/LWw5ThclHlVkZEUhS2s6R1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cROkRh/btsJfSkBayR/LWw5ThclHlVkZEUhS2s6R1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cROkRh/btsJfSkBayR/LWw5ThclHlVkZEUhS2s6R1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcROkRh%2FbtsJfSkBayR%2FLWw5ThclHlVkZEUhS2s6R1%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;1352&quot; height=&quot;580&quot; data-origin-width=&quot;1352&quot; data-origin-height=&quot;580&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2mWzI/btsJgDAieF4/Q7yIEOMbTJy3iVBflmrM4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2mWzI/btsJgDAieF4/Q7yIEOMbTJy3iVBflmrM4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2mWzI/btsJgDAieF4/Q7yIEOMbTJy3iVBflmrM4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2mWzI%2FbtsJgDAieF4%2FQ7yIEOMbTJy3iVBflmrM4K%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;844&quot; height=&quot;690&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;690&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;h4 data-ke-size=&quot;size20&quot;&gt;pagination&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1394&quot; data-origin-height=&quot;580&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/taSg0/btsJfQ76YGc/pDAVvgzH8TFWcL3po58Yj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/taSg0/btsJfQ76YGc/pDAVvgzH8TFWcL3po58Yj0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/taSg0/btsJfQ76YGc/pDAVvgzH8TFWcL3po58Yj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtaSg0%2FbtsJfQ76YGc%2FpDAVvgzH8TFWcL3po58Yj0%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;1394&quot; height=&quot;580&quot; data-origin-width=&quot;1394&quot; data-origin-height=&quot;580&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1724728788195&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;posts&quot;: [
    { &quot;id&quot;: &quot;a&quot;, &quot;title&quot;: &quot;A&quot; },
    { &quot;id&quot;: &quot;b&quot;, &quot;title&quot;: &quot;B&quot; },
    { &quot;id&quot;: &quot;c&quot;, &quot;title&quot;: &quot;C&quot; },
    { &quot;id&quot;: &quot;d&quot;, &quot;title&quot;: &quot;D&quot; },
    { &quot;id&quot;: &quot;e&quot;, &quot;title&quot;: &quot;E&quot; },
    { &quot;id&quot;: &quot;f&quot;, &quot;title&quot;: &quot;F&quot; },
    { &quot;id&quot;: &quot;g&quot;, &quot;title&quot;: &quot;G&quot; },
    { &quot;id&quot;: &quot;h&quot;, &quot;title&quot;: &quot;H&quot; },
    { &quot;id&quot;: &quot;i&quot;, &quot;title&quot;: &quot;I&quot; },
    { &quot;id&quot;: &quot;j&quot;, &quot;title&quot;: &quot;J&quot; },
    { &quot;id&quot;: &quot;k&quot;, &quot;title&quot;: &quot;K&quot; },
    { &quot;id&quot;: &quot;l&quot;, &quot;title&quot;: &quot;L&quot; },
    { &quot;id&quot;: &quot;m&quot;, &quot;title&quot;: &quot;M&quot; },
    { &quot;id&quot;: &quot;n&quot;, &quot;title&quot;: &quot;N&quot; },
    { &quot;id&quot;: &quot;o&quot;, &quot;title&quot;: &quot;O&quot; },
    { &quot;id&quot;: &quot;p&quot;, &quot;title&quot;: &quot;P&quot; },
    { &quot;id&quot;: &quot;q&quot;, &quot;title&quot;: &quot;Q&quot; },
    { &quot;id&quot;: &quot;r&quot;, &quot;title&quot;: &quot;R&quot; },
    { &quot;id&quot;: &quot;s&quot;, &quot;title&quot;: &quot;S&quot; },
    { &quot;id&quot;: &quot;t&quot;, &quot;title&quot;: &quot;T&quot; },
    { &quot;id&quot;: &quot;u&quot;, &quot;title&quot;: &quot;U&quot; },
    { &quot;id&quot;: &quot;v&quot;, &quot;title&quot;: &quot;V&quot; },
    { &quot;id&quot;: &quot;w&quot;, &quot;title&quot;: &quot;W&quot; },
    { &quot;id&quot;: &quot;x&quot;, &quot;title&quot;: &quot;X&quot; },
    { &quot;id&quot;: &quot;y&quot;, &quot;title&quot;: &quot;Y&quot; },
    { &quot;id&quot;: &quot;z&quot;, &quot;title&quot;: &quot;Z&quot; }
  ]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;1168&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Pfm3p/btsJhNoq4R6/hjkyE8REbTwfqR2jBZxkf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Pfm3p/btsJhNoq4R6/hjkyE8REbTwfqR2jBZxkf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Pfm3p/btsJhNoq4R6/hjkyE8REbTwfqR2jBZxkf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPfm3p%2FbtsJhNoq4R6%2FhjkyE8REbTwfqR2jBZxkf1%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;844&quot; height=&quot;1168&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;1168&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;h4 data-ke-size=&quot;size20&quot;&gt;sort&lt;/h4&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-origin-width=&quot;1236&quot; data-origin-height=&quot;580&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qVi6h/btsJfFFPSmM/ZpWKmkPtncueZWvnvIMw80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qVi6h/btsJfFFPSmM/ZpWKmkPtncueZWvnvIMw80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qVi6h/btsJfFFPSmM/ZpWKmkPtncueZWvnvIMw80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqVi6h%2FbtsJfFFPSmM%2FZpWKmkPtncueZWvnvIMw80%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;1236&quot; height=&quot;580&quot; data-origin-width=&quot;1236&quot; data-origin-height=&quot;580&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MqZnJ/btsJfDgZxtJ/xJ8arkTQbWBSAwBKkzVBbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MqZnJ/btsJfDgZxtJ/xJ8arkTQbWBSAwBKkzVBbk/img.png&quot; data-alt=&quot;나이가 어린 순서대로 정렬되어서 출력되는 모습&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MqZnJ/btsJfDgZxtJ/xJ8arkTQbWBSAwBKkzVBbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMqZnJ%2FbtsJfDgZxtJ%2FxJ8arkTQbWBSAwBKkzVBbk%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;844&quot; height=&quot;482&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;482&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;나이가 어린 순서대로 정렬되어서 출력되는 모습&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;DELETE&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screen Recording 2024-08-27 at 11.25.32 AM.gif&quot; data-origin-width=&quot;2940&quot; data-origin-height=&quot;1912&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/w4Nyc/btsJfEfHT5d/MjGcsyCcLUjaHjCDnQSHAk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/w4Nyc/btsJfEfHT5d/MjGcsyCcLUjaHjCDnQSHAk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/w4Nyc/btsJfEfHT5d/MjGcsyCcLUjaHjCDnQSHAk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/w4Nyc/btsJfEfHT5d/MjGcsyCcLUjaHjCDnQSHAk/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;2940&quot; height=&quot;1912&quot; data-filename=&quot;Screen Recording 2024-08-27 at 11.25.32 AM.gif&quot; data-origin-width=&quot;2940&quot; data-origin-height=&quot;1912&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;h4 data-ke-size=&quot;size20&quot;&gt;NoSQL&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-ke-style=&quot;style2&quot;&gt;데이터 베이스: {todos, users}&lt;/li&gt;
&lt;li data-ke-style=&quot;style2&quot;&gt;collection: todos, users 각각&lt;/li&gt;
&lt;li data-ke-style=&quot;style2&quot;&gt;document: {id, title, done}&lt;/li&gt;
&lt;li data-ke-style=&quot;style2&quot;&gt;field: todos안에 id, title, done 속성&lt;/li&gt;
&lt;li data-ke-style=&quot;style2&quot;&gt;todos의 스키마: id, title, done&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;652&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dS3F2S/btsJgAjn1tI/jNyMetCHuiBaA8t8NlD5M0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dS3F2S/btsJgAjn1tI/jNyMetCHuiBaA8t8NlD5M0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dS3F2S/btsJgAjn1tI/jNyMetCHuiBaA8t8NlD5M0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdS3F2S%2FbtsJgAjn1tI%2FjNyMetCHuiBaA8t8NlD5M0%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;698&quot; height=&quot;652&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;652&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;users의 스키마&lt;span style=&quot;color: #666666; text-align: left;&quot;&gt;(Schema)&lt;/span&gt; = id, name, age !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 배열은 users의 스키마에 맞지 않기 때문에 사용 불가 (NoSQL은 물리적으로는 넣을 수 있지만 넣으면 안됨 !)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 POST로 생성할 때 잘 생성해야 함 !&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;868&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/p37sK/btsJfR6Y8hH/MqY6AdxICk6rCrbYfKjTI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/p37sK/btsJfR6Y8hH/MqY6AdxICk6rCrbYfKjTI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/p37sK/btsJfR6Y8hH/MqY6AdxICk6rCrbYfKjTI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fp37sK%2FbtsJfR6Y8hH%2FMqY6AdxICk6rCrbYfKjTI1%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;572&quot; height=&quot;868&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;868&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;age속성 없는 것은 가능하지만 웬만하면 null로 넣어주기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;json에는 undefined랑 함수 못 씀 !&lt;/p&gt;
&lt;pre id=&quot;code_1724726363562&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;age&quot;: null

// null: 아무것도 아니야, 명시적
// undefined: 아무것도 아니야, 암시적(자동으로 들어가짐)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;868&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bggJDc/btsJg5DaKKm/ZOKBCP0YkeTTx4fE2Zt1gk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bggJDc/btsJg5DaKKm/ZOKBCP0YkeTTx4fE2Zt1gk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bggJDc/btsJg5DaKKm/ZOKBCP0YkeTTx4fE2Zt1gk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbggJDc%2FbtsJg5DaKKm%2FZOKBCP0YkeTTx4fE2Zt1gk%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;572&quot; height=&quot;868&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;868&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;HMR (Hot Module Replacement)&lt;/h3&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;h3 data-ke-size=&quot;size23&quot;&gt;JSON.stringify&lt;/h3&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-origin-width=&quot;844&quot; data-origin-height=&quot;690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhG2K2/btsJhM35TXC/Vm79ft7KJ5IECg5IgoLQt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhG2K2/btsJhM35TXC/Vm79ft7KJ5IECg5IgoLQt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhG2K2/btsJhM35TXC/Vm79ft7KJ5IECg5IgoLQt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhG2K2%2FbtsJhM35TXC%2FVm79ft7KJ5IECg5IgoLQt1%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;844&quot; height=&quot;690&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;690&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;h2 data-ke-size=&quot;size26&quot;&gt;zustand 적용&lt;/h2&gt;
&lt;pre id=&quot;code_1724803775796&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { create } from &quot;zustand&quot;;
import { combine } from &quot;zustand/middleware&quot;;

interface User {
  name: string;
  age: number;
  id: string;
}

export const useUsersStore = create(
  combine(
    {
      users: [],
    },
    (set) =&amp;gt; {
      return {
        fetchUsers: async () =&amp;gt; {
          const res = await fetch(&quot;http://localhost:1234/users&quot;);
          const users = await res.json();
          set({
            users, // users:users
          });
        },
        // Omit&amp;lt;User, 'id'&amp;gt;: User에서 id를 제외한 타입
        addUser: async (user: Omit&amp;lt;User, &quot;id&quot;&amp;gt;) =&amp;gt; {
          await fetch(&quot;http://localhost:1234/users&quot;, {
            method: &quot;POST&quot;,
            body: JSON.stringify(user),
          });
          fetchUsers();
        },
        updateUser: async (user: User) =&amp;gt; {
          await fetch(`http://localhost:1234/users/${user.id}`, {
            method: &quot;PUT&quot;,
            body: JSON.stringify(user),
          })
          // 목록 갱신
          1. fetchUsers();
          2. set(state =&amp;gt; ({
            users: state.users.map(u =&amp;gt; u.id === updatedUser.id ? updatedUser : u) // OK!
            // users: state.users.map(u =&amp;gt; u.id === user.id ? user : u) // OK!
          }))
        },
        deleteUser: async (user: User) =&amp;gt; {
          await fetch(`http://localhost:1234/users/${user.id}`, {
            method: &quot;DELETE&quot;,
            // 삭제하는거니까 body 필요 없음
          });
          set((state) =&amp;gt; ({
            users: state.users.filter(
              (userItem: User) =&amp;gt; userItem.id !== user.id
            ),
            // userItem = state.users 배열 내의 각 사용자 객체
            // userItem의 id가 삭제하려는 user의 id와 다른지를 확인
            // 다르면 남겨두고, 같으면 삭제됨
          }));
        },
      };
    }
  )
);
function fetchUsers() {
  throw new Error(&quot;Function not implemented.&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문자 데이터&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;&quot;&lt;/li&gt;
&lt;li&gt;''&lt;/li&gt;
&lt;li&gt;``&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;&quot;와 ''중 하나만 사용하기&lt;/p&gt;
&lt;pre id=&quot;code_1724730294245&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 데이터 보간
const fruit = '사과'
const paragraph = `나는 ${fruit}를 좋아해요`&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Tanstack Query&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;@tanstack/react-query&lt;/span&gt;는 &lt;b&gt;React Query&lt;/b&gt;의 최신 버전으로, &lt;b&gt;비동기 데이터 관리&lt;/b&gt;를 효율적으로 할 수 있게 도와주는 라이브러리입니다. React Query는 서버 상태를 관리하는 데 특화된 도구로, 특히 API 요청을 다루는 데 강력한 기능을 제공합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1724730429191&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i @tanstack/react-query&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;App.tsx&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1208&quot; data-origin-height=&quot;832&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyGWt7/btsJgDBlNLk/nLytq9TjhMrZwpTzSne7KK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyGWt7/btsJgDBlNLk/nLytq9TjhMrZwpTzSne7KK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyGWt7/btsJgDBlNLk/nLytq9TjhMrZwpTzSne7KK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcyGWt7%2FbtsJgDBlNLk%2FnLytq9TjhMrZwpTzSne7KK%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;1208&quot; height=&quot;832&quot; data-origin-width=&quot;1208&quot; data-origin-height=&quot;832&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;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;주요 부분 설명&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1. useQuery 훅:&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;useQuery는 @tanstack/react-query에서 제공하는 훅으로, 서버에서 데이터를 가져오고, 이를 상태로 관리하는 기능을 제공합니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;훅은 API 요청, 데이터 캐싱, 로딩 및 에러 상태 관리 등 복잡한 비동기 작업을 간편하게 처리할 수 있게 해줍니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2. queryKey:&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;queryKey: [&quot;users&quot;, &quot;get&quot;]는 이 쿼리를 고유하게 식별하는 키입니다. &lt;br /&gt;이 키를 통해 React Query는 이 쿼리를 캐싱하고, 상태를 관리하며, 필요시 데이터를 새로 가져옵니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;복합적인 배열 형태로 사용하여, 특정 리소스와 관련된 여러 쿼리를 명확하게 구분할 수 있습니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3. queryFn:&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;queryFn은 데이터를 가져오는 비동기 함수입니다. 이 함수는 실제로 서버에 요청을 보내고, 결과를 JSON 형태로 변환하여 반환합니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여기서는 fetch API를 사용해 GET 요청을 보내고, 사용자 데이터를 받아옵니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;4. staleTime:&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;staleTime: 1000 * 10은 데이터가 신선한 상태로 간주되는 시간을 정의합니다. 이 경우 10초(1000ms * 10) 동안은 데이터를 다시 가져오지 않고 캐시된 데이터를 사용합니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 시간 동안 동일한 쿼리가 다시 호출되면, 네트워크 요청 없이 캐시된 데이터를 바로 사용할 수 있습니다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;main.tsx&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1368&quot; data-origin-height=&quot;688&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4riIF/btsJiFKVgQP/pqnahBmOzMJnwv6JxHtkB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4riIF/btsJiFKVgQP/pqnahBmOzMJnwv6JxHtkB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4riIF/btsJiFKVgQP/pqnahBmOzMJnwv6JxHtkB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4riIF%2FbtsJiFKVgQP%2FpqnahBmOzMJnwv6JxHtkB0%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;1368&quot; height=&quot;688&quot; data-origin-width=&quot;1368&quot; data-origin-height=&quot;688&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;* 화상 회의 자주하는 게 좋음&lt;br /&gt;&lt;br /&gt;* 스크럼 회의&lt;br /&gt;목표 설정 --&amp;gt; 문서화 (기본적으로 지켜줘야 함, 일정 관리를 위해)&lt;br /&gt;&lt;br /&gt;* 프로젝트에서 zustand 사용법&lt;br /&gt;강의 3번째 시간에 설명해주시니 그거 보고 설정하기&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724724168238&quot; class=&quot;javascript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;code . -r
// Visual Studio Code를 현재 디렉토리에서 실행하는 명령어
code .
// 현재 경로 폴더를 새로운 vs 코드 창으로 열어주세요

mkdir vite-project2
// vite-project2라는 이름의 새 디렉토리를 만듭니다

cd vite-project2
//vite-project2 디렉토리로 이동합니다.

npm create vite@latest .
// 현재 디렉토리에 최신 버전의 Vite 프로젝트를 생성합니다.&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;a href=&quot;https://github.com/typicode/json-server&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/typicode/json-server&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724726796045&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 - typicode/json-server: Get a full fake REST API with zero coding in less than 30 seconds (seriously)&quot; data-og-description=&quot;Get a full fake REST API with zero coding in less than 30 seconds (seriously) - typicode/json-server&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/typicode/json-server&quot; data-og-url=&quot;https://github.com/typicode/json-server&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bLnhET/hyWVXLaTrn/HDk0HrYQfJSqVJa7evQw0k/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/typicode/json-server&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/typicode/json-server&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bLnhET/hyWVXLaTrn/HDk0HrYQfJSqVJa7evQw0k/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&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 - typicode/json-server: Get a full fake REST API with zero coding in less than 30 seconds (seriously)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Get a full fake REST API with zero coding in less than 30 seconds (seriously) - typicode/json-server&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Live Class/Beginner</category>
      <category>jsonserver</category>
      <author>dearsuhyun</author>
      <guid isPermaLink="true">https://diveintodevworld.tistory.com/77</guid>
      <comments>https://diveintodevworld.tistory.com/77#entry77comment</comments>
      <pubDate>Wed, 28 Aug 2024 10:03:45 +0900</pubDate>
    </item>
    <item>
      <title>Beginner 16회차 (8/26) | 개발 요구사항 정리, 렉시컬 스코프</title>
      <link>https://diveintodevworld.tistory.com/76</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;개발 요구사항 정리&lt;/h2&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;p data-ke-size=&quot;size16&quot;&gt;1. 프로젝트(서비스) 기획&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 할 일을 추가하는 기능&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;버튼을 클릭했을 때 추가되는 기능&lt;/li&gt;
&lt;li&gt;엔터키를 눌렀을 때 추가되는 기능&lt;/li&gt;
&lt;/ul&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;- 할 일 항목을 삭제하는 기능&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;2. 핵심 기술&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(main 기술, 모르면 프로젝트 투입이 불가능)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Next.js(SSR)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SPA(CSR)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- RESTful API&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Vite.js&lt;/p&gt;
&lt;pre id=&quot;code_1724639113319&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm create vite@latest

ESLint, Prettier 설정&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Typescript&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- React&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- vercel&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Vercel Serverless Functions&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Supabase(PostgreSQL)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SEO&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. 세부 기술&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(sub 기술, 몰라도 바로 배워서 프로젝트 투입 가능)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ESLint, Prettier&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- SCSS&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Tailwind CSS&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Axios&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- React Router&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Framer Motion&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- React Query&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Zustand&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Day.js&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Sortable.js&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;4. 개발 기간(마일스톤)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2024.09.01 - 2024.12.31&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;5. 와이어프레임&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;960&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWIGdC/btsJfO9gA7v/krirFIECsspeUDZdNs2KT1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWIGdC/btsJfO9gA7v/krirFIECsspeUDZdNs2KT1/img.webp&quot; data-alt=&quot;https://www.google.com/url?sa=i&amp;amp;amp;url=https%3A%2F%2Fmiro.com%2Fko%2Ftemplates%2Flow-fidelity-wireframes%2F&amp;amp;amp;psig=AOvVaw1flFzkVJ03O8-CysDtUlHb&amp;amp;amp;ust=1724726065720000&amp;amp;amp;source=images&amp;amp;amp;cd=vfe&amp;amp;amp;opi=89978449&amp;amp;amp;ved=0CBcQjhxqFwoTCOC1y73PkYgDFQAAAAAdAAAAABAg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWIGdC/btsJfO9gA7v/krirFIECsspeUDZdNs2KT1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWIGdC%2FbtsJfO9gA7v%2FkrirFIECsspeUDZdNs2KT1%2Fimg.webp&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;1440&quot; height=&quot;960&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.google.com/url?sa=i&amp;amp;url=https%3A%2F%2Fmiro.com%2Fko%2Ftemplates%2Flow-fidelity-wireframes%2F&amp;amp;psig=AOvVaw1flFzkVJ03O8-CysDtUlHb&amp;amp;ust=1724726065720000&amp;amp;source=images&amp;amp;cd=vfe&amp;amp;opi=89978449&amp;amp;ved=0CBcQjhxqFwoTCOC1y73PkYgDFQAAAAAdAAAAABAg&lt;/figcaption&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 요구사항 정의서 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 기능 개발&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) 테스트(단위, E2E, QA)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) 배포&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5) 리팩토링 (성능 최적화, 유지보수)&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;/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;h2 data-ke-size=&quot;size26&quot;&gt;렉시컬 스코프&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 스코프 = 범위, context&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;함수의 렉시컬 스코프(Lexical Scope)란, 정적 스코프(Static Scope)라고도 하며, 함수를 선언한 위치에서 유효하게 접근 가능한 범위(유효범위)를 말합니다.&lt;br /&gt;간단하게는 전역(Global)을 포함한 선언된 함수의 상위 함수 범위로 이해할 수 있습니다.&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;예제에서,&amp;nbsp;fnC&amp;nbsp;함수는&amp;nbsp;렉시컬&amp;nbsp;스코프의&amp;nbsp;window,&amp;nbsp;a,&amp;nbsp;b,&amp;nbsp;c&amp;nbsp;객체를&amp;nbsp;모두&amp;nbsp;참조할&amp;nbsp;수&amp;nbsp;있습니다.&lt;br /&gt;fnX&amp;nbsp;함수는&amp;nbsp;fnC&amp;nbsp;함수의&amp;nbsp;상위&amp;nbsp;함수가&amp;nbsp;아니므로,&amp;nbsp;접근&amp;nbsp;가능하지&amp;nbsp;않습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1724644566577&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const a = {
  name: 'A',
  fnA() {
    const b = {
      name: 'B',
      fnB() {
        const c = {
          name: 'C',
          fnC() {
            console.log(window) // window 객체
            console.log(a) // a 객체
            console.log(b) // b 객체
            console.log(c) // c 객체
            console.log(d) // Error: d is not defined
          }
        }
        return c
      }
    }
    return b
  },
  fnX() {
    const d = {
      name: 'D'
    }
  }
}
a.fnA().fnB().fnC()&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;* 쿼리(검색)&lt;br /&gt;프론트엔드 --&amp;gt; 네트워크 기준에서 데이터를 요청하는 것&lt;br /&gt;react qury: 요청과 응답, 네트워크 통신을 어떻게 다룰것인가 ? FE --&amp;gt; BE&lt;br /&gt;백엔드 --&amp;gt; 데이터베이스(DB)에서 검색하는 것(특정 항목)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; BE -----(query)-----&amp;gt; DB&lt;br /&gt;&lt;br /&gt;* 문서를 읽을 때 모르는 단어, 구절, 문장이 나오면 그것에 대해서 파고들어야 함&lt;br /&gt;ex) 조직 ? 완벽하게는 아니지만 적어도 조직이 무엇을 의미하는지는 알고 다음으로 넘어가야 함&lt;br /&gt;&lt;br /&gt;* SEO 적용 --&amp;gt; 검색하면 나올 페이지, 누구나 다 쓰는 페이지&lt;br /&gt;(&amp;lt;-&amp;gt; 보안이 필요한 페이지(ex. setting의 my page 등))&lt;/blockquote&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://www.heropy.dev/p/N6phSt&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.heropy.dev/p/N6phSt&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724644654225&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;JS 함수 핵심 패턴&quot; data-og-description=&quot;자바스크립트 함수에 대한 기본적인 사용 방법부터 관련 용어, 고급 기법 등의 관련된 다양한 함수 패턴과 여러 개념을 살펴봅니다.&quot; data-og-host=&quot;www.heropy.dev&quot; data-og-source-url=&quot;https://www.heropy.dev/p/N6phSt&quot; data-og-url=&quot;https://www.heropy.dev/p/N6phSt&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Ylgkq/hyWVUgrrHd/iysKKjJY8hyG0DKe2bLqH1/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571,https://scrap.kakaocdn.net/dn/bXIbpv/hyWVRRzupl/dG0GjkQPYjOtNS04dz1skk/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571,https://scrap.kakaocdn.net/dn/mYCqm/hyWScwi0V0/GNAvKcdPhhiCYZQW2VmT50/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571&quot;&gt;&lt;a href=&quot;https://www.heropy.dev/p/N6phSt&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.heropy.dev/p/N6phSt&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Ylgkq/hyWVUgrrHd/iysKKjJY8hyG0DKe2bLqH1/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571,https://scrap.kakaocdn.net/dn/bXIbpv/hyWVRRzupl/dG0GjkQPYjOtNS04dz1skk/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571,https://scrap.kakaocdn.net/dn/mYCqm/hyWScwi0V0/GNAvKcdPhhiCYZQW2VmT50/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571');&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;JS 함수 핵심 패턴&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트 함수에 대한 기본적인 사용 방법부터 관련 용어, 고급 기법 등의 관련된 다양한 함수 패턴과 여러 개념을 살펴봅니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.heropy.dev&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;</description>
      <category>Live Class/Beginner</category>
      <author>dearsuhyun</author>
      <guid isPermaLink="true">https://diveintodevworld.tistory.com/76</guid>
      <comments>https://diveintodevworld.tistory.com/76#entry76comment</comments>
      <pubDate>Tue, 27 Aug 2024 23:39:17 +0900</pubDate>
    </item>
    <item>
      <title>Beginner 15회차 (8/21) | todo 리스트에 필터 기능 추가 실습, clsx 라이브러리로 버튼에 여러 스타일을 동시에 적용해보기, subscribeWithSelector 미들웨어 사용, if와 switch 조건문, 불변성과 가변성, React-Query 소개</title>
      <link>https://diveintodevworld.tistory.com/75</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;todo&amp;nbsp;리스트에&amp;nbsp;필터&amp;nbsp;기능&amp;nbsp;추가&amp;nbsp;실습&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 원본 todo 리스트는 가지고 있고, 필터링을 할 때 완료 전/완료 후 배열을 다시 만들어서 띄워줘야 됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;store&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1150&quot; data-origin-height=&quot;796&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwjxDK/btsJcUu4lqi/lau90EUykwuikpC3RtBEkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwjxDK/btsJcUu4lqi/lau90EUykwuikpC3RtBEkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwjxDK/btsJcUu4lqi/lau90EUykwuikpC3RtBEkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwjxDK%2FbtsJcUu4lqi%2Flau90EUykwuikpC3RtBEkK%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;1150&quot; height=&quot;796&quot; data-origin-width=&quot;1150&quot; data-origin-height=&quot;796&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;버튼을 누르면 value 바뀌도록 액션 설정&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1334&quot; data-origin-height=&quot;688&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqw0db/btsJdxMPMk5/KJBgppQA4Xc63kIj0qksP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqw0db/btsJdxMPMk5/KJBgppQA4Xc63kIj0qksP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqw0db/btsJdxMPMk5/KJBgppQA4Xc63kIj0qksP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcqw0db%2FbtsJdxMPMk5%2FKJBgppQA4Xc63kIj0qksP1%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;1334&quot; height=&quot;688&quot; data-origin-width=&quot;1334&quot; data-origin-height=&quot;688&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;lt;TodoFilters 컴포넌트&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1338&quot; data-origin-height=&quot;1156&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FNM5o/btsJbMETSAO/3wK5BcuEGht5McI7XptvXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FNM5o/btsJbMETSAO/3wK5BcuEGht5McI7XptvXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FNM5o/btsJbMETSAO/3wK5BcuEGht5McI7XptvXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFNM5o%2FbtsJbMETSAO%2F3wK5BcuEGht5McI7XptvXk%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;1338&quot; height=&quot;1156&quot; data-origin-width=&quot;1338&quot; data-origin-height=&quot;1156&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;버튼을 누르면 각 버튼에 따라 active가 붙는 화면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screen Recording 2024-08-22 at 11.37.18 PM.gif&quot; data-origin-width=&quot;1420&quot; data-origin-height=&quot;764&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJDrmg/btsJc3Fr1yE/9fOnNimK0xXKK3a9NOR4Zk/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJDrmg/btsJc3Fr1yE/9fOnNimK0xXKK3a9NOR4Zk/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJDrmg/btsJc3Fr1yE/9fOnNimK0xXKK3a9NOR4Zk/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bJDrmg/btsJc3Fr1yE/9fOnNimK0xXKK3a9NOR4Zk/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;1420&quot; height=&quot;764&quot; data-filename=&quot;Screen Recording 2024-08-22 at 11.37.18 PM.gif&quot; data-origin-width=&quot;1420&quot; data-origin-height=&quot;764&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;h3 data-ke-size=&quot;size23&quot;&gt;clsx 라이브러리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스를 여러 개 적용하고 싶을 때 !&lt;/p&gt;
&lt;pre id=&quot;code_1724204429547&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm i clsx&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;/p&gt;
&lt;pre id=&quot;code_1724337870917&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;button
  className={filterStatus === filter.value ? styles.active : ''}
  key={filter.value}
  onClick={() =&amp;gt; setFilterStatus(filter.value)}&amp;gt;
  {filter.text}
&amp;lt;/button&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;clsx 적용 코드&lt;/p&gt;
&lt;pre id=&quot;code_1724337803518&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;button
  className={clsx(
    styles.btn,
    filterStatus === filter.value &amp;amp;&amp;amp; styles.active
  )}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1724338065007&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.btn {
  border: none;
  padding: 10px;
}
.active {
  background-color: royalblue;
  color: white;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;subscribeWithSelector&amp;nbsp;미들웨어&amp;nbsp;사용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;subscribeWithSelector&lt;/span&gt;는 &lt;span&gt;zustand&lt;/span&gt;에서 상태의 특정 부분에 대해서만 구독(subscribe)할 수 있게 해주는 미들웨어입니다.&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_1724338365222&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { combine, subscribeWithSelector } from 'zustand/middleware'&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1296&quot; data-origin-height=&quot;1084&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boTZOp/btsJdw1tt5L/mSb7DSJvBbLJ7EXkFZafFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boTZOp/btsJdw1tt5L/mSb7DSJvBbLJ7EXkFZafFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boTZOp/btsJdw1tt5L/mSb7DSJvBbLJ7EXkFZafFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboTZOp%2FbtsJdw1tt5L%2FmSb7DSJvBbLJ7EXkFZafFk%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;1296&quot; height=&quot;1084&quot; data-origin-width=&quot;1296&quot; data-origin-height=&quot;1084&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;count가 늘어나면 double도 늘어나도록 만들기 위해서&lt;br /&gt;밑의 예제처럼 직접 지정하는 것이 아니라 subscribeWithSelector 이용 !&lt;br /&gt;특정한&amp;nbsp;상태를&amp;nbsp;구독해서&amp;nbsp;count가&amp;nbsp;늘어나면&amp;nbsp;double도&amp;nbsp;늘어나도록&amp;nbsp;만들기&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1348&quot; data-origin-height=&quot;1192&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dUuaDG/btsJcAcLz6p/1eLLMxPcxlRzytmKKzKAm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dUuaDG/btsJcAcLz6p/1eLLMxPcxlRzytmKKzKAm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dUuaDG/btsJcAcLz6p/1eLLMxPcxlRzytmKKzKAm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdUuaDG%2FbtsJcAcLz6p%2F1eLLMxPcxlRzytmKKzKAm1%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;1348&quot; height=&quot;1192&quot; data-origin-width=&quot;1348&quot; data-origin-height=&quot;1192&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;useABCStore.subscribe&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;count 바뀌면 double 처리 됨 !&lt;/p&gt;
&lt;pre id=&quot;code_1724339401469&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// useABCStore.subscribe(선택자, 콜백)
useABCStore.subscribe(
  (state) =&amp;gt; state.count, // 선택자
  (count) =&amp;gt; useABCStore.setState(() =&amp;gt; ({ double: count * 2 }))
);&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;zustand 이해&lt;/b&gt;&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-origin-width=&quot;790&quot; data-origin-height=&quot;760&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/x8vDy/btsJbq9P9CQ/jeTI96uXb1AYdYFskND1OK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/x8vDy/btsJbq9P9CQ/jeTI96uXb1AYdYFskND1OK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/x8vDy/btsJbq9P9CQ/jeTI96uXb1AYdYFskND1OK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fx8vDy%2FbtsJbq9P9CQ%2FjeTI96uXb1AYdYFskND1OK%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;790&quot; height=&quot;760&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;760&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;combine 사용&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;1012&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DHS4R/btsJcmlsNfL/atyhVMNIVGMtj21hw9apFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DHS4R/btsJcmlsNfL/atyhVMNIVGMtj21hw9apFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DHS4R/btsJcmlsNfL/atyhVMNIVGMtj21hw9apFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDHS4R%2FbtsJcmlsNfL%2FatyhVMNIVGMtj21hw9apFk%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;1060&quot; height=&quot;1012&quot; data-origin-width=&quot;1060&quot; data-origin-height=&quot;1012&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;프로젝트에 적용하기&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1020&quot; data-origin-height=&quot;504&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdlpY9/btsJdovG7v8/zuhbUVC3eOZkKIGEdOu6q1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdlpY9/btsJdovG7v8/zuhbUVC3eOZkKIGEdOu6q1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdlpY9/btsJdovG7v8/zuhbUVC3eOZkKIGEdOu6q1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdlpY9%2FbtsJdovG7v8%2FzuhbUVC3eOZkKIGEdOu6q1%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;1020&quot; height=&quot;504&quot; data-origin-width=&quot;1020&quot; data-origin-height=&quot;504&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;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;if와 switch 조건문&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;if 조건문 &amp;gt;= switch 조건문&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;switch -&amp;gt; if 무조건 가능 but if -&amp;gt; switch에는 불가능한 경우가 있음&lt;/span&gt; &lt;br /&gt;
&lt;pre id=&quot;code_1724339932406&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// if문
if (filterStatus === 'all') return true // 필터링 안함
if (filterStatus === 'todo') return !todo.done
if (filterStatus === 'done') return todo.done

// switch문
switch (filterStatus) {
   case 'todo':
     return !todo.done
   case 'done':
     return todo.done
   default:
    return true
}​&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;목록 가지고 올 때 원본 todos 대신 filteredTodos 사용 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;Main&amp;gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724340381727&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const todos = useTodosStore(state =&amp;gt; state.filteredTodos)&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;lt;store&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1378&quot; data-origin-height=&quot;1480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQ9Ga0/btsJbNRoTXc/e9LuON4hE7L010eC9v5nuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQ9Ga0/btsJbNRoTXc/e9LuON4hE7L010eC9v5nuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQ9Ga0/btsJbNRoTXc/e9LuON4hE7L010eC9v5nuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQ9Ga0%2FbtsJbNRoTXc%2Fe9LuON4hE7L010eC9v5nuk%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;1378&quot; height=&quot;1480&quot; data-origin-width=&quot;1378&quot; data-origin-height=&quot;1480&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;h2 data-ke-size=&quot;size26&quot;&gt;불변성과 가변성&lt;/h2&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;생긴게 같으면 같은 데이터 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'===' 일치연산자는 양 옆 피연산자의 메모리 주소를 비교하는 것 !&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;a ---&amp;gt; M1&lt;br /&gt;b ---&amp;gt; M1&lt;br /&gt;==&amp;gt; 서로 같은 메모리 주소를 바라보고 있으므로 true !&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;436&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nNlhs/btsI9ZcxQec/5DNnlZ6VE3qeccGJNeyZKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nNlhs/btsI9ZcxQec/5DNnlZ6VE3qeccGJNeyZKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nNlhs/btsI9ZcxQec/5DNnlZ6VE3qeccGJNeyZKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnNlhs%2FbtsI9ZcxQec%2F5DNnlZ6VE3qeccGJNeyZKK%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;702&quot; height=&quot;436&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;436&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;참조형 데이터: 객체, 배열, 함수&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생긴게 같아도 다른 데이터일 수 있음 !&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;생성할 때 마다 새로운 메모리에 할당&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;a ---&amp;gt; M1&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;B ---&amp;gt; M2&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;==&amp;gt; 서로 다른 메모리를 바라보고 있으므로 false !&lt;/span&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;716&quot; data-origin-height=&quot;436&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AjGau/btsJa20n4u4/lbj1Rsm5uMt5VrLw0tqk1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AjGau/btsJa20n4u4/lbj1Rsm5uMt5VrLw0tqk1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AjGau/btsJa20n4u4/lbj1Rsm5uMt5VrLw0tqk1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAjGau%2FbtsJa20n4u4%2Flbj1Rsm5uMt5VrLw0tqk1k%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;716&quot; height=&quot;436&quot; data-origin-width=&quot;716&quot; data-origin-height=&quot;436&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;데이터를 만드는 방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 생성자 함수(Constructor) 방식&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;888&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A5xLu/btsI84lypuC/9auZko25Rr4KQcpkpBWoG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A5xLu/btsI84lypuC/9auZko25Rr4KQcpkpBWoG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A5xLu/btsI84lypuC/9auZko25Rr4KQcpkpBWoG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA5xLu%2FbtsI84lypuC%2F9auZko25Rr4KQcpkpBWoG1%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;888&quot; height=&quot;508&quot; data-origin-width=&quot;888&quot; data-origin-height=&quot;508&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;2. 리터럴(Literal) 방식&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;646&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cn7UqW/btsJaqtUuq4/qH3ejZqqaHdtRBx52xk4e1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cn7UqW/btsJaqtUuq4/qH3ejZqqaHdtRBx52xk4e1/img.png&quot; data-alt=&quot;{} [] '' --&amp;amp;gt; 기호를 ~~ 리터럴이라고 부름&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cn7UqW/btsJaqtUuq4/qH3ejZqqaHdtRBx52xk4e1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcn7UqW%2FbtsJaqtUuq4%2FqH3ejZqqaHdtRBx52xk4e1%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;646&quot; height=&quot;472&quot; data-origin-width=&quot;646&quot; data-origin-height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;{} [] '' --&amp;gt; 기호를 ~~ 리터럴이라고 부름&lt;/figcaption&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;&lt;b&gt;프로젝트 예제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;todos에 todos를 그대로 넣으면 바라보는 메모리 주소가 같아서 todos가 변경되었다고 인식하지 않음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;...todos를&amp;nbsp;쓰면&amp;nbsp;todos가&amp;nbsp;바라보는&amp;nbsp;배열(m1)과&amp;nbsp;[...todos]가&amp;nbsp;바라보는&amp;nbsp;배열(m9)이&amp;nbsp;다르기&amp;nbsp;때문에&amp;nbsp;todos가&amp;nbsp;변경되었다고&amp;nbsp;인식한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열 리터럴 방식을 사용해서 [...todos]를 쓰면 ! 메모리 주소 달라짐&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;--&amp;gt; 안 쪽의 아이템의 메모리 주소는 같지만 겉 껍데기 메모리 주소만 다르게 할당해줌으로써 바뀌었다고 인식시켜주는 것 !&lt;/p&gt;
&lt;pre id=&quot;code_1724340788182&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;useTodosStore.subscribe(
  state =&amp;gt; state.filterStatus,
  () =&amp;gt; {
    const todos = useTodosStore.getState().todos
    useTodosStore.setState(() =&amp;gt; ({ todos: [...todos] }))
  }
)

// [...todos]라는 배열 데이터가 새로 만들어지는 것임
// ...todos를 쓰면 todos가 바라보는 배열(m1)과 [...todos]가 바라보는 배열(m9)이 다르기 때문에 todos가 변경되었다고 인식한다.
// 얕은 복사&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;React-Query (--&amp;gt; TanStack Query)&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;기능&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 캐싱(caching) - 데이터 저장&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 낙관적 업데이트&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;4. 패칭(fetching)&lt;/p&gt;
&lt;pre id=&quot;code_1724376875221&quot; class=&quot;typescript&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;npm i @tanstack/react-query&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트 이외의 라이브러리(Vue, Svelte 등)도 지원하겠다 ! (React-Query --&amp;gt; Tanstack Query 이름 변경)&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;Tanstack Query를 사용해서 데이터를 가져올 때는 항상 쿼리 키(Query Key)를 지정한다&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-origin-width=&quot;1482&quot; data-origin-height=&quot;616&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkohw9/btsJbHKpiP3/YesNI0Xr1cuMvVgPAY0JwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkohw9/btsJbHKpiP3/YesNI0Xr1cuMvVgPAY0JwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkohw9/btsJbHKpiP3/YesNI0Xr1cuMvVgPAY0JwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbkohw9%2FbtsJbHKpiP3%2FYesNI0Xr1cuMvVgPAY0JwK%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;1482&quot; height=&quot;616&quot; data-origin-width=&quot;1482&quot; data-origin-height=&quot;616&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- miss: 캐시된 데이터가 없다는 의미&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- cached: 캐시에 저장하는 행위&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;619&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsuX4O/btsJciDnyri/qDMHXz5VIn9LadyV7QYav0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsuX4O/btsJciDnyri/qDMHXz5VIn9LadyV7QYav0/img.jpg&quot; data-alt=&quot;출처: 박영웅 강사님 블로그 https://www.heropy.dev/p/HZaKIE&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsuX4O/btsJciDnyri/qDMHXz5VIn9LadyV7QYav0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsuX4O%2FbtsJciDnyri%2FqDMHXz5VIn9LadyV7QYav0%2Fimg.jpg&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;1280&quot; height=&quot;619&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;619&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: 박영웅 강사님 블로그 https://www.heropy.dev/p/HZaKIE&lt;/figcaption&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- hit: 캐시 데이터가 있을 때&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;619&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FRoC5/btsJbLsvJsB/u6fSLyNSPNFPXIxf44KCEK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FRoC5/btsJbLsvJsB/u6fSLyNSPNFPXIxf44KCEK/img.jpg&quot; data-alt=&quot;출처: 박영웅 강사님 블로그 https://www.heropy.dev/p/HZaKIE&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FRoC5/btsJbLsvJsB/u6fSLyNSPNFPXIxf44KCEK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFRoC5%2FbtsJbLsvJsB%2Fu6fSLyNSPNFPXIxf44KCEK%2Fimg.jpg&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;1280&quot; height=&quot;619&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;619&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: 박영웅 강사님 블로그 https://www.heropy.dev/p/HZaKIE&lt;/figcaption&gt;
&lt;/figure&gt;
&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;데이터의 신선도(유통기한)&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;TanStack Query는 캐시한 데이터를 신선(Fresh)하거나 상한(Stale) 상태로 구분해 관리함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;캐시된 데이터가 신선하다면 캐시된 데이터를 사용하고, 만약 데이터가 상했다면 서버에 다시 요청해 신선한(새로운) 데이터를 가져온다 !&lt;/span&gt;&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;832&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nFYui/btsJcIPlhqU/0C7mQkhDEWYPi66PujXn1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nFYui/btsJcIPlhqU/0C7mQkhDEWYPi66PujXn1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nFYui/btsJcIPlhqU/0C7mQkhDEWYPi66PujXn1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnFYui%2FbtsJcIPlhqU%2F0C7mQkhDEWYPi66PujXn1k%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;1512&quot; height=&quot;832&quot; data-origin-width=&quot;1512&quot; data-origin-height=&quot;832&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1524&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QhVcC/btsJcTQE61G/NDUoxUJDP0vmabHnv68qr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QhVcC/btsJcTQE61G/NDUoxUJDP0vmabHnv68qr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QhVcC/btsJcTQE61G/NDUoxUJDP0vmabHnv68qr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQhVcC%2FbtsJcTQE61G%2FNDUoxUJDP0vmabHnv68qr1%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;1524&quot; height=&quot;508&quot; data-origin-width=&quot;1524&quot; data-origin-height=&quot;508&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;&lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;시간 표기법&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;1s = 1000&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;10s = 1000 * 10&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;24h = 1000 * 60 * 60 * 24&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;30d = 1000 * 60 * 60 * 24 * 30&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;* 데이터를 기준으로 사고해야 함 (화면의 UI를 데이터로 구현하기)&lt;br /&gt;&lt;br /&gt;* 기술을 배우기 전에 공식문서를 먼저 훑어보고 !! (예습 개념) 그 다음 강의, 블로그 보기&lt;br /&gt;강의부터 보면 이해도가 떨어질 수 밖에 없음&lt;br /&gt;&lt;br /&gt;*&amp;nbsp; 프로젝트를 복습하는 방법 = 프로젝트 처음부터 다시 만들어보는 것 (복습 개념)&lt;br /&gt;&lt;br /&gt;* 코드를 작성할 때는 누군가가 읽었을 때 문제가 없도록 ! 독자를 고려하기 (hack 사용 금지 ,,)&lt;/blockquote&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://tanstack.com/query/latest&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://tanstack.com/query/latest&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724211514135&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;TanStack Query&quot; data-og-description=&quot;Instead of writing reducers, caching logic, timers, retry logic, complex async/await scripting (I could keep going...), you literally write a tiny fraction of the code you normally would. You will be surprised at how little code you're writing or how much &quot; data-og-host=&quot;tanstack.com&quot; data-og-source-url=&quot;https://tanstack.com/query/latest&quot; data-og-url=&quot;https://tanstack.com/query/latest&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://tanstack.com/query/latest&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://tanstack.com/query/latest&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;TanStack Query&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Instead of writing reducers, caching logic, timers, retry logic, complex async/await scripting (I could keep going...), you literally write a tiny fraction of the code you normally would. You will be surprised at how little code you're writing or how much&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;tanstack.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;a href=&quot;https://www.heropy.dev/p/HZaKIE&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.heropy.dev/p/HZaKIE&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724211611388&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;TanStack Query(React Query) 핵심 정리&quot; data-og-description=&quot;TanStack Query는 서버로부터 데이터 가져오기, 데이터 캐싱, 캐시 제어 등 데이터를 쉽고 효율적으로 관리할 수 있는 라이브러리로, React Query라는 이름으로 시작했지만, v4부터 Vue나 Svelte 등의 다른 &quot; data-og-host=&quot;www.heropy.dev&quot; data-og-source-url=&quot;https://www.heropy.dev/p/HZaKIE&quot; data-og-url=&quot;https://www.heropy.dev/p/HZaKIE&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b5t1C9/hyWSfMeFNg/IH1nWnJrDcza4uWs33ica1/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571,https://scrap.kakaocdn.net/dn/iHRJP/hyWSd1X1b8/pymC6iUBELkpdlrOu13Hr1/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571,https://scrap.kakaocdn.net/dn/HtZZD/hyWSj2bM16/6ljFp4IPjpatd0HKg3rYTk/img.jpg?width=2100&amp;amp;height=1016&amp;amp;face=0_0_2100_1016&quot;&gt;&lt;a href=&quot;https://www.heropy.dev/p/HZaKIE&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.heropy.dev/p/HZaKIE&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b5t1C9/hyWSfMeFNg/IH1nWnJrDcza4uWs33ica1/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571,https://scrap.kakaocdn.net/dn/iHRJP/hyWSd1X1b8/pymC6iUBELkpdlrOu13Hr1/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571,https://scrap.kakaocdn.net/dn/HtZZD/hyWSj2bM16/6ljFp4IPjpatd0HKg3rYTk/img.jpg?width=2100&amp;amp;height=1016&amp;amp;face=0_0_2100_1016');&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;TanStack Query(React Query) 핵심 정리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;TanStack Query는 서버로부터 데이터 가져오기, 데이터 캐싱, 캐시 제어 등 데이터를 쉽고 효율적으로 관리할 수 있는 라이브러리로, React Query라는 이름으로 시작했지만, v4부터 Vue나 Svelte 등의 다른&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.heropy.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.heropy.dev/p/n74Tgc&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.heropy.dev/p/n74Tgc&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724338478052&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Zustand 핵심 정리&quot; data-og-description=&quot;Zustand(주스탠드)는 작고 빠르며 확장 가능한 React 프로젝트에서 사용하는 상태 관리(Store) 라이브러리입니다.&quot; data-og-host=&quot;www.heropy.dev&quot; data-og-source-url=&quot;https://www.heropy.dev/p/n74Tgc&quot; data-og-url=&quot;https://www.heropy.dev/p/n74Tgc&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b4CF1R/hyWScCtApo/3LzH0xIlehVEe9q5mFDgbK/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571,https://scrap.kakaocdn.net/dn/0YGfr/hyWSnRvjyL/1ImA7O2LuEL3QnZDQP0eTK/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571,https://scrap.kakaocdn.net/dn/s2Owb/hyWSmkKx5t/jyzprKrk3oRlTeKKZAIVz1/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571&quot;&gt;&lt;a href=&quot;https://www.heropy.dev/p/n74Tgc&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.heropy.dev/p/n74Tgc&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b4CF1R/hyWScCtApo/3LzH0xIlehVEe9q5mFDgbK/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571,https://scrap.kakaocdn.net/dn/0YGfr/hyWSnRvjyL/1ImA7O2LuEL3QnZDQP0eTK/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571,https://scrap.kakaocdn.net/dn/s2Owb/hyWSmkKx5t/jyzprKrk3oRlTeKKZAIVz1/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571');&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;Zustand 핵심 정리&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Zustand(주스탠드)는 작고 빠르며 확장 가능한 React 프로젝트에서 사용하는 상태 관리(Store) 라이브러리입니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.heropy.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://reactrouter.com/en/main&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://reactrouter.com/en/main&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724341567737&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;Home v6.26.1 | React Router&quot; data-og-description=&quot;&quot; data-og-host=&quot;reactrouter.com&quot; data-og-source-url=&quot;https://reactrouter.com/en/main&quot; data-og-url=&quot;https://reactrouter.com/en/main&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/k5hPX/hyWSe1mdC5/p2qwtvz5dKkEBls6JiJQh0/img.jpg?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://reactrouter.com/en/main&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://reactrouter.com/en/main&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/k5hPX/hyWSe1mdC5/p2qwtvz5dKkEBls6JiJQh0/img.jpg?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&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;Home v6.26.1 | React Router&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;reactrouter.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;&amp;nbsp;&lt;/p&gt;</description>
      <category>Live Class/Beginner</category>
      <category>CLSX</category>
      <category>react-query</category>
      <category>subscribewithselector</category>
      <category>Zustand</category>
      <author>dearsuhyun</author>
      <guid isPermaLink="true">https://diveintodevworld.tistory.com/75</guid>
      <comments>https://diveintodevworld.tistory.com/75#entry75comment</comments>
      <pubDate>Fri, 23 Aug 2024 10:59:34 +0900</pubDate>
    </item>
    <item>
      <title>Recap | Beginner Live Class Recap 4회차</title>
      <link>https://diveintodevworld.tistory.com/74</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;4-1. async와 await&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;callback hell &amp;amp; Promise hell을 개선하기 위해 사용&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724305815803&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* Callback Hell */
getData (function (x) {
  getMoreData (x, function (y) {
    getMoreData (y, function (z) {
      ...
    });
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1724305824799&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* Promise Hell */
fetch('https://example.com/api')
  .then(response =&amp;gt; response.json())
  .then(data =&amp;gt; fetch(`https://example.com/api/${data.id}`))
  .then(response =&amp;gt; response.json())
  .then(data =&amp;gt; fetch(`https://example.com/api/${data.id}/details`))
  .then(response =&amp;gt; response.json())
  .then(data =&amp;gt; console.log(data))
  .catch(error =&amp;gt; console.error(error));&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;async&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;function 앞에 async를 붙이면 해당 함수는 항상 promise를 반환한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;함수를 정의할 때&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;async&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;를 함수 앞에 붙이면,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&amp;ldquo;이 함수는 비동기적인 함수이고 Promise를 반환한다&amp;rdquo;라고 선언하는 것 !&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;반환 값이 Promise 생성 함수가 아니어도 반환되는 값을 Promise 객체에 넣어주는 것이다.&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;await란 ?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;--&amp;gt; promise가 처리될 때 까지 함수 실행을 기다린다(promise가 처리되면 그 결과와 함께 실행이 재개됨)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #313130; text-align: start;&quot;&gt;프라미스가 처리되길 기다리는 동안엔 엔진이 다른 일(다른 스크립트를 실행, 이벤트 처리 등)을 할 수 있기 때문에, CPU 리소스가 낭비되지 않는다 !&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;gt; await는 async 함수 안에서만 동작한다 (일반 함수에는 사용 불가)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;Promise를 반환하는 함수 앞에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;await&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;를 붙이면, 해당 Promise의 상태가 바뀔 때까지 코드가 기다린다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;즉 Promise가 성공 상태 또는 실패 상태로 바뀌기 전까지는 다음 연산을 시작하지 않는 것이다.&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #313130; text-align: start;&quot;&gt;함수를 호출하고, 함수 본문이 실행되는 도중에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;(*)&lt;span style=&quot;background-color: #ffffff; color: #313130; text-align: start;&quot;&gt;로 표시한 줄에서 실행이 잠시 '중단&amp;rsquo;되었다가 프라미스가 처리되면 실행이 재개된다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #313130; text-align: start;&quot;&gt;이때 프라미스 객체의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;result&lt;span style=&quot;background-color: #ffffff; color: #313130; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;값이 변수 result에 할당됩니다. 따라서 위 예시를 실행하면 1초 뒤에 '완료!'가 출력된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724303824005&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async function f() {

  let promise = new Promise((resolve, reject) =&amp;gt; {
    setTimeout(() =&amp;gt; resolve(&quot;완료!&quot;), 1000)
  });

  let result = await promise; // 프라미스가 이행될 때까지 기다림 (*)

  alert(result); // &quot;완료!&quot;
}

f()&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;await는 최상위 레벨 코드에서 작동하지 않는다&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;/p&gt;
&lt;pre id=&quot;code_1724306004943&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 최상위 레벨 코드에선 문법 에러가 발생함
let response = await fetch('/article/promise-chaining/user.json');
let user = await response.json();&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;하지만 async 함수로 코드를 감싸면 최상위 레벨 코드에도 await를 사용할 수 있다&lt;/p&gt;
&lt;pre id=&quot;code_1724306035834&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(async function func1() {
    const res = await fetch(url); // 요청을 기다림
    const data = await res.json(); // 응답을 JSON으로 파싱
    console.log(data);
})();&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;기본적으로 await는 async 함수 내에서 작동하지만,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1d1c1d; text-align: left;&quot;&gt;자바스크립트의 ES2022(ECMAScript 2022) 버전부터는&amp;nbsp;&lt;/span&gt;&lt;b data-stringify-type=&quot;bold&quot;&gt;모듈&lt;/b&gt;&lt;span style=&quot;color: #1d1c1d; text-align: left;&quot;&gt;에서 최상위&amp;nbsp;&lt;/span&gt;await&lt;span style=&quot;color: #1d1c1d; text-align: left;&quot;&gt;를 사용할 수 있다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #1d1c1d; text-align: left;&quot;&gt;즉,&amp;nbsp;&lt;/span&gt;&lt;b data-stringify-type=&quot;bold&quot;&gt;import 또는 export 키워드를 사용하여 정의된 모듈 파일에서는&amp;nbsp;&lt;/b&gt;&lt;b data-stringify-type=&quot;bold&quot;&gt;async&lt;/b&gt;&lt;b data-stringify-type=&quot;bold&quot;&gt;&amp;nbsp;함수 없이도 최상위에서&amp;nbsp;&lt;/b&gt;&lt;b data-stringify-type=&quot;bold&quot;&gt;await&lt;/b&gt;&lt;b data-stringify-type=&quot;bold&quot;&gt;를 사용할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724306420821&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Top Level에선 async funciton 정의없이 곧바로 await 키워드 사용이 가능하다
const res = await fetch(url); // 요청을 기다림
const data = await res.json(); // 응답을 JSON으로 파싱
console.log(data);
출처: https://inpa.tistory.com/entry/JS- -비동기처리-async-await [Inpa Dev  &amp;zwj; :티스토리]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;주의 !&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;거의 대부분의 프로젝트에서 번들과 기타 빌드 과정을 거치기 때문에 await만 사용하는 경우,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;해당 코드가 온전한 자바스크립트 모듈로 동작하지 않을 수 있다 !&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;그래서 대부분은 async 함수 안에서 사용하도록 명시하는 것이 안전하다 !&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;그럼에도 유용할 수 있다고 볼 수 있는 경우는 HTML에 자바스크립트 모듈을 직접 연결해서 사용하는 경우가 있다.&lt;/span&gt;&lt;br /&gt;
&lt;pre id=&quot;code_1724306178499&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script type=&quot;module&quot; src=&quot;...&quot; defer&amp;gt;​&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;4-2. URL 구성 요소&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2134&quot; data-origin-height=&quot;422&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4jZVL/btsJcV1mvte/rC1bwfhwQWM7FWcYRAuRT0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4jZVL/btsJcV1mvte/rC1bwfhwQWM7FWcYRAuRT0/img.jpg&quot; data-alt=&quot;출처 : 박영웅 강사님 블로그 https://www.heropy.dev/p/QOWqjV&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4jZVL/btsJcV1mvte/rC1bwfhwQWM7FWcYRAuRT0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4jZVL%2FbtsJcV1mvte%2FrC1bwfhwQWM7FWcYRAuRT0%2Fimg.jpg&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;2134&quot; height=&quot;422&quot; data-origin-width=&quot;2134&quot; data-origin-height=&quot;422&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 박영웅 강사님 블로그 https://www.heropy.dev/p/QOWqjV&lt;/figcaption&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;1. https://&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;프로토콜(Protocol)&lt;/b&gt;:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;https://&lt;/span&gt;는 웹 브라우저와 서버가 서로 데이터를 주고받을 때 사용하는 방법을 나타낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;span&gt;https&lt;/span&gt;는 보안이 강화된 프로토콜로, 데이터를 암호화해서 안전하게 전송한다. &lt;span&gt;http://&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;2. www.heropy.dev&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;도메인 이름(Domain Name)&lt;/b&gt;:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;www&lt;/b&gt;&lt;/span&gt;: 웹 사이트의 서브도메인(subdomain)입니다. 일반적으로 웹사이트의 기본 주소를 가리킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;heropy&lt;/b&gt;&lt;/span&gt;: 이 부분은 웹사이트의 이름. 사람들이 쉽게 기억할 수 있는 주소로, &lt;span&gt;heropy&lt;/span&gt;는 이 웹사이트의 이름.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;.dev&lt;/b&gt;&lt;/span&gt;: 최상위 도메인(TLD)이라고 하며, &lt;span&gt;.com&lt;/span&gt;, &lt;span&gt;.org&lt;/span&gt;, &lt;span&gt;.net&lt;/span&gt;처럼 도메인 이름의 마지막 부분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;.dev&lt;/span&gt;는 개발자나 개발 관련 사이트에서 많이 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전체 호스트 이름&lt;/b&gt;: &lt;span&gt;www.heropy.dev&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. /p/QOWqjV/&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;경로(Path)&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;&lt;span&gt;/p/QOWqjV/&lt;/span&gt;는 서버 내에서 특정 페이지나 자원을 찾기 위한 경로. &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&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;4. ?key=value&amp;amp;a=12&amp;amp;b=34&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;쿼리 문자열(Query String)&lt;/b&gt;:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&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;예를 들어, &lt;span&gt;key=value&lt;/span&gt;, &lt;span&gt;a=12&lt;/span&gt;, &lt;span&gt;b=34&lt;/span&gt;와 같이 &lt;span&gt;key=value&lt;/span&gt; 형식으로 데이터가 전달됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 개의 데이터는 &lt;span&gt;&amp;amp;&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;5. #h1-title&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;프래그먼트(또는 해시, Fragment/Hash)&lt;/b&gt;:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;#&lt;/span&gt; 뒤에 오는 부분은 웹 페이지 내의 특정 위치로 이동하게 해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, &lt;span&gt;#h1-title&lt;/span&gt;은 페이지 내에서 &lt;span&gt;id&lt;/span&gt;가 &lt;span&gt;h1-title&lt;/span&gt;인 위치로 스크롤을 이동하게 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;4-3. 메소드 체이닝(Method Chaining)&lt;/span&gt;&lt;/h2&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;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;가능 예시&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724307537449&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const number = [1, 2, 3]
number.forEach()
// number는 변수가 참조하는 이름일 뿐 
// [1, 2, 3].forEach()와 같음&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724307551108&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function number() {
  return [1, 2, 3]
}
number().forEach()
// number 함수가 호출되면 그 자리에 [1, 2, 3]이 남음
// 항상 함수 호출되는 자리에는 어떠한 데이터가 남아있을까를 생각해야 함&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724307610953&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const number = [1, 2, 3]
number().map(n =&amp;gt; n).forEach()

// 1. number().map(n =&amp;gt; n).forEach()
// 2. [1, 2, 3].map(n=&amp;gt;n).forEach()
// 3. [1, 2, 3].forEach()&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;불가능 예시&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724307647991&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[1, 2, 3].forEach().map(n=&amp;gt;n)

// undefined.map(n =&amp;gt; n)
// forEach()는 undefined를 반환하므로 undefined에 대해 map 메소드를 호출하려고 하면 오류 발생
// undefined는 map 메소드를 가지지 않기 때문에 뒤에 map 체이닝될 수 없음&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;cf.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;forEach()&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;&amp;bull; 역할: 배열의 각 요소에 대해 주어진 함수를 실행합니다.&lt;/span&gt;&lt;br /&gt;&lt;b&gt;&amp;bull; 반환값: undefined&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;map()&lt;br /&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot;&gt;&amp;bull; 역할: 배열의 각 요소에 대해 주어진 함수를 실행하고, 그 결과를 새로운 배열로 반환합니다.&lt;/span&gt;&lt;br /&gt;&lt;b&gt;&amp;bull; 반환값: 변형된 새로운 배열&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;4-4. instanceof 연산자&lt;/span&gt;&lt;/h2&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;&lt;b&gt;왼쪽에 있는 객체&lt;/b&gt;가 &lt;b&gt;오른쪽에 있는 클래스나 생성자 함수의 인스턴스&lt;/b&gt;인지 여부를 &lt;span&gt;true&lt;/span&gt; 또는 &lt;span&gt;false&lt;/span&gt;로 반환한다.&lt;/p&gt;
&lt;pre id=&quot;code_1724313585375&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;object instanceof Constructor(생성자함수 또는 클래스)&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;/p&gt;
&lt;pre id=&quot;code_1724319381730&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Car {
  constructor(model) {
    this.model = model;
  }
}

let myCar = new Car(&quot;Toyota&quot;);

console.log(myCar instanceof Car); // true&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;instanceof의 동작 방식&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;instanceof&lt;/span&gt;는 &lt;i&gt;&lt;b&gt;객체의 프로토타입 체인&lt;/b&gt;&lt;/i&gt;을 따라가면서, 해당 객체가 특정 생성자 함수 또는 클래스의 인스턴스인지 확인합니다. 즉, 객체의 프로토타입 체인이 생성자 함수의 &lt;span&gt;prototype&lt;/span&gt; 속성을 포함하고 있는지를 확인하는 것입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1724320375555&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Animal() {}
function Dog() {}

Dog.prototype = Object.create(Animal.prototype);

let myDog = new Dog();

console.log(myDog instanceof Dog);    // true
console.log(myDog instanceof Animal); // true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1. 객체와 프로토타입&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;객체(Object): 자바스크립트에서 모든 것은 객체로 이루어져 있습니다. 객체는 여러 속성(프로퍼티)과 메서드(함수)를 가질 수 있습니다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;프로토타입(Prototype): 자바스크립트의 모든 객체는 또 다른 객체인 &amp;ldquo;프로토타입&amp;rdquo;을 가지고 있습니다. 이 프로토타입 객체는 해당 객체가 사용할 수 있는 속성이나 메서드를 상속(물려받음)하는 역할을 합니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2. 프로토타입 체인이란?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;프로토타입 체인은 여러 객체들이 서로 연결된 &amp;ldquo;연쇄 구조&amp;rdquo;를 의미합니다. 특정 객체에서 속성이나 메서드를 찾을 때, 자바스크립트는 그 객체에 해당 속성이 있는지 먼저 찾습니다. 만약 해당 속성이 없다면, 그 객체의 프로토타입에서 다시 찾아보는 과정을 거칩니다. 이 과정을 계속 반복해, 최상위 프로토타입 객체인 Object.prototype에 도달할 때까지 찾습니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 과정에서 연결된 객체들의 연쇄 구조가 바로 프로토타입 체인입니다.&lt;/span&gt;&lt;br /&gt;
&lt;pre id=&quot;code_1724319834463&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let person = {
  name: &quot;Alice&quot;,
  greet: function() {
    console.log(&quot;Hello!&quot;);
  }
};

let student = {
  study: function() {
    console.log(&quot;Studying...&quot;);
  }
};

// student의 프로토타입을 person으로 설정
student.__proto__ = person;

console.log(student.name); // &quot;Alice&quot;
student.greet();           // &quot;Hello!&quot;
student.study();           // &quot;Studying...&quot;​&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;color: #000000;&quot;&gt;&lt;b&gt;student&lt;/b&gt;&lt;b&gt; 객체&lt;/b&gt;는 study라는 메서드만 가지고 있지만 student.__proto__를 person 객체로 설정했기 때문에, student는 이제 person의 속성(name)과 메서드(greet)를 사용할 수 있습니다.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;span style=&quot;color: #000000;&quot;&gt;3. 프로토타입 체인의 끝&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;모든 객체의 프로토타입 체인은 최종적으로 Object.prototype 객체에서 끝납니다. Object.prototype은 모든 객체의 최상위 프로토타입이므로, 이 객체에서 찾을 수 없는 속성이나 메서드는 정의되어 있지 않은 것으로 간주됩니다.&lt;/span&gt;&lt;br /&gt;
&lt;pre id=&quot;code_1724320312421&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log(student.toString()); // &quot;[object Object]&quot;​&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여기서 toString() 메서드는 student 객체나 person 객체에 정의되어 있지 않지만, 자바스크립트는 계속 프로토타입 체인을 따라 올라가 Object.prototype.toString 메서드를 찾아서 실행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&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;span&gt;&amp;nbsp;&lt;/span&gt;Array와 instanceof&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;arr&lt;span&gt;는 배열(&lt;/span&gt;Array&lt;span&gt;)이므로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;arr instanceof Array&lt;span&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;true&lt;span&gt;를 반환합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;arr&lt;/span&gt;는 &lt;i&gt;&lt;b&gt;자바스크립트의 모든 배열이 사실 객체(&lt;span&gt;Object&lt;/span&gt;)이기도 하기 때문&lt;/b&gt;&lt;/i&gt;에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;arr instanceof Object&lt;/span&gt;도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;true&lt;/span&gt;를 반환합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1724320452607&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;let arr = [];

console.log(arr instanceof Array);    // true
console.log(arr instanceof Object);   // true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;배열이 객체라는 의미&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;자바스크립트에서 배열도 사실 객체입니다. 배열은 객체처럼 키-값 쌍을 사용해 데이터를 저장하지만, 특별히 인덱스(숫자 키)를 사용해 데이터를 관리합니다.&lt;/span&gt;&lt;br /&gt;
&lt;pre id=&quot;code_1724321113152&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let fruits = [&quot;Apple&quot;, &quot;Banana&quot;, &quot;Cherry&quot;];​&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1724321117329&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let fruits = {
  0: &quot;Apple&quot;,
  1: &quot;Banana&quot;,
  2: &quot;Cherry&quot;
};​&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;배열의 각 요소는 숫자(0, 1, 2&amp;hellip;)를 키로 가지는 객체의 속성으로 저장됩니다. 그래서 자바스크립트에서는 배열도 객체의 일종이라고 할 수 있는 것입니다.&lt;/span&gt;&lt;/blockquote&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;span&gt;iframe&lt;/span&gt; 등에서)에서 생성된 객체에 대해 &lt;span&gt;instanceof&lt;/span&gt;를 사용할 때는 예상치 못한 결과가 나올 수 있습니다. 이는 자바스크립트의 각 실행 환경(스코프)이 자체적인 내장 객체(예: &lt;span&gt;Array&lt;/span&gt;, &lt;span&gt;Object&lt;/span&gt; 등)를 가지고 있기 때문입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1724321905417&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let iframe = document.createElement('iframe');
document.body.appendChild(iframe);

let arr = new iframe.contentWindow.Array();

console.log(arr instanceof Array); // false
console.log(arr instanceof iframe.contentWindow.Array); // true&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&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;arr1&lt;/span&gt;은 메인 페이지의 &lt;span&gt;Array&lt;/span&gt; 생성자로부터 생성된 배열입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;arr2&lt;/span&gt;는 &lt;span&gt;iframe&lt;/span&gt; 내부의 &lt;span&gt;Array&lt;/span&gt; 생성자로부터 생성된 배열입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;arr1 instanceof Array&lt;/span&gt;는 &lt;span&gt;true&lt;/span&gt;를 반환합니다. 이는 &lt;span&gt;arr1&lt;/span&gt;이 메인 페이지의 &lt;span&gt;Array&lt;/span&gt; 생성자로부터 생성되었기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;그러나 &lt;span&gt;arr2 instanceof Array&lt;/span&gt;는 &lt;span&gt;false&lt;/span&gt;를 반환합니다. 이는 &lt;span&gt;arr2&lt;/span&gt;가 &lt;span&gt;iframe&lt;/span&gt; 내부의 &lt;span&gt;Array&lt;/span&gt; 생성자로부터 생성되었기 때문에, 메인 페이지의 &lt;span&gt;Array&lt;/span&gt;와는 다른 생성자이기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;다른 스코프&lt;/b&gt;란 자바스크립트에서 실행 환경이나 컨텍스트가 서로 다른 경우를 의미합니다. 예를 들어, 웹 페이지에서 실행되는 자바스크립트 코드와 그 안에 삽입된 iframe 내부에서 실행되는 자바스크립트 코드는 서로 다른 스코프에서 실행됩니다. 각 스코프는 자바스크립트의 내장 객체(예: Array, Object, Function 등)를 자체적으로 관리합니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;스코프란?&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;스코프는 변수가 정의되고 접근할 수 있는 범위를 의미합니다. 예를 들어, 함수 안에서 선언된 변수는 그 함수 내에서만 접근할 수 있는 것처럼, 특정 실행 환경에서 실행되는 코드들은 그 환경의 스코프를 따릅니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;iframe과 다른 스코프&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;iframe은 HTML 문서 안에 또 다른 HTML 문서를 삽입할 수 있는 요소입니다. iframe은 독립적인 문서로 취급되며, 해당 iframe 내부에서 실행되는 자바스크립트 코드도 메인 페이지와는 독립적인 스코프를 가집니다.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예를 들어, 메인 페이지에서 사용하는 Array 객체와 iframe 내부에서 사용하는 Array 객체는 서로 다른 Array 생성자를 참조할 수 있습니다. 이는 각각의 스코프가 자체적으로 내장 객체를 관리하기 때문입니다.&lt;/span&gt;&lt;/blockquote&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;&lt;a href=&quot;https://ko.javascript.info/async-await&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ko.javascript.info/async-await&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724306321529&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;async와 await&quot; data-og-description=&quot;&quot; data-og-host=&quot;ko.javascript.info&quot; data-og-source-url=&quot;https://ko.javascript.info/async-await&quot; data-og-url=&quot;https://ko.javascript.info/async-await&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cmwhz4/hyWShwSWXs/KDrffbI9tUYLV8jlJ4Y9o0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bXDXl5/hyWSio0yjf/HxbXO56TwdovJf6TPp1Y51/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512&quot;&gt;&lt;a href=&quot;https://ko.javascript.info/async-await&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.javascript.info/async-await&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cmwhz4/hyWShwSWXs/KDrffbI9tUYLV8jlJ4Y9o0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bXDXl5/hyWSio0yjf/HxbXO56TwdovJf6TPp1Y51/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512');&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;async와 await&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ko.javascript.info&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%B2%98%EB%A6%AC-async-await&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%B2%98%EB%A6%AC-async-await&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724306444901&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;  자바스크립트 Async/Await 개념 &amp;amp; 문법 정복&quot; data-og-description=&quot;자바스크립트 비동기 처리 3가지 방식 자바스크립트는 싱글 스레드 프로그래밍 언어기 때문에 멀티 작업을 하기 위해선 비동기 처리 방식이 자주 쓰인다. 비동기 처리는 백그라운드로 동작되기&quot; data-og-host=&quot;inpa.tistory.com&quot; data-og-source-url=&quot;https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%B2%98%EB%A6%AC-async-await&quot; data-og-url=&quot;https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%B2%98%EB%A6%AC-async-await&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/w8G1P/hyWSmrpZhX/k3b3gGWF9MAPTZ0ybqSlrk/img.jpg?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/QYqxU/hyWSjaoNO2/FEI1YAyXtYHR2PToDL7yUK/img.jpg?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/vmkw4/hyWSaqZixM/CVctLawSUNibu18FZlNHq1/img.png?width=615&amp;amp;height=462&amp;amp;face=0_0_615_462&quot;&gt;&lt;a href=&quot;https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%B2%98%EB%A6%AC-async-await&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%B2%98%EB%A6%AC-async-await&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/w8G1P/hyWSmrpZhX/k3b3gGWF9MAPTZ0ybqSlrk/img.jpg?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/QYqxU/hyWSjaoNO2/FEI1YAyXtYHR2PToDL7yUK/img.jpg?width=800&amp;amp;height=400&amp;amp;face=0_0_800_400,https://scrap.kakaocdn.net/dn/vmkw4/hyWSaqZixM/CVctLawSUNibu18FZlNHq1/img.png?width=615&amp;amp;height=462&amp;amp;face=0_0_615_462');&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;  자바스크립트 Async/Await 개념 &amp;amp; 문법 정복&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;자바스크립트 비동기 처리 3가지 방식 자바스크립트는 싱글 스레드 프로그래밍 언어기 때문에 멀티 작업을 하기 위해선 비동기 처리 방식이 자주 쓰인다. 비동기 처리는 백그라운드로 동작되기&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;inpa.tistory.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;</description>
      <category>Live Class/Beginner</category>
      <author>dearsuhyun</author>
      <guid isPermaLink="true">https://diveintodevworld.tistory.com/74</guid>
      <comments>https://diveintodevworld.tistory.com/74#entry74comment</comments>
      <pubDate>Thu, 22 Aug 2024 19:28:16 +0900</pubDate>
    </item>
    <item>
      <title>Recap | Beginner Live Class Recap 2,3회차</title>
      <link>https://diveintodevworld.tistory.com/73</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;2-1. 리액트에서는 단일요소가 return 되어야 한다&lt;/span&gt;&lt;/h2&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;return&lt;/span&gt; 문에서 JSX를 반환할 때, 반드시 하나의 최상위 요소로 감싸야 한다&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;599&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oLHmz/btsJbrmgDSj/qNZ4Bb6PIRgvtqFtXNg7nk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oLHmz/btsJbrmgDSj/qNZ4Bb6PIRgvtqFtXNg7nk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oLHmz/btsJbrmgDSj/qNZ4Bb6PIRgvtqFtXNg7nk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoLHmz%2FbtsJbrmgDSj%2FqNZ4Bb6PIRgvtqFtXNg7nk%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;1280&quot; height=&quot;599&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;599&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트 컴포넌트는 JSX를 반환할 때, 여러 요소를 반환할 수 있지만, 이 요소들을 &lt;b&gt;하나의 부모 요소&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;&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) 단일 부모 요소로 감싸기&lt;/p&gt;
&lt;pre id=&quot;code_1724283066719&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function MyComponent() {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Hello&amp;lt;/h1&amp;gt;
      &amp;lt;p&amp;gt;This is a paragraph.&amp;lt;/p&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;2) React Fragement 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부모 요소가 필요 없지만 여전히 다수의 요소를 반환해야 한다면, &lt;span&gt;React.Fragment&lt;/span&gt; 또는 빈 태그(&lt;span&gt;&amp;lt;&amp;gt;...&amp;lt;/&amp;gt;&lt;/span&gt;)를 사용할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1724283087084&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function MyComponent() {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;h1&amp;gt;Hello&amp;lt;/h1&amp;gt;
      &amp;lt;p&amp;gt;This is a paragraph.&amp;lt;/p&amp;gt;
    &amp;lt;/&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;2-2. 구조분해할당 이해하기&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구조 분해 할당(Destructuring Assignment)&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;1) 배열 구조분해할당&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;[b, c, d] = numbers&lt;/span&gt;는 &lt;span&gt;numbers&lt;/span&gt; 배열의 첫 번째, 두 번째, 세 번째 값을 각각 &lt;span&gt;b&lt;/span&gt;, &lt;span&gt;c&lt;/span&gt;, &lt;span&gt;d&lt;/span&gt;에 할당&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;--&amp;gt; 인덱스를 일일이 지정할 필요 없이, 배열의 값을 간편하게 꺼내어 사용할 수 있음&lt;/p&gt;
&lt;pre id=&quot;code_1724283868835&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const numbers = [1, 2, 3, 4];

// 기존 방식
const b = numbers[0];
const c = numbers[1];
const d = numbers[2];

// 구조 분해 할당 방식
const [b, c, d] = numbers;

console.log(b); // 1
console.log(c); // 2
console.log(d); // 3&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;2) 객체 구조분해할당&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{ name } = users&lt;span&gt;는 &lt;/span&gt;users&lt;span&gt; 객체에서 &lt;/span&gt;name&lt;span&gt; 속성의 값을 변수 &lt;/span&gt;name&lt;span&gt;에 할당&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;--&amp;gt; &lt;/span&gt;객체에서 원하는 속성을 간편하게 꺼내어 사용할 수 있음&lt;/p&gt;
&lt;pre id=&quot;code_1724283942617&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const users = {
  name: &quot;Mike&quot;,
  age: 30
};

// 기존 방식
// const name = users.name;

// 구조 분해 할당 방식
const { name } = users;

console.log(name); // &quot;Mike&quot;&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;&lt;b&gt;- 기본값 할당 지정&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 &lt;span&gt;users&lt;/span&gt; 객체에서 &lt;span&gt;email&lt;/span&gt; 속성을 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 &lt;span&gt;users&lt;/span&gt; 객체에 &lt;span&gt;email&lt;/span&gt; 속성이 없거나 &lt;span&gt;undefined&lt;/span&gt;일 경우, &lt;span&gt;&quot;suhyun8667@naver.com&quot;&lt;/span&gt;이라는 기본값이 대신 사용된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 기본값은 &lt;span&gt;email&lt;/span&gt;이라는 속성이 없거나 정의되지 않았을 때 안전하게 사용할 값을 미리 지정하는 데 유용하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 &lt;span&gt;users&lt;/span&gt; 객체에 &lt;span&gt;email&lt;/span&gt; 속성이 있다면, 그 값이 &lt;span&gt;email&lt;/span&gt; 변수에 할당된다.&lt;/p&gt;
&lt;pre id=&quot;code_1724284033832&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const { email = &quot;suhyun8667@naver.com&quot; } = users;
console.log(email);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&amp;bull; 만약 users = {}라면:&lt;br /&gt;email 변수는 &quot;suhyun8667@naver.com&quot; 값을 가 지고&lt;br /&gt;&lt;br /&gt;&amp;bull; 만약 users = { email: &quot;anotheremail@example.com&quot; }라면:&lt;br /&gt;email 변수는 &quot;anotheremail@example.com&quot; 값을 가진다&lt;/blockquote&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;&lt;span&gt; &lt;/span&gt;이 코드는 &lt;span&gt;users&lt;/span&gt; 객체에서 &lt;span&gt;age&lt;/span&gt; 속성을 찾아서 그 값을 &lt;span&gt;userAge&lt;/span&gt;라는 새로운 변수에 할당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;span&gt;age&lt;/span&gt;라는 속성을 &lt;span&gt;userAge&lt;/span&gt;라는 이름으로 &lt;b&gt;바꾸어서&lt;/b&gt; 사용할 수 있게 해주는 것 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수 이름이 이미 다른 부분에서 사용되고 있거나, 더 의미 있는 이름으로 바꿔서 사용하고 싶을 때 유용하다.&lt;/p&gt;
&lt;pre id=&quot;code_1724284157748&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const { age: userAge } = users;
console.log(userAge);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;3-1. Typescript에서 type과 interface의 차이점&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 기본적인 차이점&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&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;b&gt;interface&lt;/b&gt;&lt;/span&gt;: 주로 &lt;b&gt;객체의 구조&lt;/b&gt;를 정의하는 데 사용됩니다. 객체가 가져야 할 속성의 이름과 타입을 명확히 정의합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;b&gt;type&lt;/b&gt;&lt;/span&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;2. 코드 분석&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724285698565&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export interface ICountValue {
  a: number;
  b: string;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ICountValue&lt;/span&gt;라는 인터페이스를 정의하여, &lt;span&gt;a&lt;/span&gt;라는 숫자 속성과 &lt;span&gt;b&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;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724285707350&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export type CountValue = number;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;CountValue&lt;/span&gt;라는 타입을 정의하여, 숫자 타입의 별칭을 만들었다. 즉, &lt;span&gt;CountValue&lt;/span&gt;는 &lt;span&gt;number&lt;/span&gt;와 같은 의미 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;type&lt;/span&gt;은 인터페이스처럼 객체의 구조뿐만 아니라, &lt;b&gt;기본 타입(number, string 등)&lt;/b&gt;, &lt;b&gt;유니언 타입&lt;/b&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;3. 구체적인 차이점&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;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;인터페이스&lt;/b&gt;는 &lt;b&gt;확장이 가능하다&lt;/b&gt;. 즉, 다른 인터페이스를 상속받아 확장 가능 !&lt;/p&gt;
&lt;pre id=&quot;code_1724285814184&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface IBase {
  a: number;
}

interface IExtended extends IBase {
  b: string;
}&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&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;타입&lt;/b&gt;은 교차 타입(Intersection Types)을 통해 확장 가능&lt;/p&gt;
&lt;pre id=&quot;code_1724285854065&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type Base = {
  a: number;
};

type Extended = Base &amp;amp; {
  b: string;
};&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;유니언 타입 정의&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;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;type&lt;/span&gt;을 사용하면 유니언 타입을 정의할 수 있습니다. 인터페이스는 유니언 타입 직접적으로 표현하지 못함&lt;/p&gt;
&lt;pre id=&quot;code_1724285897381&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type StringOrNumber = string | number;
// string or number&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;중복 선언 가능성&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;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;인터페이스&lt;/b&gt;는 같은 이름으로 여러 번 선언할 수 있으며, 선언된 내용은 자동으로 병합된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;--&amp;gt; &amp;ldquo;선언 병합(Declaration Merging)&amp;rdquo;&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_1724285921181&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface IUser {
  name: string;
}

interface IUser {
  age: number;
}

const user: IUser = {
  name: &quot;Alice&quot;,
  age: 30,
};&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;4. 언제 무엇을 사용할까?&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;interface&lt;/b&gt;: 객체의 구조를 정의하고, 이 구조를 상속받거나 확장할 필요가 있는 경우 인터페이스를 사용하는 것이 좋습니다. 특히 클래스 기반의 구조에서 사용하기 적합합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;type&lt;/b&gt;&lt;/span&gt;: 기본 타입의 별칭을 만들거나, 유니언 타입, 교차 타입, 튜플 등을 정의할 때 사용합니다. 복잡한 타입 조합이 필요한 경우 유용합니다.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;924&quot; data-origin-height=&quot;940&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWYytg/btsJaRFM9iS/xWNVRHuWDkrKWcyN2KZarK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWYytg/btsJaRFM9iS/xWNVRHuWDkrKWcyN2KZarK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWYytg/btsJaRFM9iS/xWNVRHuWDkrKWcyN2KZarK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWYytg%2FbtsJaRFM9iS%2FxWNVRHuWDkrKWcyN2KZarK%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;924&quot; height=&quot;940&quot; data-origin-width=&quot;924&quot; data-origin-height=&quot;940&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;3-2. 비동기적으로 데이터 요청하기&lt;/span&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1724286491838&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async function fetchData() {
  const responseObject = await fetch('https://api.heropy.dev/v0/users');
  const data = await responseObject.json(); 

  console.log(data);
}

fetchData(); // 함수 호출&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&gt;&lt;span&gt; &lt;/span&gt;1.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;fetchData&lt;/b&gt;&lt;/span&gt;&lt;b&gt; 함수가 호출된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;async&lt;/span&gt; 키워드로 정의된 이 함수는 내부에서 &lt;span&gt;await&lt;/span&gt; 키워드를 사용하여 비동기 작업을 처리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비동기 함수는 기본적으로 &lt;b&gt;Promise&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;span&gt;&lt;span&gt; &lt;/span&gt;2.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;API 요청을 보낸다 (&lt;/b&gt;&lt;span&gt;&lt;b&gt;fetch&lt;/b&gt;&lt;/span&gt;&lt;b&gt;).&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fetch('&lt;a href=&quot;https://api.heropy.dev/v0/users')&quot;&gt;https://api.heropy.dev/v0/users')&lt;/a&gt;&lt;/span&gt;는 API로 HTTP 요청을 보내는 비동기 작업이다. 이 작업은 사용자 데이터를 가져오기 위한 요청을 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&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;span&gt;&lt;span&gt; &lt;/span&gt;3.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;await&lt;/b&gt;&lt;/span&gt;&lt;b&gt;로 응답을 기다린다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt; 키워드를 사용하면, &lt;span&gt;fetch&lt;/span&gt; 요청이 완료될 때까지 코드 실행이 일시 정지된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;fetch&lt;/span&gt;가 완료되면 서버에서 응답이 도착하고, 이 응답은 &lt;span&gt;responseObject&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&gt;&lt;span&gt; &lt;/span&gt;4.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;JSON 데이터로 변환한다 (&lt;/b&gt;&lt;/span&gt;&lt;b&gt;responseObject.json()&lt;/b&gt;&lt;span&gt;&lt;b&gt;).&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;responseObject.json()&lt;/span&gt;은 응답 본문을 JSON 형태로 변환하는 또 다른 비동기 작업이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;await&lt;/span&gt; 키워드를 사용하여 JSON 변환이 완료될 때까지 기다리고, 변환된 데이터는 &lt;span&gt;data&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&gt;&lt;span&gt; &lt;/span&gt;5.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;콘솔에 데이터를 출력한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;변환된 JSON 데이터가 &lt;span&gt;data&lt;/span&gt; 변수에 저장된 후, 이 데이터를 &lt;span&gt;console.log(data)&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&gt;&lt;span&gt; &lt;/span&gt;6.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;함수를 호출하여 실행한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;마지막으로 &lt;span&gt;fetchData();&lt;/span&gt;를 호출하여 이 비동기 함수가 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;3-3. 화면에 user 목록 띄우기 예제&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1208&quot; data-origin-height=&quot;2200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mmbzJ/btsJaojOIqE/gpCss28EKbGWGtceYabDg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mmbzJ/btsJaojOIqE/gpCss28EKbGWGtceYabDg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mmbzJ/btsJaojOIqE/gpCss28EKbGWGtceYabDg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmmbzJ%2FbtsJaojOIqE%2FgpCss28EKbGWGtceYabDg0%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;1208&quot; height=&quot;2200&quot; data-origin-width=&quot;1208&quot; data-origin-height=&quot;2200&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;pre id=&quot;code_1724286751251&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const [users, setUsers] = useState([])
  // 여기에서 빈 배열에는 무엇이 들어가 있을지 알 수가 없음
  // 즉 이 배열데이터가 어떤 타입인지 모르는 상태
  // ts는 쌩으로 빈 배열이라고 판단하고 이 안에는 아무것도 들어갈 수 없다고 판단함
  // never[]
  // 이렇게만 해주면 밑에 jsx 문법 부분에서 {user.name}에 오류 발생
  // user는 never이기 때문에 name이라는 속성이 존재 하지 않아서 오류가 발생함
  
  const [users, setUsers] = useState&amp;lt;User[]&amp;gt;([])
  // 따라서 Users의 배열이라고 type을 직접 명시해줘야 함&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724287228664&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const [count, setCount] = useState(31)
  // 이 부분의 경우는 초기 값이 이미 number이기 때문에 type 추론 가능, 따로 명시 안해줘도 됨&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;3-4. 함수 호이스팅&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 호이스팅은 함수 선언식일 때만 가능 !&lt;/p&gt;
&lt;pre id=&quot;code_1724296931471&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 함수 표현식 (할당 연산자가 있는 것)
// 호이스팅 되지 않음.
const getUsers = async () =&amp;gt; {}

// 함수 선언식
// 호이스팅 가능. 위로 올라가서 정의되기 때문에 정상적으로 동작
async function getUsers() {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;3-5. promise 객체&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;promise 객체란 ?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트&amp;nbsp;Promise&amp;nbsp;객체는&amp;nbsp;비동기&amp;nbsp;작업의&amp;nbsp;최종&amp;nbsp;완료&amp;nbsp;또는&amp;nbsp;실패를&amp;nbsp;나타내는&amp;nbsp;Array나&amp;nbsp;Object&amp;nbsp;처럼&amp;nbsp;독자적인&amp;nbsp;객체라고&amp;nbsp;보면&amp;nbsp;된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비동기 작업이 끝날 때까지 결과를 기다리는 것이 아니라, 결과를 제공하겠다는 '약속'을 반환한다는 의미에서 Promise라 지어졌다고 한다.&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;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;promise 객체 생성&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: #212529; text-align: left;&quot;&gt;Promise&amp;nbsp;객체를&amp;nbsp;생성하려면&amp;nbsp;new&amp;nbsp;키워드와&amp;nbsp;Promise&amp;nbsp;생성자&amp;nbsp;함수를&amp;nbsp;사용하면&amp;nbsp;된다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;이때&amp;nbsp;Promise&amp;nbsp;생성자&amp;nbsp;안에&amp;nbsp;두개의&amp;nbsp;매개변수를&amp;nbsp;가진&amp;nbsp;콜백&amp;nbsp;함수를&amp;nbsp;넣게&amp;nbsp;되는데,&amp;nbsp;첫&amp;nbsp;번째&amp;nbsp;인수는&amp;nbsp;작업이&amp;nbsp;성공했을&amp;nbsp;때&amp;nbsp;성공(resolve)임을&amp;nbsp;알려주는&amp;nbsp;객체이며,&amp;nbsp;두&amp;nbsp;번째&amp;nbsp;인수는&amp;nbsp;작업이&amp;nbsp;실패했을&amp;nbsp;때&amp;nbsp;실패(reject)임을&amp;nbsp;알려주는&amp;nbsp;오류&amp;nbsp;객체이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724301862594&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const myPromise = new Promise((resolve, reject) =&amp;gt; {
	// 비동기 작업 수행
    const data = fetch('서버로부터 요청할 URL');
    
    if(data)
    	resolve(data); // 만일 요청이 성공하여 데이터가 있다면
    else
    	reject(&quot;Error&quot;); // 만일 요청이 실패하여 데이터가 없다면
})&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;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;propmise 객체의 3가지 상태&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfzVZR/btsJcNhTWub/iCzAuJg4HOdl9tpmReFvK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfzVZR/btsJcNhTWub/iCzAuJg4HOdl9tpmReFvK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfzVZR/btsJcNhTWub/iCzAuJg4HOdl9tpmReFvK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfzVZR%2FbtsJcNhTWub%2FiCzAuJg4HOdl9tpmReFvK1%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;900&quot; height=&quot;500&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;801&quot; data-origin-height=&quot;297&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dWHPux/btsJbhYDsSM/qvJvHYgImaNFU2qW25UaK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dWHPux/btsJbhYDsSM/qvJvHYgImaNFU2qW25UaK0/img.png&quot; data-alt=&quot;출처 : https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dWHPux/btsJbhYDsSM/qvJvHYgImaNFU2qW25UaK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdWHPux%2FbtsJbhYDsSM%2FqvJvHYgImaNFU2qW25UaK0%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;801&quot; height=&quot;297&quot; data-origin-width=&quot;801&quot; data-origin-height=&quot;297&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise&lt;/figcaption&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;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;1) pending&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;이행하지도, 거부하지도 않은 초기 상태&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&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;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;2) resolved&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;이 확정된 상태는 &lt;span&gt;fulfilled&lt;/span&gt;(성공)일 수도 있고, &lt;span&gt;rejected&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: #ffffff; color: #212529; text-align: left;&quot;&gt;3-1) fulfilled&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;작업이 성공적으로 완료됨을 의미&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;3-2) rejected&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;작업이 실패했음을 의미&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;promise의 메서드&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;1) .then()&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;promise 객체가 fulfilled 상태가 되면 실행할 콜백함수를 등록하는 메서드&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;2) .catch()&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;promise 객체가 rejected 상태가 되면 실행할 콜백함수를 등록하는 메서드&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;3) .finally()&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: left;&quot;&gt;어떤 작업의 성공, 실패 여부와 상관없이 항상 실행하고 싶은 콜백함수를 등록하는 메서드&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724301893298&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;myPromise
    .then((value) =&amp;gt; { // 성공적으로 수행했을 때 실행될 코드
    	console.log(&quot;Data: &quot;, value); // 위에서 return resolve(data)의 data값이 출력된다
    })
    .catch((error) =&amp;gt; { // 실패했을 때 실행될 코드
     	console.error(error); // 위에서 return reject(&quot;Error&quot;)의 &quot;Error&quot;가 출력된다
    })
    .finally(() =&amp;gt; { // 성공하든 실패하든 무조건 실행될 코드
    	
    })&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;프로미스 동시성(Promise concurrency)를 지원하는 메소드&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Promise.all()&lt;/li&gt;
&lt;li&gt;Promise.allSettled()&lt;/li&gt;
&lt;li&gt;Promise.any()&lt;/li&gt;
&lt;li&gt;Promise.race()&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) Promise.all()&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Promise.all()&lt;/span&gt;은 주어진 모든 프로미스가 &lt;b&gt;모두 이행(fulfilled)&lt;/b&gt;될 때까지 기다립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 프로미스가 성공적으로 완료되면 결과들을 배열로 반환합니다. 만약 하나라도 거부(rejected)되면, 전체가 거부 상태로 바뀝니다.&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; 여러 비동기 작업(예: 여러 개의 API 호출)이 모두 성공해야 할 때.&lt;/p&gt;
&lt;pre id=&quot;code_1724300466895&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let promise1 = Promise.resolve('작업 1 완료');
let promise2 = Promise.resolve('작업 2 완료');
let promise3 = Promise.resolve('작업 3 완료');

Promise.all([promise1, promise2, promise3]).then((results) =&amp;gt; {
  console.log(results); // ['작업 1 완료', '작업 2 완료', '작업 3 완료']
});&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: #ffffff; color: #212529; text-align: start;&quot;&gt;2) &lt;/span&gt;Promise.allSettled()&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Promise.allSettled()&lt;/span&gt;은 주어진 모든 프로미스가 &lt;b&gt;완료(settled)&lt;/b&gt;될 때까지 기다립니다. 이때 완료된 프로미스는 성공이든 실패든 상관없이 결과를 반환합니다. 결과는 각 프로미스의 상태(&lt;span&gt;fulfilled&lt;/span&gt; 또는 &lt;span&gt;rejected&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;/b&gt; 성공과 실패 여부에 관계없이 모든 비동기 작업이 끝난 후 결과를 처리하고자 할 때.&lt;/p&gt;
&lt;pre id=&quot;code_1724300540477&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let promise1 = Promise.resolve('작업 1 완료');
let promise2 = Promise.reject('작업 2 실패');
let promise3 = Promise.resolve('작업 3 완료');

Promise.allSettled([promise1, promise2, promise3]).then((results) =&amp;gt; {
  console.log(results);
  // [{status: 'fulfilled', value: '작업 1 완료'},
  //  {status: 'rejected', reason: '작업 2 실패'},
  //  {status: 'fulfilled', value: '작업 3 완료'}]
});&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: #ffffff; color: #212529; text-align: start;&quot;&gt;3) Promise.any()&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Promise.any()&lt;/span&gt;는 주어진 프로미스 중 &lt;b&gt;가장 먼저 성공한(fulfilled)&lt;/b&gt; 프로미스의 결과를 반환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 프로미스가 거부(rejected)되면 &lt;span&gt;AggregateError&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;/b&gt; 여러 비동기 작업 중에서 하나라도 성공하면 그 결과를 사용하고, 모두 실패했을 때만 에러를 처리하고자 할 때.&lt;/p&gt;
&lt;pre id=&quot;code_1724300610396&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let promise1 = new Promise((resolve, reject) =&amp;gt; setTimeout(reject, 100, '실패'));
let promise2 = new Promise((resolve) =&amp;gt; setTimeout(resolve, 200, '성공!'));
let promise3 = new Promise((resolve) =&amp;gt; setTimeout(resolve, 300, '또 다른 성공!'));

Promise.any([promise1, promise2, promise3]).then((result) =&amp;gt; {
  console.log(result); // '성공!'이 출력됩니다.
});&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: #ffffff; color: #212529; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;4) Promise.race()&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Promise.race()&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;는 주어진 프로미스 중&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;가장 먼저 완료된&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;프로미스의 결과를 반환합니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&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;/b&gt; 여러 비동기 작업 중에서 가장 빨리 완료된 작업의 결과만 필요할 때.&lt;/p&gt;
&lt;pre id=&quot;code_1724300582979&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let promise1 = new Promise((resolve) =&amp;gt; setTimeout(resolve, 500, '500ms'));
let promise2 = new Promise((resolve) =&amp;gt; setTimeout(resolve, 100, '100ms'));

Promise.race([promise1, promise2]).then((result) =&amp;gt; {
  console.log(result); // '100ms'가 출력됩니다.
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;cf. 이터러블(Iterable)&lt;/b&gt;&lt;br /&gt;자바스크립트에서 반복 가능한 객체(여러 개의 값을 하나씩 순서대로 접근할 수 있는 객체)를 의미&lt;br /&gt;&lt;br /&gt;&lt;b&gt;예시&lt;/b&gt;&lt;br /&gt;1. 배열(Array):&lt;br /&gt;예를 들어, 사과, 바나나, 오렌지가 들어 있는 과일 바구니가 있다고 해보세요. 이 바구니에서 하나씩 과일을 꺼낼 수 있다면, 이 바구니는 이터러블입니다. 자바스크립트에서 배열은 대표적인 이터러블입니다. [사과, 바나나, 오렌지]처럼 배열에 여러 개의 요소가 들어 있고, 이걸 하나씩 꺼내볼 수 있는 거죠.&lt;br /&gt;&lt;br /&gt;2. 문자열(String):&lt;br /&gt;&amp;ldquo;hello&amp;rdquo;라는 단어를 생각해봅시다. 이 단어에서 &amp;lsquo;h&amp;rsquo;, &amp;lsquo;e&amp;rsquo;, &amp;lsquo;l&amp;rsquo;, &amp;lsquo;l&amp;rsquo;, &amp;lsquo;o&amp;rsquo;를 하나씩 꺼낼 수 있다면, 이 문자열도 이터러블입니다.&lt;br /&gt;자바스크립트에서 문자열도 하나씩 문자를 꺼낼 수 있기 때문에 이터러블입니다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Promise.any()와 연결하기&lt;/b&gt;&lt;br /&gt;Promise.any()는 여러 개의 프로미스(Promise) 중에서 가장 먼저 성공한(이행된) 결과를 얻고 싶을 때 사용합니다. 이때 여러 개의 프로미스를 배열 같은 이터러블에 넣어서 Promise.any()에 전달할 수 있습니다.
&lt;pre id=&quot;code_1724300159513&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let promise1 = new Promise((resolve, reject) =&amp;gt; setTimeout(reject, 100, '실패'));
let promise2 = new Promise((resolve) =&amp;gt; setTimeout(resolve, 200, '성공!'));
let promise3 = new Promise((resolve) =&amp;gt; setTimeout(resolve, 300, '또 다른 성공!'));

Promise.any([promise1, promise2, promise3]).then((result) =&amp;gt; {
  console.log(result); // '성공!'이 출력됩니다.
});​&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;여기서 [promise1, promise2, promise3]는 이터러블(하나씩 꺼내볼 수 있는 배열)입니다. Promise.any()는 이 배열에서 가장 먼저 성공한 promise2의 결과인 '성공!'을 반환합니다.&lt;/blockquote&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;Promise() 생성자&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724301666463&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;new Promise(executor);&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;Promise&lt;span style=&quot;background-color: #ffffff; color: #1b1b1b; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;객체는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;new&lt;span style=&quot;background-color: #ffffff; color: #1b1b1b; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&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: #1b1b1b; text-align: start;&quot;&gt;생성자는 매개변수로 &quot;실행 함수&quot;를 받습니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1b1b1b; text-align: start;&quot;&gt;이 함수는 매개 변수로 두 가지 함수를 받아야 하는데, 첫 번째 함수(&lt;/span&gt;resolve&lt;span style=&quot;background-color: #ffffff; color: #1b1b1b; text-align: start;&quot;&gt;)는 비동기 작업을 성공적으로 완료해 결과를 값으로 반환할 때 호출해야 하고, 두 번째 함수(&lt;/span&gt;reject&lt;span style=&quot;background-color: #ffffff; color: #1b1b1b; text-align: start;&quot;&gt;)는 작업이 실패하여 오류의 원인을 반환할 때 호출하면 됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #1b1b1b; text-align: start;&quot;&gt;두 번째 함수는 주로 오류 객체를 받습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724302078799&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let promise = new Promise(function(resolve, reject) {
  // 비동기 작업을 실행하는 코드가 여기에 들어갑니다.

  if (/* 작업이 성공하면 */) {
    resolve('성공 결과'); // 성공 시 호출
  } else {
    reject('실패 이유'); // 실패 시 호출
  }
});&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;cf. promise instance&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;new Promise()&lt;span&gt;를 호출하여 생성된&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;개별적인 프로미스 객체&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;(위 예제에서 promise라는 변수에 할당된 값을 프로미스 인스턴스라고 함)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;인스턴스는 특정 비동기 작업을 추적하며, 그 작업이 성공했는지, 실패했는지, 또는 아직 진행 중인지 상태를 관리합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;b&gt;executor 함수&lt;/b&gt;: &lt;span&gt;new Promise()&lt;/span&gt;는 두 개의 매개변수, &lt;span&gt;resolve&lt;/span&gt;와 &lt;span&gt;reject&lt;/span&gt;를 받는 콜백 함수를 인자로 받습니다. 이 콜백 함수는 프로미스가 생성될 때 자동으로 실행됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;resolve&lt;/b&gt;: 비동기 작업이 성공했을 때 호출합니다. 이때 인자로 전달된 값은 프로미스의 결과로 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- &lt;b&gt;reject&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;/p&gt;
&lt;pre id=&quot;code_1724302134035&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let promise = new Promise((resolve, reject) =&amp;gt; {
  setTimeout(() =&amp;gt; {
    resolve(&quot;1초 후에 작업이 완료되었습니다.&quot;);
  }, 1000);
});

promise.then((result) =&amp;gt; {
  console.log(result); // &quot;1초 후에 작업이 완료되었습니다.&quot; 출력
}).catch((error) =&amp;gt; {
  console.error(error); // 만약 reject()가 호출되었다면 이 블록이 실행됩니다.
});&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;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;&lt;a href=&quot;https://www.freecodecamp.org/korean/news/javascript-promise-tutorial-how-to-resolve-or-reject-promises-in-js/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.freecodecamp.org/korean/news/javascript-promise-tutorial-how-to-resolve-or-reject-promises-in-js/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724301431518&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;자바스크립트 프로미스 튜토리얼 - 자바스크립트의 프로미스를 이행하거나 거부하는 방법&quot; data-og-description=&quot;프로미스는 자바스크립트에서 비동기 처리를 위한 중요한 요소이지만 프로미스를 이해하고 적용하는 것은 그렇게 쉽지 않다고 생각하셨을 수도 있습니다. 하지만 절 따라오세요, 여러분은 혼&quot; data-og-host=&quot;www.freecodecamp.org&quot; data-og-source-url=&quot;https://www.freecodecamp.org/korean/news/javascript-promise-tutorial-how-to-resolve-or-reject-promises-in-js/&quot; data-og-url=&quot;https://www.freecodecamp.org/korean/news/javascript-promise-tutorial-how-to-resolve-or-reject-promises-in-js/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/3t5lz/hyWSpIpTxN/PCo4VSlrNHD9lMxJM7k28k/img.png?width=900&amp;amp;height=500&amp;amp;face=0_0_900_500,https://scrap.kakaocdn.net/dn/bZmyHp/hyWSadrNfx/XcJS4fTH2u6IejNY51Ec1k/img.png?width=900&amp;amp;height=500&amp;amp;face=0_0_900_500,https://scrap.kakaocdn.net/dn/odWfk/hyWSoQiJPQ/4yc5pe1PYixHqr79v3H6Mk/img.png?width=1076&amp;amp;height=595&amp;amp;face=0_0_1076_595&quot;&gt;&lt;a href=&quot;https://www.freecodecamp.org/korean/news/javascript-promise-tutorial-how-to-resolve-or-reject-promises-in-js/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.freecodecamp.org/korean/news/javascript-promise-tutorial-how-to-resolve-or-reject-promises-in-js/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/3t5lz/hyWSpIpTxN/PCo4VSlrNHD9lMxJM7k28k/img.png?width=900&amp;amp;height=500&amp;amp;face=0_0_900_500,https://scrap.kakaocdn.net/dn/bZmyHp/hyWSadrNfx/XcJS4fTH2u6IejNY51Ec1k/img.png?width=900&amp;amp;height=500&amp;amp;face=0_0_900_500,https://scrap.kakaocdn.net/dn/odWfk/hyWSoQiJPQ/4yc5pe1PYixHqr79v3H6Mk/img.png?width=1076&amp;amp;height=595&amp;amp;face=0_0_1076_595');&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;자바스크립트 프로미스 튜토리얼 - 자바스크립트의 프로미스를 이행하거나 거부하는 방법&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;프로미스는 자바스크립트에서 비동기 처리를 위한 중요한 요소이지만 프로미스를 이해하고 적용하는 것은 그렇게 쉽지 않다고 생각하셨을 수도 있습니다. 하지만 절 따라오세요, 여러분은 혼&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.freecodecamp.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%B2%98%EB%A6%AC-Promise#%EC%BD%9C%EB%B0%B1_%ED%95%A8%EC%88%98%EC%9D%98_%EB%B9%84%EB%8F%99%EA%B8%B0_%EC%B2%98%EB%A6%AC_%EB%AC%B8%EB%B2%95&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%B2%98%EB%A6%AC-Promise#%EC%BD%9C%EB%B0%B1_%ED%95%A8%EC%88%98%EC%9D%98_%EB%B9%84%EB%8F%99%EA%B8%B0_%EC%B2%98%EB%A6%AC_%EB%AC%B8%EB%B2%95&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724301801428&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;  자바스크립트 Promise 개념 &amp;amp; 문법 정복하기&quot; data-og-description=&quot;콜백 지옥을 탈출하는 새로운 문법 자바스크립트에서 '비동기 처리' 란 현재 실행중인 작업과는 별도로 다른 작업을 수행하는 것을 말한다. 예를 들어 서버에서 데이터를 받아오는 작업은 시간&quot; data-og-host=&quot;inpa.tistory.com&quot; data-og-source-url=&quot;https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%B2%98%EB%A6%AC-Promise#%EC%BD%9C%EB%B0%B1_%ED%95%A8%EC%88%98%EC%9D%98_%EB%B9%84%EB%8F%99%EA%B8%B0_%EC%B2%98%EB%A6%AC_%EB%AC%B8%EB%B2%95&quot; data-og-url=&quot;https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%B2%98%EB%A6%AC-Promise&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cN5Jhl/hyWSjnS8pK/VsOarguZZ68tu7wkSv5br1/img.jpg?width=800&amp;amp;height=452&amp;amp;face=0_0_800_452,https://scrap.kakaocdn.net/dn/bd50ud/hyWSfMyMRM/byKiaPFuE7M0tfAWuCzCo0/img.jpg?width=800&amp;amp;height=452&amp;amp;face=0_0_800_452,https://scrap.kakaocdn.net/dn/B6HOW/hyWSgSfnt8/hd9JsNdogNqzFSd5Uff3a1/img.png?width=801&amp;amp;height=297&amp;amp;face=0_0_801_297&quot;&gt;&lt;a href=&quot;https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%B2%98%EB%A6%AC-Promise#%EC%BD%9C%EB%B0%B1_%ED%95%A8%EC%88%98%EC%9D%98_%EB%B9%84%EB%8F%99%EA%B8%B0_%EC%B2%98%EB%A6%AC_%EB%AC%B8%EB%B2%95&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%B2%98%EB%A6%AC-Promise#%EC%BD%9C%EB%B0%B1_%ED%95%A8%EC%88%98%EC%9D%98_%EB%B9%84%EB%8F%99%EA%B8%B0_%EC%B2%98%EB%A6%AC_%EB%AC%B8%EB%B2%95&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cN5Jhl/hyWSjnS8pK/VsOarguZZ68tu7wkSv5br1/img.jpg?width=800&amp;amp;height=452&amp;amp;face=0_0_800_452,https://scrap.kakaocdn.net/dn/bd50ud/hyWSfMyMRM/byKiaPFuE7M0tfAWuCzCo0/img.jpg?width=800&amp;amp;height=452&amp;amp;face=0_0_800_452,https://scrap.kakaocdn.net/dn/B6HOW/hyWSgSfnt8/hd9JsNdogNqzFSd5Uff3a1/img.png?width=801&amp;amp;height=297&amp;amp;face=0_0_801_297');&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;  자바스크립트 Promise 개념 &amp;amp; 문법 정복하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;콜백 지옥을 탈출하는 새로운 문법 자바스크립트에서 '비동기 처리' 란 현재 실행중인 작업과는 별도로 다른 작업을 수행하는 것을 말한다. 예를 들어 서버에서 데이터를 받아오는 작업은 시간&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;inpa.tistory.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;</description>
      <category>Live Class/Beginner</category>
      <author>dearsuhyun</author>
      <guid isPermaLink="true">https://diveintodevworld.tistory.com/73</guid>
      <comments>https://diveintodevworld.tistory.com/73#entry73comment</comments>
      <pubDate>Thu, 22 Aug 2024 13:53:43 +0900</pubDate>
    </item>
    <item>
      <title>JS | 직렬화와 역직렬화, JSON.stringify()와 JSON.parse()</title>
      <link>https://diveintodevworld.tistory.com/72</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;709&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwqEEG/btsJaBJRmEW/sorKdx2KI55fKGFZDJKCg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwqEEG/btsJaBJRmEW/sorKdx2KI55fKGFZDJKCg1/img.png&quot; data-alt=&quot;출처 : https://velog.io/@leesfact/%EB%8D%B0%EC%9D%B4%ED%84%B0%EA%B5%90%ED%99%98-%ED%98%95%EC%8B%9D-JSON%EA%B3%BC-%EC%A7%81%EB%A0%AC%ED%99%94%EC%99%80-%EC%97%AD%EC%A7%81%EB%A0%AC%ED%99%94&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwqEEG/btsJaBJRmEW/sorKdx2KI55fKGFZDJKCg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwqEEG%2FbtsJaBJRmEW%2FsorKdx2KI55fKGFZDJKCg1%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;1280&quot; height=&quot;709&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;709&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://velog.io/@leesfact/%EB%8D%B0%EC%9D%B4%ED%84%B0%EA%B5%90%ED%99%98-%ED%98%95%EC%8B%9D-JSON%EA%B3%BC-%EC%A7%81%EB%A0%AC%ED%99%94%EC%99%80-%EC%97%AD%EC%A7%81%EB%A0%AC%ED%99%94&lt;/figcaption&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;&lt;b&gt;1. 직렬화(Serialization)란?&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;직렬화(Serialization)는 &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;2. JSON.stringify()란?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;JSON.stringify()&lt;/span&gt;는 자바스크립트에서 &lt;b&gt;객체를 JSON 형식의 문자열로 직렬화&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;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;JSON&lt;/b&gt;(JavaScript Object Notation)은 데이터 교환 형식으로 널리 사용되는 텍스트 기반의 형식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;JSON.stringify()&lt;/span&gt;는 자바스크립트 객체를 JSON 문자열로 변환해 줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1724251299745&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const user = {
  name: &quot;Alice&quot;,
  age: 25,
  isStudent: true
};

const jsonString = JSON.stringify(user);
console.log(jsonString); // {&quot;name&quot;:&quot;Alice&quot;,&quot;age&quot;:25,&quot;isStudent&quot;:true}&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;3. 역직렬화(Deserialization)란?&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;역직렬화(Deserialization)는 &lt;b&gt;직렬화된 데이터를 다시 원래의 객체나 데이터 구조로 복원하는 과정&lt;/b&gt;입니다. 직렬화된 문자열을 받아서, 다시 자바스크립트 객체로 변환할 때 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직렬화된 데이터를 다시 &lt;b&gt;컴퓨터가 이해할 수 있는 복잡한 데이터(객체)로 되돌리는 과정&lt;/b&gt;이라고 생각하면 됩니다.&lt;span&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;&lt;b&gt;4. JSON.parse()와 역직렬화&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;span&gt;JSON.parse()&lt;/span&gt;는 JSON 문자열을 받아서 &lt;b&gt;자바스크립트 객체로 역직렬화&lt;/b&gt;해 줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1724251356378&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const jsonString = '{&quot;name&quot;:&quot;Alice&quot;,&quot;age&quot;:25,&quot;isStudent&quot;:true}';
const user = JSON.parse(jsonString);

console.log(user.name); // &quot;Alice&quot;
console.log(user.age); // 25&lt;/code&gt;&lt;/pre&gt;</description>
      <category>TIL</category>
      <category>json.parse()</category>
      <category>json.stringify()</category>
      <category>역직렬화</category>
      <category>직렬화</category>
      <author>dearsuhyun</author>
      <guid isPermaLink="true">https://diveintodevworld.tistory.com/72</guid>
      <comments>https://diveintodevworld.tistory.com/72#entry72comment</comments>
      <pubDate>Wed, 21 Aug 2024 23:43:20 +0900</pubDate>
    </item>
    <item>
      <title>자바스크립트의 실행 컨텍스트(Execution Context)와 this 키워드, ES6 모듈 특징</title>
      <link>https://diveintodevworld.tistory.com/71</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f89009;&quot;&gt;실행 컨텍스트 (Execution Context) - Record와 Outer를 중심으로&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c1bef9;&quot;&gt;record/outer는 실행컨텍스트와 크게 관련 없음&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c1bef9;&quot;&gt;lexical 은 실행 컨텍스트보다 상위개념이라고 볼 수 있음&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c1bef9;&quot;&gt;설명이 어렵게 되어 있음 - 전반적으로 더 읽기 좋게 풀어서 설명해보기 (어렵게 썼는데 틀리면 ? 신뢰도 하락)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c1bef9;&quot;&gt;독자 입장에서 글의 흐름이 뭉쳐있다, 쉽게 풀고 더 흐름을 자연스럽게 고쳐보기&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;실행 컨텍스트는 실행 가능한 코드에 제공할 환경(코드 실행에 영향을 주는 조건이나 상태) 정보를 모아놓은 객체입니다.&lt;br /&gt;해당 객체에는 변수 객체, 스코프 체인, this 정보가 담겨있습니다.&lt;br /&gt;자동으로 전역 컨텍스트가 생성된 후 함수 호출시마다 함수 컨텍스트가 생성되고, 컨텍스트 생성이 완료된 후에 함수가 실행됩니다. &lt;br /&gt;함수 실행 중에 사용 되는 변수들을 변수 객체 안에서 값을 찾고 값이 존재하지 않는다면 Lexical 환경의 outerEnvironmentReference를 통해 Scope 체인을 따라 올라가면서 탐색합니다. 함수 실행이 마무리가 되면 해당 컨텍스트는 사라지고, 페이지가 종료되면 전역 컨텍스트도 사라집니다.&lt;/blockquote&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;span&gt;1.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;전역 실행 컨텍스트 (Global Execution Context)&lt;/b&gt;:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;자바스크립트 프로그램이 시작될 때 생성됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;전역 컨텍스트에서 &lt;span&gt;this&lt;/span&gt;는 전역 객체(&lt;span&gt;window&lt;/span&gt; 객체 또는 Node.js 환경에서는 &lt;span&gt;global&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&gt;&lt;span&gt; &lt;/span&gt;2.&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;b&gt;함수 실행 컨텍스트 (Function Execution Context)&lt;/b&gt;:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;함수가 호출될 때마다 새로운 실행 컨텍스트가 생성됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;함수 내부에서의 &lt;span&gt;this&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;3가지 주요 구성 요소&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;1) &lt;/span&gt;&lt;/span&gt;&lt;b&gt;변수 객체(Variable Object)&lt;/b&gt;: 현재 실행 중인 함수의 매개변수, 변수, 함수 선언 등을 포함합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;2)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;스코프 체인(Scope Chain)&lt;/b&gt;: 현재 컨텍스트에서 접근할 수 있는 변수들을 결정합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;3)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;this&lt;/b&gt;&lt;/span&gt;&lt;b&gt; 바인딩&lt;/b&gt;: &lt;span&gt;this&lt;/span&gt;가 가리키는 객체를 결정합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724221182141&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var x = 'xxx';

function foo () {
  var y = 'yyy';

  function bar () {
    var z = 'zzz';
    console.log(x + y + z);
  }
  
  bar();
}

foo();&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;gt; 콜스택에 전역 실행 컨텍스트를 담음 --&amp;gt; 전역에서 함수 foo를 호출하면 --&amp;gt; foo의 실행 컨텍스트를 만들어서 콜스택에 담음 (콜스택에서는 가장 최근에 추가된 콜스택만 활성화됨) -&amp;gt; 함수 bar를 호출하면 --&amp;gt; bar의 실행 컨텍스트를 만들어서 콜 스택에 담음 --&amp;gt; 가장 최근에 추가된 bar 부터 실행 --&amp;gt; bar 콜스택에서 삭제 --&amp;gt; foo 실행 --&amp;gt; foo 콜스택에서 삭제 --&amp;gt; 전역 실행&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;439&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d66BIN/btsJbKegwjX/LckrDDksWvIvln5HWEIWeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d66BIN/btsJbKegwjX/LckrDDksWvIvln5HWEIWeK/img.png&quot; data-alt=&quot;출처: https://velog.io/@ggong/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-execution-context&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d66BIN/btsJbKegwjX/LckrDDksWvIvln5HWEIWeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd66BIN%2FbtsJbKegwjX%2FLckrDDksWvIvln5HWEIWeK%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;1280&quot; height=&quot;439&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;439&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처: https://velog.io/@ggong/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EC%9D%98-%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-execution-context&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Record로 호이스팅 이해하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c1bef9;&quot;&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;환경 레코드(Environment Record)란?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;환경 레코드(Environment Record)는 자바스크립트에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;변수와 함수가 어디에 저장되고 어떻게 관리되는지&lt;/b&gt;를 담당하는 구조입니다. 쉽게 말하면, 코드에서 사용하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;변수와 함수들을 저장하는 &amp;ldquo;메모장&amp;rdquo;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;같은 역할을 한다고 생각하면 됩니다.&lt;span style=&quot;background-color: #c1bef9;&quot;&gt; --&amp;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;&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;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;변수와 함수의 저장소&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;예를 들어,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;let x = 5;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;라는 코드를 실행하면, 환경 레코드에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;라는 이름과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;5&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;/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;예를 들어,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;function sayHello() {}&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;라는 코드를 실행하면, 환경 레코드는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;sayHello&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;/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;예를 들어,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;console.log(x);&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;라는 코드가 실행될 때, 환경 레코드는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;가 어떤 값(이 경우&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;)을 가지고 있는지 알려줍니다.&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;/h4&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;자바스크립트가 코드를 실행할 때, 먼저 실행 컨텍스트를 생성합니다. 그리고 이 실행 컨텍스트 내에서 환경 레코드가 만들어집니다. 이 과정은 두 단계로 이루어집니다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;1단계: 생성 단계&lt;/b&gt; - 변수와 함수의 선언이 환경 레코드에 기록됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;2단계: 실행 단계&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;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;호이스팅은 &lt;b&gt;생성 단계&lt;/b&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) var 키워드와 변수 호이스팅&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;var&lt;/span&gt;로 선언된 변수는 코드의 최상위로 호이스팅되며, &lt;b&gt;초기화와 선언이 동시에 이루어집니다&lt;/b&gt;. 하지만 중요한 점은, &lt;b&gt;호이스팅될 때 변수가 &lt;/b&gt;&lt;span&gt;&lt;b&gt;undefined&lt;/b&gt;&lt;/span&gt;&lt;b&gt;로 초기화&lt;/b&gt;된다는 것입니다. 즉, 변수를 실제로 할당하기 전에 접근해도 오류가 발생하지 않고 &lt;span&gt;undefined&lt;/span&gt;를 반환합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1724228124470&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log(a); // undefined
var a = 10;
console.log(a); // 10&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;실행 과정&lt;br /&gt;1. 생성 단계:&lt;br /&gt;자바스크립트 엔진은 var a를 발견하고, 이를 환경 레코드에 undefined 값과 함께 등록합니다.&lt;br /&gt;&lt;br /&gt;2. 실행 단계:&lt;br /&gt;console.log(a);를 실행할 때, a는 이미 환경 레코드에 존재하며 undefined로 초기화되어 있습니다. 따라서 undefined가 출력됩니다.&lt;br /&gt;이후 a = 10;이 실행되면, a의 값이 10으로 바뀝니다.&lt;/blockquote&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) &lt;/b&gt;&lt;b&gt;let과 const 키워드와 변수 호이스팅&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;let&lt;/span&gt;과 &lt;span&gt;const&lt;/span&gt;로 선언된 변수도 &lt;b&gt;호이스팅&lt;/b&gt;됩니다. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;하지만 중요한 차이점은, 이들 변수는 호이스팅되지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;초기화되지 않습니다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c1bef9;&quot;&gt;호이스팅 (끌어올려지는 것 + 초기화되는것) --&amp;gt; 자바스크립트의 개발용어로 이해하면&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c1bef9;&quot;&gt;let, const는 호이스팅된다고 말할 수 없음 !&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;ldquo;Temporal Dead Zone (TDZ)&amp;rdquo;**에 놓이게 됩니다. 이 때문에, 선언되기 전에 해당 변수에 접근하면 &lt;span&gt;ReferenceError&lt;/span&gt;가 발생합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1724232075188&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 20;
console.log(b); // 20

console.log(c); // ReferenceError: Cannot access 'c' before initialization
const c = 30;
console.log(c); // 30&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;실행 과정&lt;br /&gt;1. 생성 단계:&lt;br /&gt;자바스크립트 엔진은 let과 const로 선언된 변수들을 환경 레코드에 등록하지만, 초기화는 하지 않습니다. 이때 이 변수들은 TDZ에 놓여 있습니다.&lt;br /&gt;TDZ란 변수가 초기화되기 전까지 해당 변수를 참조할 수 없는 기간을 의미합니다.&lt;br /&gt;&lt;br /&gt;2. 실행 단계:&lt;br /&gt;console.log(b); 또는 console.log(c);가 실행될 때, 변수 b와 c는 TDZ에 있기 때문에 ReferenceError가 발생합니다.&lt;br /&gt;이후 변수들이 선언되면서 TDZ가 종료되고, 변수들이 초기화됩니다. b = 20;, c = 30;이 실행되면, 이제 b와 c는 정상적으로 값을 가집니다.&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. Outer로 스코프체이닝 이해하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 스코프 체이닝(Scope Chaining)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스코프 체이닝은 &lt;b&gt;현재 스코프에서 변수를 찾지 못하면, 외부(상위) 스코프에서 계속해서 변수를 찾는 과정&lt;/b&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;2. Lexical Environment (렉시컬 환경)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Lexical Environment&lt;/b&gt;는 자바스크립트에서 &lt;b&gt;변수와 함수 선언을 기록하고 관리하는 구조&lt;/b&gt;를 말합니다. 쉽게 말하면, &lt;b&gt;변수와 함수들이 어디에 저장되고, 어떻게 접근되는지를 결정하는 &amp;ldquo;상자&amp;rdquo;&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;3. Outer Environment Reference&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Outer Environment Reference&lt;/b&gt;는 현재 함수(또는 블록)가 자신을 둘러싼 외부 스코프를 참조할 수 있도록 만들어진 &lt;b&gt;연결 고리&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(현재 &lt;b&gt;Lexical Environment&lt;/b&gt;에서 &lt;b&gt;바깥쪽(외부)의 Lexical Environment&lt;/b&gt;를 참조할 수 있는 링크)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 현재 코드가 바깥에서 선언된 변수나 함수에 접근할 수 있도록 해주는 &amp;ldquo;다리&amp;rdquo;라고 생각하면 됩니다.&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;4. Lexical Environment와 Outer Environment Reference의 관계&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Lexical Environment&lt;/b&gt;는 각 실행 컨텍스트(예: 전역, 함수)에서 사용되는 변수와 함수들을 저장하고 관리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 &lt;b&gt;Lexical Environment&lt;/b&gt;는 &lt;b&gt;Outer Environment Reference&lt;/b&gt;를 통해 바로 바깥쪽의 Lexical Environment와 연결됩니다. 이 연결을 통해 자바스크립트는 변수를 현재 스코프에서 찾지 못하면, 바깥쪽 스코프에서 찾을 수 있게 됩니다.&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;&lt;b&gt;Lexical Environment&lt;/b&gt;들은 서로 &lt;b&gt;Outer Environment Reference&lt;/b&gt;로 연결되어 &lt;b&gt;스코프 체인&lt;/b&gt;을 형성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트는 변수를 사용할 때, 먼저 현재 &lt;b&gt;Lexical Environment&lt;/b&gt;에서 찾고, 없으면 &lt;b&gt;Outer Environment Reference&lt;/b&gt;를 따라 바깥쪽 스코프에서 변수를 찾습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;쉽게 비유&lt;br /&gt;Lexical Environment: 각 방 안에 있는 &amp;ldquo;변수와 함수들이 기록된 상자&amp;rdquo;&lt;br /&gt;Outer Environment Reference: 각 방을 연결하는 &amp;ldquo;복도&amp;rdquo;&lt;br /&gt;이 복도를 따라가면서 다른 방의 상자(즉, 외부 스코프에 있는 변수들)에 접근할 수 있습니다.&lt;/blockquote&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;3. 스코프 체이닝과 Outer Environment Reference의 연결&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724232788967&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let globalVar = &quot;I'm a global variable&quot;;

function outerFunction() {
  let outerVar = &quot;I'm in outerFunction&quot;;

  function innerFunction() {
    let innerVar = &quot;I'm in innerFunction&quot;;

    console.log(globalVar); // 스코프 체인을 따라 전역 스코프에서 찾음
    console.log(outerVar);  // 스코프 체인을 따라 outerFunction 스코프에서 찾음
    console.log(innerVar);  // 현재 스코프에서 찾음
  }

  innerFunction();
}

outerFunction();&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;스코프 체이닝의 동작:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;innerFunction&lt;span&gt; 내부에서 &lt;/span&gt;globalVar&lt;span&gt;, &lt;/span&gt;outerVar&lt;span&gt;, &lt;/span&gt;innerVar&lt;span&gt;를 출력하려고 할 때:&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;globalVar&lt;/span&gt;&lt;/b&gt;는 &lt;span&gt;innerFunction&lt;/span&gt; 스코프에서 찾을 수 없으므로, &lt;b&gt;Outer Environment Reference&lt;/b&gt;를 통해 상위 스코프인 &lt;span&gt;outerFunction&lt;/span&gt;으로 이동합니다. 거기서도 찾을 수 없으므로 다시 &lt;b&gt;전역 스코프&lt;/b&gt;로 이동해 찾습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;outerVar&lt;/span&gt;&lt;/b&gt;는 &lt;span&gt;innerFunction&lt;/span&gt; 스코프에 없지만, 바로 외부 스코프인 &lt;span&gt;outerFunction&lt;/span&gt; 스코프에 존재합니다. 그래서 여기서 변수를 찾습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;innerVar&lt;/span&gt;&lt;/b&gt;는 &lt;span&gt;innerFunction&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f89009;&quot;&gt;this 키워드란?&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;this&lt;/span&gt;는 자바스크립트에서 현재 실행 중인 코드의 &lt;b&gt;실행 컨텍스트&lt;/b&gt;에 따라 참조하는 객체를 의미합니다. &lt;span&gt;this&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&gt;&lt;span&gt; &lt;/span&gt;1.&lt;span&gt; &lt;span&gt; &lt;b&gt;전역 컨텍스트에서의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;span&gt;&lt;b&gt;this&lt;/b&gt;&lt;/span&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;전역 컨텍스트에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;this&lt;/span&gt;는 전역 객체를 참조합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;브라우저 환경에서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;this === window&lt;/span&gt;가 참입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1724228431214&quot; class=&quot;javascript&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;console.log(this); // window 객체를 출력 (브라우저에서)&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;2. &lt;span&gt;&lt;span&gt;&lt;b&gt;일반함수에서의 this&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;호출 위치에서 this가 정의 !&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724228442628&quot; class=&quot;javascript&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const person = {
  name: &quot;Alice&quot;,
  sayHello: function() {
    console.log(&quot;Hello, &quot; + this.name);
  }
};

person.sayHello(); // &quot;Hello, Alice&quot;&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;/p&gt;
&lt;pre id=&quot;code_1724811062133&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// numbers1, numbers2는 같은 배열 데이터 생성 방식
const numbers1 = [5, 6, 7, 8] // 리터럴 방식
const numbers2 = new Array(5, 6, 7, 8) // 생성자 방식

Array.prototype.hello = function() {
  return this.join(' / ')
}
// [1, 2, 3].map()
// Array.prototype.map = function() {}
// join() 메서드는 배열의 모든 요소를 연결해 하나의 문자열로 만듦

// 배열 데이터에서 커스텀 메서드 사용
const res = numbers1.hello()
console.log(res) // 5 / 6 / 7 / 8&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;2) &lt;b&gt;객체의 메서드에서의 &lt;/b&gt;&lt;span&gt;&lt;b&gt;this&lt;/b&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;객체의 메서드에서 &lt;span&gt;this&lt;/span&gt;는 그 메서드가 속한 객체를 참조합니다. &lt;span style=&quot;background-color: #c1bef9;&quot;&gt;--&amp;gt; 알 수 없다&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;밑의 예제를 보면 객체의 메서드에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;this는 그 메서드가 속한 객체를 참조합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c1bef9;&quot;&gt;--&amp;gt; 참조한다는 것을 확신할 수 없음&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c1bef9;&quot;&gt;--&amp;gt; 이 예제를 설명할 때는 맞지만, 일반화된 this 키워드 설명할 때에는 틀렸음&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724221381606&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const obj = {
  name: 'Alice',
  greet() {
    console.log(this.name); // this는 obj를 참조
  }
};
obj.greet(); // &quot;Alice&quot; 출력&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;3) &lt;b&gt;생성자 함수에서의 &lt;/b&gt;&lt;span&gt;&lt;b&gt;this&lt;/b&gt;&lt;/span&gt;:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #c1bef9;&quot;&gt;&amp;bull; 함수가 new 키워드와 함께 호출될 때(생성자 함수 호출),&amp;nbsp;&lt;b&gt;새로 생성된 객체(인스턴스)&lt;/b&gt;를 가리킵니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c1bef9;&quot;&gt;this는 그 인스턴스를 참조합니다.&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;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;생성자 함수의 역할은 &lt;span style=&quot;background-color: #c1bef9;&quot;&gt;새 인스턴스&lt;/span&gt;를 생성하고,&lt;s&gt; 이 새 객체에 속성을 추가하는 것입니다.&lt;/s&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;&lt;span style=&quot;background-color: #c1bef9;&quot;&gt;객체(데이터) vs 개체(물체, 모든 데이터)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c1bef9;&quot;&gt;Object&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c1bef9;&quot;&gt;object&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #c1bef9;&quot;&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;&amp;bull;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt; 일반함수로 만들어진&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;생성자 함수에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;this는 새로 생성된 &lt;span style=&quot;background-color: #c1bef9;&quot;&gt;인스턴스&lt;/span&gt;를 참조할 수 있다 !!!&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724221400923&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function Person(name) {
  this.name = name;
}
const person1 = new Person('Bob');
console.log(person1.name); // &quot;Bob&quot; 출력&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;/p&gt;
&lt;pre id=&quot;code_1724811143849&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// numbers1, numbers2는 같은 배열 데이터 생성 방식
const numbers1 = [5, 6, 7, 8] // 리터럴 방식
const numbers2 = new Array(5, 6, 7, 8) // 생성자 방식, numbers2는 인스턴스

Array.prototype.hello = function() {
  return this.join(' / ')
}
// [1, 2, 3].map()
// Array.prototype.map = function() {}
// join() 메서드는 배열의 모든 요소를 연결해 하나의 문자열로 만듦

// 배열 데이터에서 커스텀 메서드 사용
const res = numbers2.hello()
console.log(res) // 5 / 6 / 7 / 8&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;2.&lt;b&gt; 명시적인 this 바인딩 (call, apply, bind)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;span&gt;call&lt;/span&gt;, &lt;span&gt;apply&lt;/span&gt;, &lt;span&gt;bind&lt;/span&gt; 메서드를 사용하여 함수 호출 시 &lt;span&gt;this&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;1) call 메서드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;call&lt;/span&gt;은 함수를 &lt;b&gt;즉시 실행하면서&lt;/b&gt; &lt;span&gt;this&lt;/span&gt;를 내가 원하는 값으로 설정해주는 역할을 합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 sayHello함수는 this가 가리키고 있는 것이 무엇인지 알지 못하지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;call 메서드를 사용함으로써 이 this가 person을 가리키고 있다고 설정해 주는 것 !&lt;/p&gt;
&lt;pre id=&quot;code_1724223516007&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function sayHello(greeting) {
  console.log(greeting + &quot;, my name is &quot; + this.name);
}

const person = { name: &quot;Alice&quot; };

sayHello.call(person, &quot;Hi&quot;);
// &quot;Hi, my name is Alice&quot;&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;2) apply 메서드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;call과 거의 일치하지만, 함수에 전달하는 인수들을 배열로 전달해줍니다.&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&gt;apply&lt;/span&gt;도 &lt;span&gt;call&lt;/span&gt;처럼 &lt;span&gt;this&lt;/span&gt;를 &lt;span&gt;person&lt;/span&gt;으로 설정해주지만, 다른 점은 &lt;span&gt;apply&lt;/span&gt;에서는 인수들을 배열로 줘야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;--&amp;gt; &lt;span&gt;sayHello&lt;/span&gt; 함수에서 &lt;span&gt;greeting&lt;/span&gt;과 &lt;span&gt;punctuation&lt;/span&gt;을 배열로 넘겨주면 되는 것 !&lt;/p&gt;
&lt;pre id=&quot;code_1724223635924&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function sayHello(greeting, punctuation) {
  console.log(greeting + &quot;, my name is &quot; + this.name + punctuation);
}

const person = { name: &quot;Bob&quot; };

sayHello.apply(person, [&quot;Hello&quot;, &quot;!&quot;]);
// &quot;Hello, my name is Bob!&quot;&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) bind 메서드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;bind는 &lt;span&gt;call&lt;/span&gt;이나 &lt;span&gt;apply&lt;/span&gt;와 달리 &lt;b&gt;즉시 함수를 호출하지 않고&lt;/b&gt;, &lt;span&gt;this&lt;/span&gt;가 고정된 &lt;b&gt;새로운 함수&lt;/b&gt;를 반환합니다. 이후 이 새로운 함수를 호출할 때마다 &lt;span&gt;this&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&gt;bind&lt;/span&gt;는 &amp;ldquo;나중에 쓸 때 이 함수에서 &lt;span&gt;this&lt;/span&gt;는 무조건 &lt;span&gt;person&lt;/span&gt;이야!&amp;rdquo; 라고 말해주는 역할을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 &lt;span&gt;boundSayHello&lt;/span&gt;라는 새로운 함수가 만들어지고, 이 함수는 &lt;span&gt;this&lt;/span&gt;가 항상 &lt;span&gt;person&lt;/span&gt;이 되는 것 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;--&amp;gt; 언제 &lt;/span&gt;boundSayHello&lt;span&gt;를 호출하든, &lt;/span&gt;this&lt;span&gt;는 &lt;/span&gt;person&lt;span&gt;이고, &lt;/span&gt;name&lt;span&gt;은 &lt;/span&gt;&quot;Charlie&quot;가 된다고 해석합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1724223759604&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function sayHello(greeting) {
  console.log(greeting + &quot;, my name is &quot; + this.name);
}

const person = { name: &quot;Charlie&quot; };

const boundSayHello = sayHello.bind(person);

boundSayHello(&quot;Hi&quot;);
// &quot;Hi, my name is Charlie&quot;&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;3.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;화살표함수에서의 this&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;선언 위치에서 this가 정의 !&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화살표 함수에서는 &lt;span&gt;this&lt;/span&gt;가 &lt;b&gt;항상 함수를 감싸고 있는 외부 환경&lt;/b&gt;에 의해 결정됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 화살표 함수는 자기만의 &lt;span&gt;this&lt;/span&gt;를 가지지 않고, 자신이 속한 &lt;b&gt;바깥 함수나 전역 컨텍스트&lt;/b&gt;의 &lt;span&gt;this&lt;/span&gt;를 그대로 사용 !&lt;/p&gt;
&lt;pre id=&quot;code_1724224455046&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;function abc() {
  this.a = 10;
  const obj2 = {
    a: 1,
    b: 2,
    getB() =&amp;gt; {
      console.log(this.a); // 10
    }
  }
}

const obj3 = {
  a: 1,
  b: 2,
  getC() =&amp;gt; {
    console.log(this.a); // undefined&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724224548861&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const person = {
  name: &quot;Charlie&quot;,
  sayHello: function() {
    const innerFunction = () =&amp;gt; {
      console.log(&quot;Hello from innerFunction, &quot; + this.name);
    };
    innerFunction();
  }
};

person.sayHello(); // &quot;Hello from innerFunction, Charlie&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&amp;bull; call: 함수를 호출할 때 this를 특정 객체로 설정하며, 추가적인 인수들을 개별적으로 전달합니다.&lt;br /&gt;함수.call(특정객체, 인수1, 인수2, ...)&lt;br /&gt;즉시 호출됨.&lt;br /&gt;&lt;br /&gt;&amp;bull; apply: call과 거의 동일하지만, 인수들을 배열 형태로 전달합니다.&lt;br /&gt;함수.apply(특정객체, [인수1, 인수2, ...])&lt;br /&gt;즉시 호출됨.&lt;br /&gt;&lt;br /&gt;&amp;bull; bind: this가 고정된 새로운 함수를 반환합니다. 이 함수는 이후 호출할 때마다 this가 고정된 객체를 참조합니다.&lt;br /&gt;const 새로운함수 = 함수.bind(특정객체)&lt;br /&gt;즉시 호출되지 않고, 반환된 함수를 나중에 호출.&lt;/blockquote&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;cf. 엄격모드와 비엄격모드&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트에서 &lt;b&gt;모듈 구조&lt;/b&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;1. 모듈 구조가 아닌 경우 (전통적인 스크립트 방식)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724231468098&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// traditional.js - 전통적인 스크립트 방식

x = 10; // 전역 변수로 암묵적 선언 (비엄격 모드에서는 허용됨)
console.log(x); // 10

function nonStrictFunction() {
    y = 20; // 암묵적 전역 변수 선언 (비엄격 모드에서는 허용됨)
    console.log(y); // 20
}

nonStrictFunction();

console.log(this); // 전역 객체 (window, Node.js에서는 global)&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;특징:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;엄격 모드가 기본적으로 비활성화&lt;/b&gt;: 전통적인 스크립트에서는 엄격 모드가 기본적으로 비활성화되어 있습니다. 따라서 &lt;span&gt;&quot;use strict&quot;;&lt;/span&gt;를 명시적으로 선언해야 엄격 모드가 적용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;암묵적 전역 변수 생성 허용&lt;/b&gt;: &lt;span&gt;x = 10;&lt;/span&gt;과 같은 암묵적 전역 변수 선언이 허용됩니다. 선언되지 않은 변수를 할당할 경우 자동으로 전역 변수가 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;전역 스코프 사용&lt;/b&gt;: 모든 코드는 전역 스코프에서 실행되며, &lt;span&gt;this&lt;/span&gt;는 전역 객체(&lt;span&gt;window&lt;/span&gt; 또는 &lt;span&gt;global&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;2. 모듈 구조 (ES6 모듈)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724231491264&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// module.js - ES6 모듈 구조

let x = 10; // 모듈 스코프 내에서 변수 선언
console.log(x); // 10

function strictFunction() {
    y = 20; // ReferenceError: y is not defined (엄격 모드에서는 오류)
    console.log(y);
}

strictFunction();

console.log(this); // undefined (모듈에서는 this가 전역 객체를 가리키지 않음)&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;특징:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;엄격 모드가 자동 적용&lt;/b&gt;: ES6 모듈에서는 &lt;span&gt;&quot;use strict&quot;;&lt;/span&gt;를 명시하지 않아도 엄격 모드가 자동으로 적용됩니다. 이로 인해 더 안전한 코드 작성이 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;암묵적 전역 변수 생성 금지&lt;/b&gt;: 엄격 모드에서는 암묵적 전역 변수 생성이 금지됩니다. 위 예제에서 &lt;span&gt;y = 20;&lt;/span&gt;은 선언되지 않은 변수에 값을 할당하려고 하므로 오류가 발생합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;모듈 스코프 사용&lt;/b&gt;: ES6 모듈의 모든 코드는 고유한 모듈 스코프 내에서 실행됩니다. 이 때문에 모듈 간의 전역 변수 충돌이 발생하지 않습니다. 또한, 모듈 내에서 &lt;span&gt;this&lt;/span&gt;는 &lt;span&gt;undefined&lt;/span&gt;가 됩니다.&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 alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot 2024-08-21 at 5.33.50 PM.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dy6jaY/btsJaglH3Bj/JaAD6XaDrSxAgdLGwsDGDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dy6jaY/btsJaglH3Bj/JaAD6XaDrSxAgdLGwsDGDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dy6jaY/btsJaglH3Bj/JaAD6XaDrSxAgdLGwsDGDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdy6jaY%2FbtsJaglH3Bj%2FJaAD6XaDrSxAgdLGwsDGDk%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;1500&quot; height=&quot;348&quot; data-filename=&quot;Screenshot 2024-08-21 at 5.33.50 PM.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;348&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;결론&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;전통적인 스크립트 방식&lt;/b&gt;에서는 엄격 모드가 자동으로 적용되지 않으므로, 안전한 코드를 작성하기 위해서는 &lt;span&gt;&quot;use strict&quot;;&lt;/span&gt;를 명시적으로 선언해야 합니다. 또한, 전역 스코프에서 모든 코드가 실행되며, 암묵적인 전역 변수 생성이 허용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&amp;bull;&lt;span&gt; &lt;/span&gt;&lt;b&gt;ES6 모듈 방식&lt;/b&gt;에서는 엄격 모드가 자동으로 적용되어, 더 안전한 코드 작성을 보장합니다. 모듈 스코프 내에서 코드가 실행되며, &lt;span&gt;this&lt;/span&gt;는 전역 객체를 가리키지 않고 &lt;span&gt;undefined&lt;/span&gt;가 됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&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://youtu.be/EWfujNzSUmw?si=NR1VHFLZJprG3Sbt&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://youtu.be/EWfujNzSUmw?si=NR1VHFLZJprG3Sbt&lt;/a&gt;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=EWfujNzSUmw&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/38gBL/hyWSiCeUpt/IpTVACyCsS8lJXgkjYTGGk/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=934_170_992_232&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;[10분 테코톡]   하루의 실행 컨텍스트&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/EWfujNzSUmw&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@kados22/FE-%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8%EA%B0%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@kados22/FE-%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8%EA%B0%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724226449445&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[FE 기술 면접] 실행 컨텍스트가 무엇인가요?&quot; data-og-description=&quot;1️⃣ 실행 컨텍스트(Execution Context)에 대해서 설명해주세요.실행 컨텍스트는 실행 가능한 코드에 제공할 환경 정보를 모아놓은 객체입니다. 해당 객체에는 변수 객체, 스코프 체인, this 정보가 &quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@kados22/FE-%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8%EA%B0%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94&quot; data-og-url=&quot;https://velog.io/@kados22/FE-기술-면접-실행-컨텍스트가-무엇인가요&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/0sNWb/hyWSiCgwzd/EknIyV7B80F2acOiNsN6w1/img.png?width=884&amp;amp;height=228&amp;amp;face=558_154_814_198,https://scrap.kakaocdn.net/dn/XhSnL/hyWSjBadzl/I1vFJnrERL2iG2J5T4Fme1/img.png?width=884&amp;amp;height=228&amp;amp;face=558_154_814_198,https://scrap.kakaocdn.net/dn/cs4oTZ/hyWSbC9RY1/GzEKgdiqDSx9WRoYBeFcT1/img.jpg?width=460&amp;amp;height=460&amp;amp;face=103_138_356_414&quot;&gt;&lt;a href=&quot;https://velog.io/@kados22/FE-%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8%EA%B0%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@kados22/FE-%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91-%EC%8B%A4%ED%96%89-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8%EA%B0%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80%EC%9A%94&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/0sNWb/hyWSiCgwzd/EknIyV7B80F2acOiNsN6w1/img.png?width=884&amp;amp;height=228&amp;amp;face=558_154_814_198,https://scrap.kakaocdn.net/dn/XhSnL/hyWSjBadzl/I1vFJnrERL2iG2J5T4Fme1/img.png?width=884&amp;amp;height=228&amp;amp;face=558_154_814_198,https://scrap.kakaocdn.net/dn/cs4oTZ/hyWSbC9RY1/GzEKgdiqDSx9WRoYBeFcT1/img.jpg?width=460&amp;amp;height=460&amp;amp;face=103_138_356_414');&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;[FE 기술 면접] 실행 컨텍스트가 무엇인가요?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;1️⃣ 실행 컨텍스트(Execution Context)에 대해서 설명해주세요.실행 컨텍스트는 실행 가능한 코드에 제공할 환경 정보를 모아놓은 객체입니다. 해당 객체에는 변수 객체, 스코프 체인, this 정보가&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;velog.io&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;</description>
      <category>TIL</category>
      <category>this</category>
      <category>명시적바인딩</category>
      <category>실행컨택스트</category>
      <author>dearsuhyun</author>
      <guid isPermaLink="true">https://diveintodevworld.tistory.com/71</guid>
      <comments>https://diveintodevworld.tistory.com/71#entry71comment</comments>
      <pubDate>Wed, 21 Aug 2024 18:56:19 +0900</pubDate>
    </item>
    <item>
      <title>Beginner 14회차 (8/20) | TS 유틸리티 타입, React-Router의 페이지 지정 방법, 모달 애니메이션 적용 실습, todo 순서 바꾸기 실습(sortablejs), useRef와 current 속성</title>
      <link>https://diveintodevworld.tistory.com/70</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;TS&amp;nbsp;유틸리티&amp;nbsp;타입&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 데이터에 있는 모든 내용을 선택적으로 만듬&lt;/p&gt;
&lt;pre id=&quot;code_1724116562538&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface User {
    name: string
    age: number
}

const user: User {
    name: 'suhyun'
}
// 오류 발생
// 'age: 85' 없으면 필수인데 없기 때문에 오류 !&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;Partial을 붙여주면 interface 내용이 필수적이 아니라 선택적으로 설정된 것과 같이 작동 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;user에서 name, age를 사용하지 않아도 오류가 발생하지 않음&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;'처음부터 선택적으로 만들면 안되는가 ?'&lt;br /&gt;--&amp;gt; 모든 것에 필수여야 하는 경우에 대응하기 힘듬&lt;br /&gt;만들 때는 필수 --&amp;gt; 선택적으로 ? 붙여서 사용하는 것이 일반적 !&lt;/blockquote&gt;
&lt;pre id=&quot;code_1724116949395&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface PartialUser {
    name?: string
    age?: number
}

// utility type (TS에 이미 내장된 타입)
const user: Partial&amp;lt;User&amp;gt; {
    name: 'suhyun'
}&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1368&quot; data-origin-height=&quot;724&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ct6n7Q/btsI8r8ct5g/eKedJLNxN4wXa6HBI6jJfk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ct6n7Q/btsI8r8ct5g/eKedJLNxN4wXa6HBI6jJfk/img.png&quot; data-alt=&quot;api &amp;amp;gt; todos.ts&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ct6n7Q/btsI8r8ct5g/eKedJLNxN4wXa6HBI6jJfk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fct6n7Q%2FbtsI8r8ct5g%2FeKedJLNxN4wXa6HBI6jJfk%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;1368&quot; height=&quot;724&quot; data-origin-width=&quot;1368&quot; data-origin-height=&quot;724&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;api &amp;gt; todos.ts&lt;/figcaption&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;- record&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;key를 속성(key)로, type을 그 속성값의 type으로 지정하는 새로운 타입&lt;/p&gt;
&lt;pre id=&quot;code_1724134862422&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Record&amp;lt;KEY, TYPE&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724134915906&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type TName = 'neo' | 'lewis'

const developers: Record&amp;lt;TName, number&amp;gt; = {
  neo: 12,
  lewis: 13
}&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;/p&gt;
&lt;pre id=&quot;code_1724135077471&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface INewType {
  neo: number
  lewis: number
}&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;- omit&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;TYPE&lt;span style=&quot;text-align: start;&quot;&gt;에서&amp;nbsp;&lt;/span&gt;KEY&lt;span style=&quot;text-align: start;&quot;&gt;로 속성을 생략하고 나머지를 선택한 새로운 타입을 반환&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;TYPE&lt;span style=&quot;text-align: start;&quot;&gt;은 속성을 가지는 인터페이스나 객체 타입이어야 함&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724135017086&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Omit&amp;lt;TYPE, KEY&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1724135032884&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface IUser {
  name: string
  age: number
  email: string
  isValid: boolean
}
type TKey = 'name' | 'email'

const user: Omit&amp;lt;IUser, TKey&amp;gt; = {
  age: 22,
  isValid: true,
  name: 'Neo' // TS2322: Type '{ age: number; isValid: true; name: string; }' is not assignable to type 'Pick&amp;lt;IUser, &quot;age&quot; | &quot;isValid&quot;&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;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;이렇게 이해할 수 있음 !&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724135046802&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;interface INewType {
  // name: string
  age: number
  // email: string
  isValid: boolean
}&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;- exclude&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;유니언&amp;nbsp;&lt;/span&gt;TYPE1&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;에서 유니언&amp;nbsp;&lt;/span&gt;TYPE2&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;를 제외한 새로운 타입을 반환&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1724135133768&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Exclude&amp;lt;TYPE1, TYPE2&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1724135142935&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type T = string | number

const a: Exclude&amp;lt;T, number&amp;gt; = 'Only string'
const b: Exclude&amp;lt;T, number&amp;gt; = 1234 // TS2322: Type '123' is not assignable to type 'string'.
const c: T = 'String'
const d: T = 1234&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;h3 data-ke-size=&quot;size23&quot;&gt;todo 추가 기능이 구현되지 않는 문제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 코드&lt;/p&gt;
&lt;pre id=&quot;code_1724118011604&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async function createTodo() {
    await axios.post('/api/todos'), {
      method: 'POST',
      data: {
        title
      }
    }
    getTodos()
  }&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;method, data 부분을 axios의 두번째 인수로 줘야 하는데 그렇지 못해서 발생한 오류 수정&lt;/p&gt;
&lt;pre id=&quot;code_1724118050006&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;async function createTodo() {
    await axios.post('/api/todos', {
      method: 'POST',
      data: {
        title
      }
    })
    getTodos()
  }&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;수정 후 main에 푸시하면 vercel에서 자동으로 배포 !&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1932&quot; data-origin-height=&quot;868&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kA2mR/btsI8ZDka0x/ycRH146AzQ1rCOL0yPni6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kA2mR/btsI8ZDka0x/ycRH146AzQ1rCOL0yPni6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kA2mR/btsI8ZDka0x/ycRH146AzQ1rCOL0yPni6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkA2mR%2FbtsI8ZDka0x%2FycRH146AzQ1rCOL0yPni6K%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;1932&quot; height=&quot;868&quot; data-origin-width=&quot;1932&quot; data-origin-height=&quot;868&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;h2 data-ke-size=&quot;size26&quot;&gt;React-Router의 페이지 지정 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 객체 형식으로 페이지(라우트) 지정&lt;/p&gt;
&lt;pre id=&quot;code_1724121299483&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export const router = createBrowserRouter([
  {
    path: '/',
    element: &amp;lt;Main /&amp;gt;,
    // 메인 페이지가 보이는 상태에서 모달을 보여줄거니까 children으로 설정
    children: [
      {
        path: ':todoId',
        element: &amp;lt;TodoItemDetails /&amp;gt;
      }
    ]
  }
])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1306&quot; data-origin-height=&quot;436&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bi4RQf/btsI9tEYfld/1MqUxRJ0xcKTQKNIgTRntK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bi4RQf/btsI9tEYfld/1MqUxRJ0xcKTQKNIgTRntK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bi4RQf/btsI9tEYfld/1MqUxRJ0xcKTQKNIgTRntK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbi4RQf%2FbtsI9tEYfld%2F1MqUxRJ0xcKTQKNIgTRntK%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;1306&quot; height=&quot;436&quot; data-origin-width=&quot;1306&quot; data-origin-height=&quot;436&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;2. 컴포넌트 방식으로 페이지(라우트) 지정&lt;/p&gt;
&lt;pre id=&quot;code_1724121315534&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export default function Index() {
  // location 객체는 현재 URL에 대한 정보를 가지고 있음
  const location = useLocation()
  return (
    &amp;lt;AnimatePresence mode=&quot;wait&quot;&amp;gt;
      &amp;lt;Routes
        location={location}
        key={location.pathname}&amp;gt;
        &amp;lt;Route
          path=&quot;/&quot;
          element={&amp;lt;Main /&amp;gt;}&amp;gt;
          &amp;lt;Route
            path={'/:todoId'}
            element={&amp;lt;TodoItemDetails /&amp;gt;}
          /&amp;gt;
        &amp;lt;/Route&amp;gt;
      &amp;lt;/Routes&amp;gt;
    &amp;lt;/AnimatePresence&amp;gt;
  )
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1178&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9Q53n/btsI9FLPsvr/sIe8hzC4ITyDEafHkrjoD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9Q53n/btsI9FLPsvr/sIe8hzC4ITyDEafHkrjoD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9Q53n/btsI9FLPsvr/sIe8hzC4ITyDEafHkrjoD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9Q53n%2FbtsI9FLPsvr%2FsIe8hzC4ITyDEafHkrjoD0%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;1178&quot; height=&quot;472&quot; data-origin-width=&quot;1178&quot; data-origin-height=&quot;472&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;h2 data-ke-size=&quot;size26&quot;&gt;모달 애니메이션 적용 실습&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;routes &amp;gt; index.tsx&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;AnimatePresence&amp;gt; 전체 주소의 사라지는 애니매이션 까지 담당하겠다 !&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;페이지를 바꾸는 방법으로 모달을 사용하고 있기 때문에 페이지 사라질 때 부분도 설정해주어야 함&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;모달 사라지게 할 때 주소가 바로 사라지니까 당연히 모달도 바로 사라지는 것 --&amp;gt; AnimatePresence 사용&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;992&quot; data-origin-height=&quot;1084&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIS9Od/btsI9RFs6oJ/Oe6PUfct1BaadKL9KOAsek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIS9Od/btsI9RFs6oJ/Oe6PUfct1BaadKL9KOAsek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIS9Od/btsI9RFs6oJ/Oe6PUfct1BaadKL9KOAsek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIS9Od%2FbtsI9RFs6oJ%2FOe6PUfct1BaadKL9KOAsek%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;992&quot; height=&quot;1084&quot; data-origin-width=&quot;992&quot; data-origin-height=&quot;1084&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;todoItemDetails.tsx&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&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;1092&quot; data-origin-height=&quot;1048&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/99rTd/btsI80CgffK/eB0b1ggk4A4qgIZ4Tdrt4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/99rTd/btsI80CgffK/eB0b1ggk4A4qgIZ4Tdrt4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/99rTd/btsI80CgffK/eB0b1ggk4A4qgIZ4Tdrt4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F99rTd%2FbtsI80CgffK%2FeB0b1ggk4A4qgIZ4Tdrt4k%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;1092&quot; height=&quot;1048&quot; data-origin-width=&quot;1092&quot; data-origin-height=&quot;1048&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;exit={{ opacity: 0}}을 추가해서 사라질 때도 자연스럽게 사라지도록 만들어주기 !&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;832&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dBt7E4/btsI9ivS47E/FQMwkCZBNgpx5BjMFsTvc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dBt7E4/btsI9ivS47E/FQMwkCZBNgpx5BjMFsTvc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dBt7E4/btsI9ivS47E/FQMwkCZBNgpx5BjMFsTvc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdBt7E4%2FbtsI9ivS47E%2FFQMwkCZBNgpx5BjMFsTvc1%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;1038&quot; height=&quot;832&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;832&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;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screen Recording 2024-08-20 at 11.59.58 AM.gif&quot; data-origin-width=&quot;2110&quot; data-origin-height=&quot;1432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ds7QjH/btsI8m0bP2Q/O0QhHWtIjcqkzVA8flCep1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ds7QjH/btsI8m0bP2Q/O0QhHWtIjcqkzVA8flCep1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ds7QjH/btsI8m0bP2Q/O0QhHWtIjcqkzVA8flCep1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/ds7QjH/btsI8m0bP2Q/O0QhHWtIjcqkzVA8flCep1/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;2110&quot; height=&quot;1432&quot; data-filename=&quot;Screen Recording 2024-08-20 at 11.59.58 AM.gif&quot; data-origin-width=&quot;2110&quot; data-origin-height=&quot;1432&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;h2 data-ke-size=&quot;size26&quot;&gt;todoList에서 item 순서 바꾸기 실습&lt;/h2&gt;
&lt;pre id=&quot;code_1724122051045&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import Sortable from 'sortablejs'
npm i -D @types/sortablejs&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;useRef과 current 속성&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1180&quot; data-origin-height=&quot;796&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2b9wu/btsI9H3XPrS/WEKlBCPdxqYRhZAqIDGPD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2b9wu/btsI9H3XPrS/WEKlBCPdxqYRhZAqIDGPD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2b9wu/btsI9H3XPrS/WEKlBCPdxqYRhZAqIDGPD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2b9wu%2FbtsI9H3XPrS%2FWEKlBCPdxqYRhZAqIDGPD1%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;1180&quot; height=&quot;796&quot; data-origin-width=&quot;1180&quot; data-origin-height=&quot;796&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;Main.tsx&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1610&quot; data-origin-height=&quot;2272&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bacUJq/btsI9XeuS0a/TfKihTY4jScbsbJMjqu0Ek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bacUJq/btsI9XeuS0a/TfKihTY4jScbsbJMjqu0Ek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bacUJq/btsI9XeuS0a/TfKihTY4jScbsbJMjqu0Ek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbacUJq%2FbtsI9XeuS0a%2FTfKihTY4jScbsbJMjqu0Ek%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;1610&quot; height=&quot;2272&quot; data-origin-width=&quot;1610&quot; data-origin-height=&quot;2272&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;Sortable의 필수 속성 4가지&lt;/p&gt;
&lt;pre id=&quot;code_1724148978098&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;new Sortable(listRef.current, {
      handle: '',
      animation: 0,
      forceFallback: true,
      onEnd: () =&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;pre id=&quot;code_1724124377206&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;new Sortable(todoListEl.current, {
    handle: '.drag-handle', // 드래그 핸들이 될 요소의 선택자를 입력
    animation: 0, // 정렬할 때 애니메이션 속도(ms)를 지정, default: 150
    forceFallback: true, // 크로스 브라우징, 다양한 환경의 일관된 Drag&amp;amp;Drop(DnD)을 위해 HTML5 기본 DnD 동작을 무시하고 내장 기능을 사용, default: false
    // 요소의 DnD가 종료되면 실행할 핸들러(함수)를 지정
    onEnd: event =&amp;gt; {
      const { oldIndex, newIndex } = event
      if (oldIndex === undefined || newIndex === undefined) return
      console.log('oldIndex:', oldIndex, 'newIndex:', newIndex)
      mutate({
        oldIndex,
        newIndex
      })
    }&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;br /&gt;sortablejs는 화면만 바꿔주기 때문에 새로고침하면 순서 바꾼 것이 그대로 돌아옴&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;서버에 전송해줘서 새로고침해줘도 유지하도록 ! api 사용해주어야 함&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;760&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bg1df2/btsI7m01Cce/vVoahke3YsWsPUlCJTtGt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bg1df2/btsI7m01Cce/vVoahke3YsWsPUlCJTtGt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bg1df2/btsI7m01Cce/vVoahke3YsWsPUlCJTtGt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbg1df2%2FbtsI7m01Cce%2FvVoahke3YsWsPUlCJTtGt0%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;1050&quot; height=&quot;760&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;760&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screen Recording 2024-08-20 at 12.32.06 PM.gif&quot; data-origin-width=&quot;1714&quot; data-origin-height=&quot;1432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqe5uS/btsI8POz8Kq/pqL3KIrd41ujLysnCep9ik/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqe5uS/btsI8POz8Kq/pqL3KIrd41ujLysnCep9ik/img.gif&quot; data-alt=&quot;oldIndex, newIndex가 console에 찍히는 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqe5uS/btsI8POz8Kq/pqL3KIrd41ujLysnCep9ik/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bqe5uS/btsI8POz8Kq/pqL3KIrd41ujLysnCep9ik/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;1714&quot; height=&quot;1432&quot; data-filename=&quot;Screen Recording 2024-08-20 at 12.32.06 PM.gif&quot; data-origin-width=&quot;1714&quot; data-origin-height=&quot;1432&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;oldIndex, newIndex가 console에 찍히는 화면&lt;/figcaption&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;API 명세서 확인&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1052&quot; data-origin-height=&quot;1296&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oasS3/btsI7qbbFAe/s8Qw4uBvpQoxZDuwsTphtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oasS3/btsI7qbbFAe/s8Qw4uBvpQoxZDuwsTphtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oasS3/btsI7qbbFAe/s8Qw4uBvpQoxZDuwsTphtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoasS3%2FbtsI7qbbFAe%2Fs8Qw4uBvpQoxZDuwsTphtK%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;1052&quot; height=&quot;1296&quot; data-origin-width=&quot;1052&quot; data-origin-height=&quot;1296&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;store에 reordertodos 생성&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1136&quot; data-origin-height=&quot;1156&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eEZZfv/btsI91nBizZ/Xhy7bPbMORQIkT2MUywgdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eEZZfv/btsI91nBizZ/Xhy7bPbMORQIkT2MUywgdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eEZZfv/btsI91nBizZ/Xhy7bPbMORQIkT2MUywgdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeEZZfv%2FbtsI91nBizZ%2FXhy7bPbMORQIkT2MUywgdK%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;1136&quot; height=&quot;1156&quot; data-origin-width=&quot;1136&quot; data-origin-height=&quot;1156&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;* TS 유틸리티 타입 자주 쓰이는 4가지는 꼭 알아두기 (다른 것도 읽어보기)&lt;br /&gt;partial, record, omit, exclude&lt;br /&gt;&lt;br /&gt;* Pakage.json&lt;br /&gt;Sem Ver:&amp;nbsp;^35.2.4&lt;br /&gt;--&amp;gt;&amp;nbsp;major 버전은 바뀌지 않지만, 버셀 패키지를 설치하면 마이너와 패치 버전을 가장 최신으로 유지한다&lt;br /&gt;&lt;br /&gt;&quot;vercel&quot;: &quot;^35.2.4&quot;,&lt;br /&gt;
&lt;pre id=&quot;code_1724135184369&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// latest(최신버전) 
npm i -D vercel@latest 

// canary(배타버전) 
npm i -D vercel@canary​&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
* transition: 전 상태 --&amp;gt; 후 상태를 자연스럽게 전환해준다&lt;br /&gt;&lt;br /&gt;* 처음부터 react-** 라고 만들어진 라이브러리는 대안이 없음&lt;br /&gt;sortablejs 의 경우 react-sortablejs라는 대안이 있는 것임&lt;br /&gt;순수 js(ts)로 만들어진 라이브러리가 있다면 react-**잘 사용하지 않는 이유 ?&lt;br /&gt;--&amp;gt; react, vue, svelte같은 프레임워크는 계속 변화함 ==&amp;gt; react-**도 업데이트 되지 않으면 사용 불가&lt;br /&gt;라이브러리에 의존해서 만들어진 추가적인 라이브러리는, 라이브러리가 망가지면 쓸 수 없음&lt;br /&gt;순수 js, ts로 만들어진 라이브러리를 사용하는 것을 추천함 !&lt;/blockquote&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://www.heropy.dev/p/WhqSC8&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.heropy.dev/p/WhqSC8&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724116331380&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;한눈에 보는 타입스크립트&quot; data-og-description=&quot;타입스크립트는 Microsoft에서 개발하고 유지/관리하는 Apache 라이센스가 부여된 오픈 소스로, 자바스크립트에 강한 타입 시스템을 적용해 대부분의 에러를 컴파일 환경에서 코드를 입력하는 동안&quot; data-og-host=&quot;www.heropy.dev&quot; data-og-source-url=&quot;https://www.heropy.dev/p/WhqSC8&quot; data-og-url=&quot;https://www.heropy.dev/p/WhqSC8&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/0HcId/hyWSooCnV1/aVKI83PrzYE3pMEEgexqo0/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571,https://scrap.kakaocdn.net/dn/iRr4s/hyWOk9hmPS/D5gTykSspZ65rmMmwIiqO0/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571,https://scrap.kakaocdn.net/dn/mC0kV/hyWOiji6k1/N4oeOVW611OxToikehcSyk/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571&quot;&gt;&lt;a href=&quot;https://www.heropy.dev/p/WhqSC8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.heropy.dev/p/WhqSC8&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/0HcId/hyWSooCnV1/aVKI83PrzYE3pMEEgexqo0/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571,https://scrap.kakaocdn.net/dn/iRr4s/hyWOk9hmPS/D5gTykSspZ65rmMmwIiqO0/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571,https://scrap.kakaocdn.net/dn/mC0kV/hyWOiji6k1/N4oeOVW611OxToikehcSyk/img.jpg?width=1000&amp;amp;height=571&amp;amp;face=0_0_1000_571');&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;한눈에 보는 타입스크립트&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;타입스크립트는 Microsoft에서 개발하고 유지/관리하는 Apache 라이센스가 부여된 오픈 소스로, 자바스크립트에 강한 타입 시스템을 적용해 대부분의 에러를 컴파일 환경에서 코드를 입력하는 동안&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.heropy.dev&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/ParkYoungWoong/todo_vite-react-ts&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/ParkYoungWoong/todo_vite-react-ts&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724118308779&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 - ParkYoungWoong/todo_vite-react-ts&quot; data-og-description=&quot;Contribute to ParkYoungWoong/todo_vite-react-ts development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/ParkYoungWoong/todo_vite-react-ts&quot; data-og-url=&quot;https://github.com/ParkYoungWoong/todo_vite-react-ts&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bkbZgT/hyWSnQLgLn/YCZcMVxRsBCvf0HI0iSYhK/img.png?width=1200&amp;amp;height=600&amp;amp;face=946_125_1071_261&quot;&gt;&lt;a href=&quot;https://github.com/ParkYoungWoong/todo_vite-react-ts&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/ParkYoungWoong/todo_vite-react-ts&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bkbZgT/hyWSnQLgLn/YCZcMVxRsBCvf0HI0iSYhK/img.png?width=1200&amp;amp;height=600&amp;amp;face=946_125_1071_261');&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 - ParkYoungWoong/todo_vite-react-ts&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to ParkYoungWoong/todo_vite-react-ts development by creating an account on GitHub.&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;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://sortablejs.github.io/Sortable/#frameworks&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://sortablejs.github.io/Sortable/#frameworks&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1724121715936&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;SortableJS&quot; data-og-description=&quot;Thresholds Try modifying the inputs below to affect the swap thresholds. You can see the swap zones of the squares colored in dark blue, while the &amp;quot;dead zones&amp;quot; (that do not cause a swap) are colored in light blue. &amp;lt;!-- --&amp;gt; new Sortable(example7, { swapThre&quot; data-og-host=&quot;sortablejs.github.io&quot; data-og-source-url=&quot;https://sortablejs.github.io/Sortable/#frameworks&quot; data-og-url=&quot;https://sortablejs.github.io/Sortable/#frameworks&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://sortablejs.github.io/Sortable/#frameworks&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sortablejs.github.io/Sortable/#frameworks&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;SortableJS&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Thresholds Try modifying the inputs below to affect the swap thresholds. You can see the swap zones of the squares colored in dark blue, while the &quot;dead zones&quot; (that do not cause a swap) are colored in light blue. &amp;lt;!-- --&amp;gt; new Sortable(example7, { swapThre&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;sortablejs.github.io&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;</description>
      <category>Live Class/Beginner</category>
      <category>animatepresence</category>
      <category>reactrouter</category>
      <category>sortablejs</category>
      <category>ts유틸리티타입</category>
      <category>useRef</category>
      <author>dearsuhyun</author>
      <guid isPermaLink="true">https://diveintodevworld.tistory.com/70</guid>
      <comments>https://diveintodevworld.tistory.com/70#entry70comment</comments>
      <pubDate>Wed, 21 Aug 2024 14:02:30 +0900</pubDate>
    </item>
  </channel>
</rss>