<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Dani's Dev TokTok</title>
    <link>https://daddda3232.tistory.com/</link>
    <description>열심히 개발하는 다니니니니니니의 개발 블로그</description>
    <language>ko</language>
    <pubDate>Thu, 2 Jul 2026 04:05:54 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>다니니니</managingEditor>
    <image>
      <title>Dani's Dev TokTok</title>
      <url>https://tistory1.daumcdn.net/tistory/5808264/attach/588ac45eafa14998b1690b2bc1a914d5</url>
      <link>https://daddda3232.tistory.com</link>
    </image>
    <item>
      <title>2025년 정보처리기사 1회 필기 합격 후기</title>
      <link>https://daddda3232.tistory.com/134</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 3월 2일에 치룬 정보처리기사 필기 시험 공부 후기와 합격 후기를 적어보고자 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;안읽어도 되는 공부하게 된 배경&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;s&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;힘들게 취업했던 회사에서 멘탈이 털리는 사건이 생긴 후&lt;/span&gt;..&lt;span style=&quot;color: #dddddd;&quot;&gt;(직장내 성희롱과 성추행.....ㅠ )&lt;/span&gt;&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;s&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;멘탈 회복을 위해 어디 집중할 곳이 필요했습니다.&lt;/span&gt;&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;s&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;그래서 미루고 미뤘던 정보처리기사 시험 준비를 했습니다.&lt;/span&gt;&lt;/s&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;span style=&quot;color: #000000;&quot;&gt;2025년 1월 ~ 2025년 2월 대략 한달반 정도&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇지만 제 블로그의 다른 포스팅을 보면 아시다시피 자바의 기본 문법이나 sql 기본 문법은 부트캠프를 통해 배워서 알고 있는 상태였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 자바스크립트를 공부해서 프로그래밍 언어에서 공통적으로 쓰이는 문법(조건문이나 반복문)의 원리를 알고 있는 상태였습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;공부방법&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전에 공부해두려고 사둔 시나공 정보처리기사 필기 기본서(2024년도)가 있어서 그것을 바탕으로 이론 1회독을 했습니다.&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/Ji412/btsMKt9RZIp/FXRCxJXLsQLfWpJPMzwVtk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ji412/btsMKt9RZIp/FXRCxJXLsQLfWpJPMzwVtk/img.jpg&quot; width=&quot;391&quot; height=&quot;391&quot; data-filename=&quot;KakaoTalk_20250314_184242428_04.jpg&quot; data-origin-height=&quot;1334&quot; data-origin-width=&quot;1334&quot; data-is-animation=&quot;false&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/Ji412/btsMKt9RZIp/FXRCxJXLsQLfWpJPMzwVtk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJi412%2FbtsMKt9RZIp%2FFXRCxJXLsQLfWpJPMzwVtk%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;1334&quot; height=&quot;1334&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2YRyI/btsMLvFMEU0/lHR4g6PVxNGLU78dOXKq20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2YRyI/btsMLvFMEU0/lHR4g6PVxNGLU78dOXKq20/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1334&quot; data-origin-height=&quot;1334&quot; data-filename=&quot;edited_KakaoTalk_20250314_184242428_01.jpg&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/2YRyI/btsMLvFMEU0/lHR4g6PVxNGLU78dOXKq20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2YRyI%2FbtsMLvFMEU0%2FlHR4g6PVxNGLU78dOXKq20%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;1334&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D9j1E/btsMKIlwQLa/61FH0Hy7afhlrpAwCZFGO0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D9j1E/btsMKIlwQLa/61FH0Hy7afhlrpAwCZFGO0/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1334&quot; data-origin-height=&quot;1334&quot; data-filename=&quot;KakaoTalk_20250314_184242428_02.jpg&quot; data-widthpercent=&quot;33.34&quot; style=&quot;width: 32.5581%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D9j1E/btsMKIlwQLa/61FH0Hy7afhlrpAwCZFGO0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD9j1E%2FbtsMKIlwQLa%2F61FH0Hy7afhlrpAwCZFGO0%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;1334&quot; height=&quot;1334&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;노트를 두 권 두고 한 권은 그냥 중요해보이는 것을 적고(책에서 강조하는 것들) 한 권은 시나공 기본서의 챕터가 끝날때마다 마지막에 핵심요약한 곳이 있는데 그것을 보면서 노트에 정리해가며 공부를 했습니다.&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;기본서 구성에 기출문제집도 포함되어 있는데, 저는 기본서를 2024년 초반에 구매했기 때문에 2023년도 까지의 기출문제밖에 없었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 2024 기출문제는 시나공 홈페이지에 가서 다운받아서 문제 풀이했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 기출문제를 다 푼후에는 cbt 풀 수 있는 곳은 다 가서 한 번씩은 다 풀었습니다.&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;앞서 말했듯이 제가 프로그래밍 언어와 sql 언어의 기본문법은 알고 있어도 다른 이론 같은것은 잘 몰랐기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 기출문제를 풀때는 최대 8개 최소 4개 정도는 문제를 틀렸습니다.&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&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/lymmq/btsMMBkJhwG/hovV7EJk9KopcbWGFhrD81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lymmq/btsMMBkJhwG/hovV7EJk9KopcbWGFhrD81/img.png&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; width=&quot;411&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot; data-filename=&quot;edited_KakaoTalk_20250314_184242428.jpg&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lymmq/btsMMBkJhwG/hovV7EJk9KopcbWGFhrD81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flymmq%2FbtsMMBkJhwG%2FhovV7EJk9KopcbWGFhrD81%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;400&quot; height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UZp0q/btsMLyJkqmo/YKqc3kVDpagBGrEnpDEMSK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UZp0q/btsMLyJkqmo/YKqc3kVDpagBGrEnpDEMSK/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1334&quot; data-origin-height=&quot;1334&quot; data-filename=&quot;KakaoTalk_20250314_190341971.jpg&quot; data-widthpercent=&quot;50&quot; style=&quot;width: 49.4186%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UZp0q/btsMLyJkqmo/YKqc3kVDpagBGrEnpDEMSK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUZp0q%2FbtsMLyJkqmo%2FYKqc3kVDpagBGrEnpDEMSK%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;1334&quot; height=&quot;1334&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;문제를 계속 풀다보니 뭔가 키워드 위주로 아 이 키워드가 나오면 답은 이거겠군.. 하고 예상이 되더라구요&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기출문제 많이 풀기랑 오답노트 진짜 추천드립니다.&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignLeft&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;032&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/032.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/032.gif&quot; width=&quot;150&quot; /&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;시험은 무조건 집에서 가까운 곳에서 봐야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 그래서 집이 다행히 서울이라 지하철로 2~3정거장이면 갈 수 있는 곳으로 시험장을 정했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;준비물은&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;신분증, 필기구&lt;/b&gt;&lt;/p&gt;
&lt;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;제가 3시험장이었나 5시험장이었나 (기억이 안남..) 이었는데&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;그리고 시험장에 들어가서 감독관님이 신분증 확인하고 필기할&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험시간은 과목당 30분이라서 총 2시간 30분 정도인데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터 화면에 문제 푸는 곳 상단에 남은 시간이 나왔던 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 시간을 다 꽉 채우진 않았고 30~40분만에 풀고 나왔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대략 25분만에 풀고 나머지는 내가 잘못 찍은거 없나.. 하고 검토한 뒤에 제출했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제출하니까 가채점 결과가 나오더라구요&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;손바닥에 점수 쓰려고 하니까 어차피 나중에 나오는데 뭐하러 쓰냐며 감독관님께 혼났습니다..ㅋㅋㅋ(그래서 쫄려서 못씀)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;&lt;span style=&quot;color: #000000;&quot;&gt;최종 결과&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;정처기 필기 점수.jpg&quot; data-origin-width=&quot;807&quot; data-origin-height=&quot;348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D6GNf/btsMKxRCOYi/OUYmK4q2pTKfk6GFGR4xnK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D6GNf/btsMKxRCOYi/OUYmK4q2pTKfk6GFGR4xnK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D6GNf/btsMKxRCOYi/OUYmK4q2pTKfk6GFGR4xnK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD6GNf%2FbtsMKxRCOYi%2FOUYmK4q2pTKfk6GFGR4xnK%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;807&quot; height=&quot;348&quot; data-filename=&quot;정처기 필기 점수.jpg&quot; data-origin-width=&quot;807&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;시험에 공부한 부분이 많이 나와서 좋은 점수를 받을 수 있었습니다.&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% 기출변형이 35% 생판 처음보는거 5% 비율로 나온 것 같았습니다.&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;cbt 나 기출 볼때도 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;&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;어차피 2년 유예기간이 있어서 바로 볼지 아니면 좀 더 두고 볼지 아직 고민중입니다..ㅋㅋㅋ&amp;nbsp;&lt;/p&gt;</description>
      <category>ETC/주절주절</category>
      <category>정보처리기사</category>
      <category>정처기</category>
      <category>정처기필기</category>
      <category>필기</category>
      <author>다니니니</author>
      <guid isPermaLink="true">https://daddda3232.tistory.com/134</guid>
      <comments>https://daddda3232.tistory.com/134#entry134comment</comments>
      <pubDate>Fri, 14 Mar 2025 19:24:18 +0900</pubDate>
    </item>
    <item>
      <title>요즘에는 정처기 필기 준비중!</title>
      <link>https://daddda3232.tistory.com/133</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;미루고 미뤄왔던 정보처리기사 필기 준비중이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3월이 시험이다! 으악 떨려!&lt;/p&gt;</description>
      <category>ETC/주절주절</category>
      <author>다니니니</author>
      <guid isPermaLink="true">https://daddda3232.tistory.com/133</guid>
      <comments>https://daddda3232.tistory.com/133#entry133comment</comments>
      <pubDate>Wed, 26 Feb 2025 10:25:57 +0900</pubDate>
    </item>
    <item>
      <title>[React] React Datepicker 이용해서 달력 만들기</title>
      <link>https://daddda3232.tistory.com/130</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;들어가며&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트에서 달력을 구현할 수 있는 여러가지 라이브러리 중 react-datepicker 를 이용해서&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;&amp;nbsp;먼저 리액트 프로젝트에서 npm이나 yarn 을 이용해서 date-picker 를 다운로드 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1733230215583&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install react-datepicker

yarn add react-datepicker&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; date-fns 에서 해당 기능을 제공하므로 같이 다운로드 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1733230282871&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install date-fns

yarn add date-fns&lt;/code&gt;&lt;/pre&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;DatePicker 라는 컴포넌트를 import 해서 사용할 수 있다.&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_1733230521467&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import DatePicker from &quot;react-datepicker&quot;;
import &quot;react-datepicker/dist/react-datepicker.module.css&quot;;
import { ko } from &quot;date-fns/locale&quot;;


export default function DateSelector() {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;DatePicker
        inline
        locale={ko}
        dateFormatCalendar=&quot;yyyy년 M월&quot;
      /&amp;gt;
    &amp;lt;/&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;262&quot; data-origin-height=&quot;253&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kV8bm/btsK6aiM5Tu/AWPvecRF8fznbbA3Tz8gh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kV8bm/btsK6aiM5Tu/AWPvecRF8fznbbA3Tz8gh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kV8bm/btsK6aiM5Tu/AWPvecRF8fznbbA3Tz8gh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkV8bm%2FbtsK6aiM5Tu%2FAWPvecRF8fznbbA3Tz8gh0%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;262&quot; height=&quot;253&quot; data-origin-width=&quot;262&quot; data-origin-height=&quot;253&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 위와 같이 기본적인 달력의 UI 를 구성해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;inline 속성을 써야 기본 달력이 보이며, 쓰지 않으면 input 창을 보여주고 input 을 눌러야 달력을 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;locale 설정으로 언어를 설정할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;locale 에 ko 즉, 한국어 설정을 넣어서 한국어로 출력했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 달력의 날짜 포맷을 지정해줄 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dateFormatCalendar 에서 &quot;yyyy년 M월&quot; 로 써서 년도, 월 순으로 출력해줬다.&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;이제 여기서 응용해서 시작 일자와 종료 일자를 선택할 수 있는 달력 UI 를 구현해보고자 한다.&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;date-picker 를 사용하면 간단하게 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1733232247173&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useState } from &quot;react&quot;;
import DatePicker from &quot;react-datepicker&quot;;
import &quot;react-datepicker/dist/react-datepicker.module.css&quot;;
import { ko } from &quot;date-fns/locale&quot;;
import &quot;./DateSelector.css&quot;;

export default function DateSelector() {
  // 오늘 날짜
  const today = new Date();

  // 시작 일자, 종료 일자 상태 관리
  const [dateRange, setDateRange] = useState&amp;lt;[Date | null, Date | null]&amp;gt;([
    null,
    null,
  ]);
  const [startDate, endDate] = dateRange;

  // 날짜 포맷팅 함수
  const formatDate = (date: Date) =&amp;gt; {
    const year = date.getFullYear();
    const month = date.getMonth() + 1;
    const day = date.getDate();

    return `${year}년 ${month}월 ${day}일`;
  };

  return (
    &amp;lt;&amp;gt;
      &amp;lt;div&amp;gt;
        {startDate !== null &amp;amp;&amp;amp; &amp;lt;span&amp;gt;{`${formatDate(startDate)}`}&amp;lt;/span&amp;gt;}
        {startDate !== null &amp;amp;&amp;amp; endDate !== null &amp;amp;&amp;amp; (
          &amp;lt;span&amp;gt;{` - ${formatDate(endDate)}`}&amp;lt;/span&amp;gt;
        )}
      &amp;lt;/div&amp;gt;
      &amp;lt;DatePicker
        inline
        monthsShown={2}
        selectsRange={true}
        startDate={startDate ?? undefined}
        endDate={endDate ?? undefined}
        minDate={today}
        maxDate={
          startDate !== null &amp;amp;&amp;amp; endDate === null
            ? new Date(
                startDate.getFullYear(),
                startDate.getMonth(),
                startDate.getDate() + 10
              )
            : undefined
        }
        onChange={(date) =&amp;gt; setDateRange(date)}
        locale={ko}
        dateFormatCalendar=&quot;yyyy년 M월&quot;
      /&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;p data-ke-size=&quot;size16&quot;&gt;1. 먼저 시작 일자, 종료 일자를 지정하기 위해&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useState 를 이용해서 상태 관리를 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1733233397075&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const [dateRange, setDateRange] = useState&amp;lt;[Date | null, Date | null]&amp;gt;([
  null,
  null,
]);
const [startDate, endDate] = dateRange;&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;그리고 이걸 DatePicker 컴포넌트에서 startDate, endDate 에 각각 값을 할당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단,&amp;nbsp; 저 속성에는 null 값을 지정할 수 없다. 그래서 null 값이면 undefind 를 할당되도록 했다.&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. minDate, maxDate 속성 설정으로 날짜 범위를 제한할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1733233549185&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;minDate={today}
maxDate={
  startDate !== null &amp;amp;&amp;amp; endDate === null
    ? new Date(
        startDate.getFullYear(),
        startDate.getMonth(),
        startDate.getDate() + 10
      )
    : undefined
}&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;minDate는 오늘 날짜를 지정해서 오늘 날짜 이전의 날짜를 선택할 수 없도록 설정하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;maxDate 는 선택된 날짜로부터 10일까지만 선택하도록 제한했다.&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. onChange 함수로 날짜를 지정하면 그 값이 startDate, endDate 에 저장이 되도록 설정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;selectsRange 를 true 로 설정해야 날짜의 범위를 지정할 수 있다.&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;pre id=&quot;code_1733233775187&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  // 날짜 포맷팅 함수
  const formatDate = (date: Date) =&amp;gt; {
    const year = date.getFullYear();
    const month = date.getMonth() + 1;
    const day = date.getDate();

    return `${year}년 ${month}월 ${day}일`;
  };&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_1733233824678&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  return (
      &amp;lt;div&amp;gt;
        {startDate !== null &amp;amp;&amp;amp; &amp;lt;span&amp;gt;{`${formatDate(startDate)}`}&amp;lt;/span&amp;gt;}
        {startDate !== null &amp;amp;&amp;amp; endDate !== null &amp;amp;&amp;amp; (
          &amp;lt;span&amp;gt;{` - ${formatDate(endDate)}`}&amp;lt;/span&amp;gt;
        )}
      &amp;lt;/div&amp;gt;
  )&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;결과&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;datepicker.gif&quot; data-origin-width=&quot;510&quot; data-origin-height=&quot;341&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IS0jx/btsK4yFewyL/Zo2mWgNIdj8CDfTgmm0PD1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IS0jx/btsK4yFewyL/Zo2mWgNIdj8CDfTgmm0PD1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IS0jx/btsK4yFewyL/Zo2mWgNIdj8CDfTgmm0PD1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/IS0jx/btsK4yFewyL/Zo2mWgNIdj8CDfTgmm0PD1/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;510&quot; height=&quot;341&quot; data-filename=&quot;datepicker.gif&quot; data-origin-width=&quot;510&quot; data-origin-height=&quot;341&quot;/&gt;&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Reference&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://reactdatepicker.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://reactdatepicker.com/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1733229922870&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;React Datepicker crafted by HackerOne&quot; data-og-description=&quot;&quot; data-og-host=&quot;reactdatepicker.com&quot; data-og-source-url=&quot;https://reactdatepicker.com/&quot; data-og-url=&quot;https://reactdatepicker.com/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://reactdatepicker.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://reactdatepicker.com/&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;React Datepicker crafted by HackerOne&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;reactdatepicker.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;/p&gt;</description>
      <category>Study/React</category>
      <category>REACT</category>
      <category>react-datepicker</category>
      <author>다니니니</author>
      <guid isPermaLink="true">https://daddda3232.tistory.com/130</guid>
      <comments>https://daddda3232.tistory.com/130#entry130comment</comments>
      <pubDate>Tue, 3 Dec 2024 22:51:28 +0900</pubDate>
    </item>
    <item>
      <title>SSR 과 CSR 의 차이</title>
      <link>https://daddda3232.tistory.com/129</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;들어가며&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SSR(Server Side rendering) 과 CSR(Client Side Rendering) 은 페이지 렌더링 방식을 경정하는 개념이다.&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;SSR &amp;amp; CSR&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;SSR(Server Side Rendering)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 사이드 렌더링은 클라이언트 요청에 따라 HTML 파일을 서버에서 렌더링해서 완성된 HTML 파일을 클라이언트에 전달한다. 그 후 브라우저는 서버로부터 완성된 HTML 을 받아서 화면에 표시한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;523&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TEOZN/btsK2Y3UDhV/yVSXkU9n7voKERkukhhde1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TEOZN/btsK2Y3UDhV/yVSXkU9n7voKERkukhhde1/img.png&quot; data-alt=&quot;출처 : https://prismic.io/blog/client-side-vs-server-side-rendering&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TEOZN/btsK2Y3UDhV/yVSXkU9n7voKERkukhhde1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTEOZN%2FbtsK2Y3UDhV%2FyVSXkU9n7voKERkukhhde1%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;648&quot; height=&quot;523&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;523&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://prismic.io/blog/client-side-vs-server-side-rendering&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;서버는 웹 페이지에 대한 요청을 받으면 필요한 데이터를 검색한 후에 해당 데이터를 HTML 템플릿에 붙인다.&lt;/li&gt;
&lt;li&gt;서버는 페이지에 대한 HTML 마크업을 생성하고 콘텐츠를 렌더링하고 필요한 스타일을 적용한다.&lt;/li&gt;
&lt;li&gt;페이지를 렌더링 한 후에 서버는 렌더링된 페이지를 브라우저에 전달한다.&lt;/li&gt;
&lt;li&gt;브라우저에 전달된 HTML 은 즉시 렌더링된다. (그러나 상호작용은 불가)&lt;/li&gt;
&lt;li&gt;브라우저가 JS 를 다운받고, 실행한다.&lt;/li&gt;
&lt;li&gt;JS 가 실행된 후에는 웹 페지는 상호작용이 가능하다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;장점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;필요한 부분의 HTML 과 JS 파일만 불러오므로 초기 로딩속도가 빠르다.&lt;/li&gt;
&lt;li&gt;SEO에 유리하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;단점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JS 파일이 모두 다운로드되어야 인터랙션이 가능해서 인터랙션까지의 시간이 걸린다.&lt;/li&gt;
&lt;li&gt;페이지 이동 시 깜박거림이 있고, 이동할 때 마다 서버에 요청을 하므로 서버 비용이 증가하고 느려질 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;CSR(Client Side Rendering)&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;클라이언트 사이드 렌더링은 HTML&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;644&quot; data-origin-height=&quot;524&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oBvMO/btsK2XKKkFC/a3k4iXK7Mjbrcyb86azcZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oBvMO/btsK2XKKkFC/a3k4iXK7Mjbrcyb86azcZ1/img.png&quot; data-alt=&quot;출처 : https://prismic.io/blog/client-side-vs-server-side-rendering&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oBvMO/btsK2XKKkFC/a3k4iXK7Mjbrcyb86azcZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoBvMO%2FbtsK2XKKkFC%2Fa3k4iXK7Mjbrcyb86azcZ1%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;644&quot; height=&quot;524&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;524&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://prismic.io/blog/client-side-vs-server-side-rendering&lt;/figcaption&gt;
&lt;/figure&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;서버가 웹 페이지에 대한 요청을 받으면 브라우저에 CSS 및 자바스크립트 링크가 포함된 빈 HTML 파일을 브라우저에 보낸다.&lt;/li&gt;
&lt;li&gt;브라우저는 HTML 을 파싱해서 DOM 트리를 구성한다.&lt;/li&gt;
&lt;li&gt;브라우저는 CSS 와 자바스크립트 리소스를 다운로드한다. 그런 다음 웹 페이지를 렌더링한다.&lt;/li&gt;
&lt;li&gt;브라우저는 자바스크립트 코드를 실행하여 애니메이션, 폼 검증, API로부터 가져온 데이터와 같은 동적 콘텐츠 및 상호작용 기능을 추가한다.&lt;/li&gt;
&lt;li&gt;버튼 클릭이나 폼 제출 같은 상호작용이 발생하면 브라우저는 페이지의 일부를 리렌더링하고 업데이트 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;장점&lt;/h4&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;변경이 필요한 부분만 요청하므로 서버의 비용이 SSR 에 비해 적다&lt;/li&gt;
&lt;li&gt;로딩이 완료되면 바로 상호작용을 할 수 있어서 동적 데이터 처리에 적합하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;단점&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;초기에 렌더링에 필요한 JS를 불어와야 하므로 로딩속도가 느리다.&lt;/li&gt;
&lt;li&gt;SEO 에 불리하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;SSR과 CSR 비교&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 77.2085%; height: 96px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 19.7286%; height: 20px;&quot;&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 27.752%; height: 20px;&quot;&gt;&lt;b&gt;SSR&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 29.3781%; height: 20px;&quot;&gt;&lt;b&gt;CSR&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 19.7286%; height: 20px;&quot;&gt;&lt;b&gt;초기 로딩 속도&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 27.752%; height: 20px;&quot;&gt;빠름&lt;/td&gt;
&lt;td style=&quot;width: 29.3781%; height: 20px;&quot;&gt;느림&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 19.7286%; height: 20px;&quot;&gt;&lt;b&gt;페이지 이동 속도&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 27.752%; height: 20px;&quot;&gt;느림&lt;/td&gt;
&lt;td style=&quot;width: 29.3781%; height: 20px;&quot;&gt;빠름&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 16px;&quot;&gt;
&lt;td style=&quot;width: 19.7286%; height: 16px;&quot;&gt;&lt;b&gt;SEO&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 27.752%; height: 16px;&quot;&gt;SEO 친화적&lt;/td&gt;
&lt;td style=&quot;width: 29.3781%; height: 16px;&quot;&gt;추가 설정 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 19.7286%; height: 20px;&quot;&gt;&lt;b&gt;서버 부하&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 27.752%; height: 20px;&quot;&gt;높음&lt;/td&gt;
&lt;td style=&quot;width: 29.3781%; height: 20px;&quot;&gt;낮음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;SSR&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;초기 로딩 속도가 중요한 페이지&lt;/li&gt;
&lt;li&gt;SEO 가 중요한 페이지(ex. 쇼핑몰)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CSR&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;SEO 와 초기 속도가 덜 중요한 페이지(ex. 사내 페이지 등...)&lt;/li&gt;
&lt;li&gt;SPA 로 구현해야하는 페이지&lt;/li&gt;
&lt;li&gt;사용자와의 상호작용이 많은 애플리케이션&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&amp;nbsp;번외 ( chat gpt 대답)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;gpt 한테 물어보니 이렇게 사례를 알려줬다. 참고하면 좋을 것 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8nNSz/btsK4ex03oN/3bz2NlMCwF6ci70qr0B700/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8nNSz/btsK4ex03oN/3bz2NlMCwF6ci70qr0B700/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8nNSz/btsK4ex03oN/3bz2NlMCwF6ci70qr0B700/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8nNSz%2FbtsK4ex03oN%2F3bz2NlMCwF6ci70qr0B700%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;700&quot; height=&quot;478&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;478&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 alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;563&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pKgFR/btsK1Yqr6EP/6w2DS7GK6iPq2BgzxtIwUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pKgFR/btsK1Yqr6EP/6w2DS7GK6iPq2BgzxtIwUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pKgFR/btsK1Yqr6EP/6w2DS7GK6iPq2BgzxtIwUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpKgFR%2FbtsK1Yqr6EP%2F6w2DS7GK6iPq2BgzxtIwUk%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;692&quot; height=&quot;563&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;563&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;711&quot; data-origin-height=&quot;363&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uN54O/btsK4wrE7ZF/6C2PBdMSXWrq6JR1DkNHD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uN54O/btsK4wrE7ZF/6C2PBdMSXWrq6JR1DkNHD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uN54O/btsK4wrE7ZF/6C2PBdMSXWrq6JR1DkNHD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuN54O%2FbtsK4wrE7ZF%2F6C2PBdMSXWrq6JR1DkNHD0%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;711&quot; height=&quot;363&quot; data-origin-width=&quot;711&quot; data-origin-height=&quot;363&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Reference&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;a href=&quot;https://kruschecompany.com/ssr-or-csr-for-progressive-web-app/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://kruschecompany.com/ssr-or-csr-for-progressive-web-app/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732980659132&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;SSR or CSR - what is better for Progressive Web App?&quot; data-og-description=&quot;Progressive Web Apps are on rising tide of popularity. In this article, we&amp;rsquo;ll talk a bit about transitioning to PWA and related issues&quot; data-og-host=&quot;kruschecompany.com&quot; data-og-source-url=&quot;https://kruschecompany.com/ssr-or-csr-for-progressive-web-app/&quot; data-og-url=&quot;https://kruschecompany.com/ssr-or-csr-for-progressive-web-app/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cW77xK/hyXDduGB4k/Ls401KlRyQbjttHcYJuyOk/img.jpg?width=620&amp;amp;height=324&amp;amp;face=0_0_620_324,https://scrap.kakaocdn.net/dn/b9tkl6/hyXGBgk94d/tbGAdKZu9YZnk2ngAHeuWk/img.jpg?width=1024&amp;amp;height=1024&amp;amp;face=0_0_1024_1024,https://scrap.kakaocdn.net/dn/bRxEaT/hyXGMPHEgh/egvSSZv3RVtyJ64h7oD5s1/img.jpg?width=1024&amp;amp;height=1024&amp;amp;face=0_0_1024_1024&quot;&gt;&lt;a href=&quot;https://kruschecompany.com/ssr-or-csr-for-progressive-web-app/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kruschecompany.com/ssr-or-csr-for-progressive-web-app/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cW77xK/hyXDduGB4k/Ls401KlRyQbjttHcYJuyOk/img.jpg?width=620&amp;amp;height=324&amp;amp;face=0_0_620_324,https://scrap.kakaocdn.net/dn/b9tkl6/hyXGBgk94d/tbGAdKZu9YZnk2ngAHeuWk/img.jpg?width=1024&amp;amp;height=1024&amp;amp;face=0_0_1024_1024,https://scrap.kakaocdn.net/dn/bRxEaT/hyXGMPHEgh/egvSSZv3RVtyJ64h7oD5s1/img.jpg?width=1024&amp;amp;height=1024&amp;amp;face=0_0_1024_1024');&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;SSR or CSR - what is better for Progressive Web App?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Progressive Web Apps are on rising tide of popularity. In this article, we&amp;rsquo;ll talk a bit about transitioning to PWA and related issues&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kruschecompany.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://prismic.io/blog/client-side-vs-server-side-rendering&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://prismic.io/blog/client-side-vs-server-side-rendering&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732980706512&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;Client-side Rendering (CSR) vs. Server-side Rendering (SSR)&quot; data-og-description=&quot;Choosing between client-side (CSR) vs. server-side rendering (SSR)? This guide breaks down the differences, pros/cons, and ideal use cases for each approach.&quot; data-og-host=&quot;prismic.io&quot; data-og-source-url=&quot;https://prismic.io/blog/client-side-vs-server-side-rendering&quot; data-og-url=&quot;https://prismic.io/blog/client-side-vs-server-side-rendering&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ugLFI/hyXGIGwS0f/KWSnvZG7TWmUIibeZwF5O1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/oqI3V/hyXDa5LRFQ/vcyp1ZUMF0DoJN1lLQRRK1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/codETK/hyXGLDgvks/kx14gQpO9hUsadDNKLAYgK/img.jpg?width=2000&amp;amp;height=1625&amp;amp;face=0_0_2000_1625&quot;&gt;&lt;a href=&quot;https://prismic.io/blog/client-side-vs-server-side-rendering&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://prismic.io/blog/client-side-vs-server-side-rendering&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ugLFI/hyXGIGwS0f/KWSnvZG7TWmUIibeZwF5O1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/oqI3V/hyXDa5LRFQ/vcyp1ZUMF0DoJN1lLQRRK1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/codETK/hyXGLDgvks/kx14gQpO9hUsadDNKLAYgK/img.jpg?width=2000&amp;amp;height=1625&amp;amp;face=0_0_2000_1625');&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;Client-side Rendering (CSR) vs. Server-side Rendering (SSR)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Choosing between client-side (CSR) vs. server-side rendering (SSR)? This guide breaks down the differences, pros/cons, and ideal use cases for each approach.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;prismic.io&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://velog.io/@vagabondms/%EA%B8%B0%EC%88%A0-%EC%8A%A4%ED%84%B0%EB%94%94-SSR%EA%B3%BC-CSR%EC%9D%98-%EC%B0%A8%EC%9D%B4&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@vagabondms/%EA%B8%B0%EC%88%A0-%EC%8A%A4%ED%84%B0%EB%94%94-SSR%EA%B3%BC-CSR%EC%9D%98-%EC%B0%A8%EC%9D%B4&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732981084695&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;[ 기술 스터디 ] SSR과 CSR의 차이&quot; data-og-description=&quot;자강두천&quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@vagabondms/%EA%B8%B0%EC%88%A0-%EC%8A%A4%ED%84%B0%EB%94%94-SSR%EA%B3%BC-CSR%EC%9D%98-%EC%B0%A8%EC%9D%B4&quot; data-og-url=&quot;https://velog.io/@vagabondms/기술-스터디-SSR과-CSR의-차이&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cdJCTZ/hyXGzQlQiJ/28hN3mE0lZsYy13KiNIzG0/img.jpg?width=259&amp;amp;height=194&amp;amp;face=0_0_259_194,https://scrap.kakaocdn.net/dn/b4dKaj/hyXGFiIIpj/UhwPFPgYsRxj2wK1nt9DLk/img.jpg?width=259&amp;amp;height=194&amp;amp;face=0_0_259_194&quot;&gt;&lt;a href=&quot;https://velog.io/@vagabondms/%EA%B8%B0%EC%88%A0-%EC%8A%A4%ED%84%B0%EB%94%94-SSR%EA%B3%BC-CSR%EC%9D%98-%EC%B0%A8%EC%9D%B4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@vagabondms/%EA%B8%B0%EC%88%A0-%EC%8A%A4%ED%84%B0%EB%94%94-SSR%EA%B3%BC-CSR%EC%9D%98-%EC%B0%A8%EC%9D%B4&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cdJCTZ/hyXGzQlQiJ/28hN3mE0lZsYy13KiNIzG0/img.jpg?width=259&amp;amp;height=194&amp;amp;face=0_0_259_194,https://scrap.kakaocdn.net/dn/b4dKaj/hyXGFiIIpj/UhwPFPgYsRxj2wK1nt9DLk/img.jpg?width=259&amp;amp;height=194&amp;amp;face=0_0_259_194');&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;[ 기술 스터디 ] SSR과 CSR의 차이&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;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>Study/CS</category>
      <category>csr</category>
      <category>SSR</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>다니니니</author>
      <guid isPermaLink="true">https://daddda3232.tistory.com/129</guid>
      <comments>https://daddda3232.tistory.com/129#entry129comment</comments>
      <pubDate>Wed, 27 Nov 2024 00:14:22 +0900</pubDate>
    </item>
    <item>
      <title>[React] React의 렌더링 프로세스(Virtual DOM)</title>
      <link>https://daddda3232.tistory.com/128</link>
      <description>&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;React 의 특징 중 하나는 Virtual DOM(가상돔) 를 가지고 있다는 것이다.&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;React 의 렌더링 프로세스&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Virtual DOM (가상 돔)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DOM 을 변경하는 작업이 많아질수록, 브라우저는 많은 연산을 수행해야 하고 이는 성능 저하로 이어질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React 같은 라이브러리는 가상 DOM 을 사용해서 이 문제를 해결한다.&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;Virtual DOM(가상 돔) 은 실제 DOM의 복사본으로, JS 객체 형태로 메모리 안에 저장된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상돔은 브라우저의 실제 DOM을 조작하기 전에 변경 사항을 미리 계산하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최소한의 작업만 실제 DOM 에 적용하도록 도와준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해서 성능을 최적화하고 빠른 UI 업데이트를 할 수 있게 해준다.&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;React 의 렌더링 프로세스&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;컴포넌트에서 반환하는 JSX 를 React Element 라는 객체를 생성한다.&lt;/li&gt;
&lt;li&gt;React Element 들을 모아서 Virtual DOM 을 생성한다.&lt;/li&gt;
&lt;li&gt;생성된 가상돔을 바탕으로 브라우저의 실제 DOM 에 컴포넌트를 렌더링한다&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;React 의 리렌더링 프로세스&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React 에서 상태(state) 나 props 가 변경될 때 컴포넌트를 다시 렌더링한다.&lt;/p&gt;
&lt;p 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;React 는 2단계를 거쳐서 화면에 UI 를 리렌더링한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Render Phase(렌더 단계) : 컴포넌트를 계산하고 업데이트 사항을 파악하는 단계&lt;/li&gt;
&lt;li&gt;Commit Phase(커밋 단계) : 변경사항을 실제 DOM 에 반영하는 단계&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Render Phase(렌더 단계)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트 컴포넌트가 렌더링 해야하는 UI 를 가상돔으로 변환하는 과정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리액트는 두 개의 가상돔을 가지고 렌더링을 진행한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째 가상 돔은 변경 이전의 내용을 담고 있고, 두 번째 가상 돔은 변경 이후에 보여질 내용을 담고 있다.&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;492&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crAdrd/btsK1HhDYJl/vWNcLpC6pPfa8mMygd6fHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crAdrd/btsK1HhDYJl/vWNcLpC6pPfa8mMygd6fHk/img.png&quot; data-alt=&quot;출처 : 코딩온 교안 자료&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crAdrd/btsK1HhDYJl/vWNcLpC6pPfa8mMygd6fHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcrAdrd%2FbtsK1HhDYJl%2FvWNcLpC6pPfa8mMygd6fHk%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;492&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;492&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;리액트는 변경 전 가상 돔과 변경 후 가상 돔의 차이점을 비교해서 어느 부분이 바뀌었는지 파악한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정을 &lt;b&gt;Diffing&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Commit Phase(커밋 단계)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변경된 Virtual DOM(가상돔) 을 Actual DOM 에 반영시키는 단계다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, 리액트는 Render Phase 에서 반영된 모든 변경사항을 Actual DOM 에 한번에 업데이트 한다.&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;h4 data-ke-size=&quot;size20&quot;&gt;렌더링 프로세스 정리&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;리액트는 두 개의 가상돔(변경 이전의 가상돔, 변경 후의 가상돔) 의 내용을 비교해서 동시에 발생하는 업데이트들을 모은다. (Diffing)&lt;/li&gt;
&lt;li&gt;Diffing 을 통해 변경 사항을 파악한 후, 반영된 모든 업데이트들을 실제 돔에 한번에 적용시킨다.&lt;br /&gt;(Reconsiliation)&lt;/li&gt;
&lt;/ol&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;React.Memo, useMemo, useCallback 같은 메모이제이션을 할 수 있는 리엑트 도구들을 사용해서&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;불필요한 리렌더링을 방지하고 적절한 최적화를 해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Reference&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=N7qlk_GQRJU&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=N7qlk_GQRJU&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=gc-kXt0tjTM&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=gc-kXt0tjTM&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/React</category>
      <category>REACT</category>
      <category>virtual dom</category>
      <category>가상돔</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>다니니니</author>
      <guid isPermaLink="true">https://daddda3232.tistory.com/128</guid>
      <comments>https://daddda3232.tistory.com/128#entry128comment</comments>
      <pubDate>Tue, 26 Nov 2024 10:52:04 +0900</pubDate>
    </item>
    <item>
      <title>브라우저의 렌더링 과정</title>
      <link>https://daddda3232.tistory.com/127</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;들어가며&lt;/h3&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이전에 면접 질문으로도 받았었고 프론트엔드 개발자 뿐만 아니라 웹 개발자라면 알아야 할 거라 생각해서 정리해보려 한다.&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;브라우저 렌더링&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;브라우저의 렌더링 순서&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;브라우저는 HTML, CSS, 자바스크립트, 이미지, 폰트 파일 등 렌더링에 필요한 리소스를 요청하고 서버로부터 응답받는다.&lt;/li&gt;
&lt;li&gt;서버로부터 HTML 문서를 전달받으면, 브라우저 엔진은 위에서 아래로 순차적으로 파싱하며 태그와 속성을 발견한다&lt;/li&gt;
&lt;li&gt;이 태그와 속성들을 트리 형태로 변환해서 메모리에 저장되는데, 이를 &lt;b&gt;DOM Tree&lt;/b&gt; 라고 한다.&lt;/li&gt;
&lt;li&gt;HTML 파싱 중 CSS 를 만나면 이를 파싱해서 &lt;b&gt;CSSOM Tree&lt;/b&gt; 로 변환한다.&lt;/li&gt;
&lt;li&gt;DOM tree 와 CSSOM tree 를 결합해서 &lt;b&gt;Render Tree&lt;/b&gt; 를 생성한다.&lt;/li&gt;
&lt;li&gt;렌더 트리를 기반으로 html 요소의 레이아웃(위치와 크기) 을 계산하고, 브라우저 화면에 html 요소를 페인팅한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;DOM 생성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DOM(Document Object Model) 은 웹 페이지의 구조를 표현한 객체 모델로, 노드로 이루어졌다.&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;다음과 같은 html 문서가 있다고 했을 때&lt;/p&gt;
&lt;pre id=&quot;code_1732544794991&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&amp;gt;
    &amp;lt;title&amp;gt;Document&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;ul&amp;gt;
        &amp;lt;li id=&quot;apple&quot;&amp;gt;Apple&amp;lt;/li&amp;gt;
        &amp;lt;li id=&quot;banana&quot;&amp;gt;Banana&amp;lt;/li&amp;gt;
        &amp;lt;li id=&quot;orange&quot;&amp;gt;Orange&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
    &amp;lt;script src=&quot;app.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&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;브라우저 엔진은 다음 과정을 거쳐서 html 문서를 파싱해서 DOM을 생성한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;547&quot; data-origin-height=&quot;498&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QHZCL/btsKVtDKNsX/FfTbvfr2EFs5IeufkfsoNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QHZCL/btsKVtDKNsX/FfTbvfr2EFs5IeufkfsoNk/img.png&quot; data-alt=&quot;HTML 파싱 / 출처 : 모던 자바스크립트 Deep Dive&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QHZCL/btsKVtDKNsX/FfTbvfr2EFs5IeufkfsoNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQHZCL%2FbtsKVtDKNsX%2FFfTbvfr2EFs5IeufkfsoNk%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;547&quot; height=&quot;498&quot; data-origin-width=&quot;547&quot; data-origin-height=&quot;498&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;HTML 파싱 / 출처 : 모던 자바스크립트 Deep Dive&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;서버에 있는 html 파일이 브라우저 요청에 의해 응답됨&lt;br /&gt;서버는 브라우저가 요청한 html 파일을 바이트(2진수) 형태로 응답(바이트화)&lt;/li&gt;
&lt;li&gt;바이트 형태로 응답받은 html 문서를 meta 태그의 charset 어트리뷰트에 지정된 인코딩 방식(ex. UTF-8)을 기준으로&lt;br /&gt;문자열로 변환(캐릭터화)&lt;/li&gt;
&lt;li&gt;문자열로 변환된 html 문서를 읽어들여서 &lt;b&gt;토큰&lt;/b&gt;화 시킴&lt;/li&gt;
&lt;li&gt;각 토큰들을 객체로 변환해서 &lt;b&gt;노드&lt;/b&gt;들을 생성&lt;br /&gt;(토큰 내용에 따라 문서 노드, 요소 노드, 어트리뷰트 노드, 텍스트 노트가 생성됨)&lt;/li&gt;
&lt;li&gt;만들어낸 노드들을 관계화 시켜서(예. 부모-자식 관계 설정) 트리 자료 구조로 구성함.&lt;br /&gt;이 트리 자료구조를 &lt;b&gt;DOM(Document Object Model)&lt;/b&gt; 이라 함&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;937&quot; data-origin-height=&quot;471&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HT6hh/btsKU9FshRR/ea3KoQ0FUPEHY6nj1VcNO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HT6hh/btsKU9FshRR/ea3KoQ0FUPEHY6nj1VcNO0/img.png&quot; data-alt=&quot;DOM 구조 / 출처 : 모던 자바스크립트 Deep Dive&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HT6hh/btsKU9FshRR/ea3KoQ0FUPEHY6nj1VcNO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHT6hh%2FbtsKU9FshRR%2Fea3KoQ0FUPEHY6nj1VcNO0%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;937&quot; height=&quot;471&quot; data-origin-width=&quot;937&quot; data-origin-height=&quot;471&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;DOM 구조 / 출처 : 모던 자바스크립트 Deep Dive&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;CSSOM 생성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;렌더링 엔진은 DOM 을 생성하다가 CSS 를 로드하는 link 태그나 style 태그를 만나면 DOM 생성을 일시 중단한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 link 태그를 만난다면 href 에 어트리뷰트 지정된 CSS 파일을 서버에 요청한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로드한 CSS 파일이나 style 태그 내의 CSS 를&amp;nbsp; HTML 과 동일한 파싱 과정(바이트 -&amp;gt; 문자 -&amp;gt; 토큰 -&amp;gt; 노드 -&amp;gt; CSSOM) 을 거쳐서 CSSOM(CSS Object Model) 을 생성한다.&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;CSS 파싱을 완료하면 HTML 파싱이 중단된 지점부터 다시 HTML을 파싱하기 시작하여 DOM 생성을 한다.&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;위의 html 파일에 지정된 style.css 코드가 다음과 같다고 가정해보자&lt;/p&gt;
&lt;pre id=&quot;code_1732548789560&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;body {
   font-size : 18px;
}

ul {
   list-style-type : none;
}&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;CSSOM은 CSS 상속을 반영해서 생성된다.&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;773&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bW6jJE/btsKXrxnHmS/pZcHK4ZNwxJuuqPzlSTZq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bW6jJE/btsKXrxnHmS/pZcHK4ZNwxJuuqPzlSTZq1/img.png&quot; data-alt=&quot;CSSOM / 출처 : 모던 자바스크립트 Deep Dive&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bW6jJE/btsKXrxnHmS/pZcHK4ZNwxJuuqPzlSTZq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbW6jJE%2FbtsKXrxnHmS%2FpZcHK4ZNwxJuuqPzlSTZq1%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;773&quot; height=&quot;360&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;360&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;CSSOM / 출처 : 모던 자바스크립트 Deep Dive&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;h4 data-ke-size=&quot;size20&quot;&gt;렌더 트리 생성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DOM 트리와 CSSOM 트리를 결합해서 렌더 트리(Render Tree) 를 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 사이트를 그리기 위한 최종 설계도라고 생각하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, body 태그 내에 있는 노드들과 CSS 에 의해 표시되는 노드들만 포함해서 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(head 태그 내의 meta 태그 등과 CSS 에 의해 비표시 되는 것 display : none 표시 되는 노드들은 포함하지 않는다.)&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;/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;이 계산은 화면의 뷰포트(viewport) 크기와 같은 정보에 의존한다.&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;레이아웃이 완료되면, 브라우저는 각 요소를 실제로 화면에 그리는 작업을 한다.&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;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;628&quot; data-origin-height=&quot;150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHAWbn/btsKVdgN5RF/P0DJyqrokvKIBLPaQsLAg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHAWbn/btsKVdgN5RF/P0DJyqrokvKIBLPaQsLAg0/img.png&quot; data-alt=&quot;렌더트리와 레이아웃, 페인트 / 출처 : 모던 자바스크립트 Deep Dive&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHAWbn/btsKVdgN5RF/P0DJyqrokvKIBLPaQsLAg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHAWbn%2FbtsKVdgN5RF%2FP0DJyqrokvKIBLPaQsLAg0%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;628&quot; height=&quot;150&quot; data-origin-width=&quot;628&quot; data-origin-height=&quot;150&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;렌더트리와 레이아웃, 페인트 / 출처 : 모던 자바스크립트 Deep Dive&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;다음의 경우 레이아웃 계산과 페인팅이 재차 실행된다.&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;li&gt;HTML 요소의 레이아웃(위치, 크기)에 변경을 발생시키는 width/height, margin, padding, border, display, position, top/right/bottom/left 등의 스타일 변경&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 변경된 DOM 트리와 CSSOM 트리는 다시 렌더트리로 결합되고 변경된 렌더 트리를 기반으로 레이아웃과 페인트 과정을 다시 거친다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 리플로우(reflow), 리페인트(repaint) 라 한다.&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;리플로우(reflow)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저가 페이지의 레이아웃을 다시 계산하는 과정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드의 추가나 삭제, 요소의 크기나 위치 변경, 윈도우 리사이징 등 레이아웃에 영향을 주는 변경이 발생한 경우애 한하여 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; 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;페이지 초기 렌더링 시(최초 layout)&lt;/li&gt;
&lt;li&gt;윈도우 리사이징(viewport 크기 변경 시)&lt;/li&gt;
&lt;li&gt;노드 추가 또는 제거&lt;/li&gt;
&lt;li&gt;요소의 위치, 크기 변경(left, top, margin, padding, border, width, heigth)&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;리페인트(repaint)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요소의 모양이나 스타일이 변경될 때 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요소의 레이아웃은 그대로지만 색상이나 배경 등의 스타일만 변경되는 경우에 해당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 브라우저는 요소의 모양이나 색상만 다시 그리면 되기 때문에 리플로우보다는 비용이 덜 든다.&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;이 둘을 잘 이해하고 관리하면 성능 최적화에 도움이 된다.&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;리플로우(reflow) 를 유발하는 CSS 속성 사용 최소화&lt;br /&gt;width, height, margin, padding, border 등의 속성은 요소의 레이아웃을 다시 계산하므로 가능한 미리&lt;br /&gt;CSS 에서 스타일을 설정해서 초기 로드 시에만 계산이 이루어지도록 하고 이후에는 변경을 최소화하는 것이 좋다&lt;/li&gt;
&lt;li&gt;CSS 애니메이션 최적화&lt;br /&gt;애니메이션에 transform 과 opacity 속성을 사용하는 것이 좋다. 이 두 속성은 리페인트만 발생시킨다.&lt;br /&gt;위에서 말했다시피 width, height, left, top 등은 리플로우를 발생시키므로&lt;br /&gt;transform 의 속성을 이용하는 것이 성능에 유리하다&amp;nbsp;&lt;/li&gt;
&lt;li&gt;will-change 속성 사용&lt;br /&gt;CSS 의 will-change 속성을 사용해서 브라우저에 특정 요소가 변경될 것이라고 알려줄 수 있다.&lt;br /&gt;미리 GPU 에 요소를 준비하게 해서 리플로우 및 리페인트에 미치는 영향을 줄일 수 있다.&lt;br /&gt;하지만 너무 자주 사용하면 메모리 낭비가 일어나므로 필요한 요소에만 적용하는 것이 좋다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;자바스크립트 파싱에 의한 HTML 파싱 중단&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML 파싱 중간에 script 태그를 만나면 브라우저는 해당 스크립트를 로드하고 실행하기 위해 HTML 파싱을 일시 중단한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, script 태그에 의해 블로킹이 발생할 수 있다.&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;이로 인해서 파싱 속도가 저하되고, DOM 트리가 완성되기 전에 자바스크립트가 DOM 을 조작하면 에러가 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 HTML 문서 내에서 script 태그의 위치가 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1732551122114&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&amp;gt;
    &amp;lt;title&amp;gt;Document&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;ul&amp;gt;
        &amp;lt;li id=&quot;apple&quot;&amp;gt;Apple&amp;lt;/li&amp;gt;
        &amp;lt;li id=&quot;banana&quot;&amp;gt;Banana&amp;lt;/li&amp;gt;
        &amp;lt;li id=&quot;orange&quot;&amp;gt;Orange&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
    &amp;lt;script src=&quot;app.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&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;위의 코드 예제의 경우 sciprt 태그 즉, 자바스크립트 코드는 DOM 트리가 완성된 후에 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 자바스크립트가 DOM을 조작할 때 DOM트리가 완성되지 않아서 생기는 오류가 생기지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 위의 코드는 자바스크립트가 실행되기 이전에 DOM 생성이 완료되어 랜더링되므로 페이지 로딩 시간이 단축된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1732551251383&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&amp;gt;
    &amp;lt;title&amp;gt;Document&amp;lt;/title&amp;gt;
    &amp;lt;script src=&quot;app.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;ul&amp;gt;
        &amp;lt;li id=&quot;apple&quot;&amp;gt;Apple&amp;lt;/li&amp;gt;
        &amp;lt;li id=&quot;banana&quot;&amp;gt;Banana&amp;lt;/li&amp;gt;
        &amp;lt;li id=&quot;orange&quot;&amp;gt;Orange&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&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;그러나 위의 코드는 script 태그가 위에 존재하기 때문에 블로킹이 일어나서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;DOM조작 시 오류가 날 수 있다.&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;script 태그의 async, defer 속성&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트 파싱에 의한 DOM 생성 중단을 방지하기 위해 HTML5 부터 async와 defer 속성이 script 태그에 추가되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두 속성은 외부 스크립트를 로드할 경우에만 사용할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1732551549803&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&amp;gt;
    &amp;lt;title&amp;gt;Document&amp;lt;/title&amp;gt;
    &amp;lt;script defer src=&quot;app.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;ul&amp;gt;
        &amp;lt;li id=&quot;apple&quot;&amp;gt;Apple&amp;lt;/li&amp;gt;
        &amp;lt;li id=&quot;banana&quot;&amp;gt;Banana&amp;lt;/li&amp;gt;
        &amp;lt;li id=&quot;orange&quot;&amp;gt;Orange&amp;lt;/li&amp;gt;
    &amp;lt;/ul&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&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;위의 코드처럼 script 태그에 defer (혹은 async ) 속성을 써주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 속성들을 사용하면 HTML 파싱과 외부 자바스크립트 파일의 로드가 비동기적으로 동시에 진행된다.&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;async&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;여러 개의 script 에 async 속성을 지정하면 태그의 순서와 상관없이 로드가 완료된 자바스크립트부터 실행한다.&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;defer&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바스크립트 파싱과 실행은 HTML 파싱이 완료된 직후, 즉 DOM 생성이 완료된 직후에 진행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 DOM 생성이 완료된 이후 실행되어야 할 자바스크립트에 유용하다.&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;async 는 스크립트 로드 순서에 상관없이 실행되는 경우에 적합하고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;defer는 스크립트 실행 순서가 중요할 때 적합하다.&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;Reference&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=Mqh13dNI8jc&amp;amp;t=646s&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=Mqh13dNI8jc&amp;amp;t=646s&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=R23JmhbPnVo&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=R23JmhbPnVo&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;모던 자바스크립트 Deep Dive&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;http://product.kyobobook.co.kr/detail/S000001766445?LINK=NVB&amp;amp;NaPm=ct%3Dlwt20us8%7Cci%3D3eeae87413d188962c2189bfc03af972cec288fd%7Ctr%3Dboksl1%7Csn%3D5342564%7Chk%3D0a86971807241e21311b2f82ad997d61e4c24ab4&quot;&gt;http://product.kyobobook.co.kr/detail/S000001766445?LINK=NVB&amp;amp;NaPm=ct%3Dlwt20us8%7Cci%3D3eeae87413d188962c2189bfc03af972cec288fd%7Ctr%3Dboksl1%7Csn%3D5342564%7Chk%3D0a86971807241e21311b2f82ad997d61e4c24ab4&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732529811661&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;모던 자바스크립트 Deep Dive | 이웅모 - 교보문고&quot; data-og-description=&quot;모던 자바스크립트 Deep Dive | 269개의 그림과 원리를 파헤치는 설명으로 &amp;lsquo;자바스크립트의 기본 개념과 동작 원리&amp;rsquo;를 이해하자!웹페이지의 단순한 보조 기능을 처리하기 위한 제한적인 용도로 &quot; data-og-host=&quot;product.kyobobook.co.kr&quot; data-og-source-url=&quot;http://product.kyobobook.co.kr/detail/S000001766445?LINK=NVB&amp;amp;NaPm=ct%3Dlwt20us8%7Cci%3D3eeae87413d188962c2189bfc03af972cec288fd%7Ctr%3Dboksl1%7Csn%3D5342564%7Chk%3D0a86971807241e21311b2f82ad997d61e4c24ab4&quot; data-og-url=&quot;https://product.kyobobook.co.kr/detail/S000001766445&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/1AKDl/hyXDe62ID1/h6eKN0gsiK0g11Zh9oHg8k/img.jpg?width=458&amp;amp;height=559&amp;amp;face=0_0_458_559,https://scrap.kakaocdn.net/dn/Hj7sv/hyXC86OMKh/INiLjxN63YkUJadpQIv4k0/img.jpg?width=458&amp;amp;height=559&amp;amp;face=0_0_458_559,https://scrap.kakaocdn.net/dn/2zmGH/hyXDaQ67V9/KUFgjVJnKGeAEHvtJSmVvk/img.png?width=335&amp;amp;height=335&amp;amp;face=0_0_335_335&quot;&gt;&lt;a href=&quot;http://product.kyobobook.co.kr/detail/S000001766445?LINK=NVB&amp;amp;NaPm=ct%3Dlwt20us8%7Cci%3D3eeae87413d188962c2189bfc03af972cec288fd%7Ctr%3Dboksl1%7Csn%3D5342564%7Chk%3D0a86971807241e21311b2f82ad997d61e4c24ab4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;http://product.kyobobook.co.kr/detail/S000001766445?LINK=NVB&amp;amp;NaPm=ct%3Dlwt20us8%7Cci%3D3eeae87413d188962c2189bfc03af972cec288fd%7Ctr%3Dboksl1%7Csn%3D5342564%7Chk%3D0a86971807241e21311b2f82ad997d61e4c24ab4&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/1AKDl/hyXDe62ID1/h6eKN0gsiK0g11Zh9oHg8k/img.jpg?width=458&amp;amp;height=559&amp;amp;face=0_0_458_559,https://scrap.kakaocdn.net/dn/Hj7sv/hyXC86OMKh/INiLjxN63YkUJadpQIv4k0/img.jpg?width=458&amp;amp;height=559&amp;amp;face=0_0_458_559,https://scrap.kakaocdn.net/dn/2zmGH/hyXDaQ67V9/KUFgjVJnKGeAEHvtJSmVvk/img.png?width=335&amp;amp;height=335&amp;amp;face=0_0_335_335');&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;모던 자바스크립트 Deep Dive | 이웅모 - 교보문고&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;모던 자바스크립트 Deep Dive | 269개의 그림과 원리를 파헤치는 설명으로 &amp;lsquo;자바스크립트의 기본 개념과 동작 원리&amp;rsquo;를 이해하자!웹페이지의 단순한 보조 기능을 처리하기 위한 제한적인 용도로&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;product.kyobobook.co.kr&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 style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #222222; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://poiemaweb.com/js-dom&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://poiemaweb.com/js-dom&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732544602686&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;DOM | PoiemaWeb&quot; data-og-description=&quot;브라우저는 웹 문서(HTML, XML, SVG)를 로드한 후, 파싱하여 DOM(문서 객체 모델. Document Object Model)을 생성한다. 파일로 만들어져 있는 웹 문서를 브라우저에 렌더링하기 위해서는 웹 문서를 브라우저&quot; data-og-host=&quot;poiemaweb.com&quot; data-og-source-url=&quot;https://poiemaweb.com/js-dom&quot; data-og-url=&quot;https://poiemaweb.com/js-dom&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dp6hk5/hyXDelJSOJ/4cUHiNkAMOjBErjULyCFY0/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/bJhQ8E/hyXC8ThGuO/I2IV187FfeRSt0gSzrq6x0/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/nIyeG/hyXC7Urry3/Vy6C7i3ehz3YYmwE8IbzO0/img.png?width=2028&amp;amp;height=1202&amp;amp;face=0_0_2028_1202&quot;&gt;&lt;a href=&quot;https://poiemaweb.com/js-dom&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://poiemaweb.com/js-dom&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dp6hk5/hyXDelJSOJ/4cUHiNkAMOjBErjULyCFY0/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/bJhQ8E/hyXC8ThGuO/I2IV187FfeRSt0gSzrq6x0/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/nIyeG/hyXC7Urry3/Vy6C7i3ehz3YYmwE8IbzO0/img.png?width=2028&amp;amp;height=1202&amp;amp;face=0_0_2028_1202');&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;DOM | PoiemaWeb&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;브라우저는 웹 문서(HTML, XML, SVG)를 로드한 후, 파싱하여 DOM(문서 객체 모델. Document Object Model)을 생성한다. 파일로 만들어져 있는 웹 문서를 브라우저에 렌더링하기 위해서는 웹 문서를 브라우저&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;poiemaweb.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.maeil-mail.kr/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.maeil-mail.kr/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732550418990&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;매일메일 - 기술 면접 질문 구독 서비스&quot; data-og-description=&quot;기술 면접 질문을 매일매일 메일로 보내드릴게요!&quot; data-og-host=&quot;www.maeil-mail.kr&quot; data-og-source-url=&quot;https://www.maeil-mail.kr/&quot; data-og-url=&quot;https://www.maeil-mail.kr&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/f6IsG/hyXDhQkmwI/3eeUtFzVBGYyfA9mQMKfDk/img.png?width=2077&amp;amp;height=1159&amp;amp;face=0_0_2077_1159,https://scrap.kakaocdn.net/dn/Z4HhQ/hyXDgDR7he/sxzQRLP3gE2wV9kwxC10MK/img.png?width=2077&amp;amp;height=1159&amp;amp;face=0_0_2077_1159&quot;&gt;&lt;a href=&quot;https://www.maeil-mail.kr/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.maeil-mail.kr/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/f6IsG/hyXDhQkmwI/3eeUtFzVBGYyfA9mQMKfDk/img.png?width=2077&amp;amp;height=1159&amp;amp;face=0_0_2077_1159,https://scrap.kakaocdn.net/dn/Z4HhQ/hyXDgDR7he/sxzQRLP3gE2wV9kwxC10MK/img.png?width=2077&amp;amp;height=1159&amp;amp;face=0_0_2077_1159');&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.maeil-mail.kr&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>Study/CS</category>
      <category>브라우저</category>
      <category>브라우저 렌더링</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>다니니니</author>
      <guid isPermaLink="true">https://daddda3232.tistory.com/127</guid>
      <comments>https://daddda3232.tistory.com/127#entry127comment</comments>
      <pubDate>Mon, 25 Nov 2024 19:17:00 +0900</pubDate>
    </item>
    <item>
      <title>로컬 스토리지(Local Storage)와 세션 스토리지(Session Storage)</title>
      <link>https://daddda3232.tistory.com/126</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목을 입력해주세요_-001 (39).png&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;891&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bf8Wxo/btsKUw7GEYC/4nBPJt7DVedNJcnTf9d320/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bf8Wxo/btsKUw7GEYC/4nBPJt7DVedNJcnTf9d320/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bf8Wxo/btsKUw7GEYC/4nBPJt7DVedNJcnTf9d320/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbf8Wxo%2FbtsKUw7GEYC%2F4nBPJt7DVedNJcnTf9d320%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;600&quot; height=&quot;424&quot; data-filename=&quot;제목을 입력해주세요_-001 (39).png&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;891&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;로컬 스토리지와 세션 스토리지는 HTML5 부터 추가된 웹 스토리지의 종류로 서버가 아니라 클라이언트에서 데이터를 저장할 수 있다.&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;h3 data-ke-size=&quot;size23&quot;&gt;웹 스토리지(Web Storage)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 스토리지(Web Storage) 는 브라우저가 제공하는 클라이언트 측 저장소다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터는 키-값(key-value) 쌍으로 저장하며, 문자열 형태로 저장된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 저장 시 : JSON.stringify(배열/객체)&lt;/li&gt;
&lt;li&gt;데이터 사용 시 : JSON.parse(문자열배열/객체)&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 스토리지는 쿠키와 유사하지만 용량이 훨씬 크다.(쿠키 : 4KB / 웹 스토리지 : 약 5MB)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버와 독립적으로 브라우저에 데이터를 저장할 수 있는 기능을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 모든 HTTP 요청마다 전송되어 성능을 저하를 일으킬 수 있는 쿠키와 달리 서버에 전송되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 스토리지는 클라이언트 저장소이므로 쉽게 접근 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 민감한 데이터를 저장하기는 부적절하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;민감한 데이터는 암호화하거나 서버에만 관리하는 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 스토리지의 종류에는 로컬 스토리지와 세션 스토리지가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;로컬 스토리지(Local Storage)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로컬 스토리지는 데이터를 명시적으로 삭제하지 않는 이상 브라우저를 닫아도 데이터가 유지된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 PC, 같은 브라우저 일 경우 데이터가 계속 유지된다는 뜻이다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사용 메서드&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;값 설정 : setItem(key, value)&lt;/li&gt;
&lt;li&gt;값 읽기 : getItem(key)&lt;/li&gt;
&lt;li&gt;전체 지우기 : clear()&lt;/li&gt;
&lt;li&gt;키 번호 읽기 : ket(index)&lt;/li&gt;
&lt;li&gt;개별 항목 삭제 : removeItem(key)&lt;/li&gt;
&lt;li&gt;개수 : length&lt;/li&gt;
&lt;/ul&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;로컬 스토리지를 활용해서 서버에 저장하지 않고 클라이언트에서만 todo list 를 구현해보고자 한다.&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;index.html&lt;/p&gt;
&lt;pre id=&quot;code_1732525115353&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot; /&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&amp;gt;
    &amp;lt;title&amp;gt;Document&amp;lt;/title&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Todo&amp;lt;/h1&amp;gt;
    &amp;lt;form&amp;gt;
      &amp;lt;label for=&quot;todo&quot;&amp;gt;할 일&amp;lt;/label&amp;gt;
      &amp;lt;input type=&quot;text&quot; id=&quot;todo&quot; name=&quot;todo&quot; /&amp;gt;
      &amp;lt;button type=&quot;submit&quot;&amp;gt;등록&amp;lt;/button&amp;gt;
      &amp;lt;button type=&quot;button&quot; class=&quot;all-delete&quot;&amp;gt;댓글 모두 지우기&amp;lt;/button&amp;gt;
    &amp;lt;/form&amp;gt;
    &amp;lt;ul class=&quot;todo-list&quot;&amp;gt;&amp;lt;/ul&amp;gt;
  &amp;lt;/body&amp;gt;
  &amp;lt;script src=&quot;./index.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/html&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;index.js&lt;/p&gt;
&lt;pre id=&quot;code_1732525139098&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 대상요소 잡기
const form = document.querySelector(&quot;form&quot;);
const todoInput = form.querySelector(&quot;#todo&quot;);
const todoList = document.querySelector(&quot;.todo-list&quot;);
const allDeleteBtn = document.querySelector(&quot;.all-delete&quot;);

const TODO = &quot;todo&quot;;
let todoObj = [];

// 폼요소 제출 이벤트
form.addEventListener(&quot;submit&quot;, handleSubmit);

let savedTodo = localStorage.getItem(TODO);

// 폼요소 제출 이벤트 함수
function handleSubmit(event) {
  // 이벤트 기본 기능 막기
  event.preventDefault();

  // 빈값인지 확인
  if (todoInput.value.trim() == &quot;&quot;) {
    alert(&quot;내용을 입력해주세요&quot;);
    return;
  }

  // 로컬스토리지에 내용 저장
  handleSave(todoInput.value);
  todoInput.value = &quot;&quot;;
  todoInput.focus();
}

// 로컬스토리지 댓글 내용 저장
function handleSave(content) {
  // 새로운 객체 생성
  let newTodo = {
    text: content,
    id: Date.now(),
  };

  // 새로 추가된 내용 배열에 추가
  todoObj.push(newTodo);
  // li추가 함수
  todoWrite(newTodo);
  // json형태로 로컬스토리지에 저장
  todoLocalSave();
}

function todoLocalSave() {
  localStorage.setItem(TODO, JSON.stringify(todoObj));
}

// li에 댓글내용 입력을 위한 함수
function todoWrite(comment) {
  const li = document.createElement(&quot;li&quot;);
  li.id = comment.id;
  const span = document.createElement(&quot;span&quot;);
  span.innerText = comment.text;
  const button = document.createElement(&quot;button&quot;);
  button.innerText = &quot;❌&quot;;
  button.addEventListener(&quot;click&quot;, deleteTodo);
  li.appendChild(span);
  li.appendChild(button);
  todoList.appendChild(li);
}

// 로컬스토리지에 있던거 화면에 출력하기
if (savedTodo !== null) {
  const parsedTodo = JSON.parse(savedTodo);
  todoObj = parsedTodo;
  todoObj.forEach(todoWrite);
}

// 모두 지우기
allDeleteBtn.addEventListener(&quot;click&quot;, deleteAll);

function deleteAll() {
  localStorage.clear();
  const li = todoList.querySelectorAll(&quot;li&quot;);
  li.forEach((li) =&amp;gt; li.remove())
}

// todo 지우기
function deleteTodo(event) {
  const li = event.target.parentElement;
  todoObj = todoObj.filter((todo) =&amp;gt; todo.id !== parseInt(li.id));
  li.remove();
  todoLocalSave();
}&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&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;todo.gif&quot; data-origin-width=&quot;437&quot; data-origin-height=&quot;349&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cRU5Mz/btsKXgo2c3M/qAgdeJbe6TpauqcJvLK5Ok/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cRU5Mz/btsKXgo2c3M/qAgdeJbe6TpauqcJvLK5Ok/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cRU5Mz/btsKXgo2c3M/qAgdeJbe6TpauqcJvLK5Ok/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cRU5Mz/btsKXgo2c3M/qAgdeJbe6TpauqcJvLK5Ok/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;437&quot; height=&quot;349&quot; data-filename=&quot;todo.gif&quot; data-origin-width=&quot;437&quot; data-origin-height=&quot;349&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;855&quot; data-origin-height=&quot;579&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/X7IwI/btsKWhIMOqA/omKNUFFeKtS98YK3r19Ci0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/X7IwI/btsKWhIMOqA/omKNUFFeKtS98YK3r19Ci0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/X7IwI/btsKWhIMOqA/omKNUFFeKtS98YK3r19Ci0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FX7IwI%2FbtsKWhIMOqA%2FomKNUFFeKtS98YK3r19Ci0%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;855&quot; height=&quot;579&quot; data-origin-width=&quot;855&quot; data-origin-height=&quot;579&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;새로고침을 하거나 브라우저를 닫았다가 켜도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작성했던 todo 내용을 지우지 않는 한 그대로 남아있어서 다시 불러올 수 있다.&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;장기적으로 유지해야하는 데이터를 저장하는 편이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 사용자 설정이나, 캐싱 정보 등이 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;세션 스토리지(Session Storage)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세션 스토리지는 로컬 스토리지와는 달리 브라우저 창이 닫히면 데이터도 사라진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용하는 메서드는 로컬 스토리지와 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;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;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 15.8914%;&quot;&gt;&lt;b&gt;항목&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.5426%;&quot;&gt;&lt;b&gt;로컬 스토리지&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.5659%;&quot;&gt;&lt;b&gt;세션 스토리지&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 15.8914%;&quot;&gt;&lt;b&gt;데이터 지속성&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.5426%;&quot;&gt;브라우저를 닫아도 지속&lt;br /&gt;(명시적으로 지우거나 캐시 데이터를 지우지 않는 이상 지속됨)&lt;/td&gt;
&lt;td style=&quot;width: 43.5659%;&quot;&gt;브라우저 창을 닫으면 데이터 삭제됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 15.8914%;&quot;&gt;&lt;b&gt;사용 목적&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.5426%;&quot;&gt;장기적으로 유지해야 할 데이터&lt;br /&gt;(예 : 사용자 설정, 캐싱 데이터)&lt;/td&gt;
&lt;td style=&quot;width: 43.5659%;&quot;&gt;일회성 또는 세션 동안만 필요한 데이터&lt;br /&gt;(예 : 폼 임시 저장)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 15.8914%;&quot;&gt;&lt;b&gt;삭제 시점&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.5426%;&quot;&gt;명시적으로 삭제하거나 브라우저 캐시 삭제 시&lt;/td&gt;
&lt;td style=&quot;width: 43.5659%;&quot;&gt;브라우저 창을 닫으면 삭제&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 15.8914%;&quot;&gt;&lt;b&gt;활용 사례&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 40.5426%;&quot;&gt;사용자 설정, 캐시 정보 등&lt;/td&gt;
&lt;td style=&quot;width: 43.5659%;&quot;&gt;인증 세션 데이터, 임시 폼 데이터 등&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;Reference&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%9B%B9_%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%A7%80&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ko.wikipedia.org/wiki/%EC%9B%B9_%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%A7%80&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732461794768&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;웹 스토리지 - 위키백과, 우리 모두의 백과사전&quot; data-og-description=&quot;위키백과, 우리 모두의 백과사전.&quot; data-og-host=&quot;ko.wikipedia.org&quot; data-og-source-url=&quot;https://ko.wikipedia.org/wiki/%EC%9B%B9_%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%A7%80&quot; data-og-url=&quot;https://ko.wikipedia.org/wiki/%EC%9B%B9_%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%A7%80&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/%EC%9B%B9_%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%A7%80&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.wikipedia.org/wiki/%EC%9B%B9_%EC%8A%A4%ED%86%A0%EB%A6%AC%EC%A7%80&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;웹 스토리지 - 위키백과, 우리 모두의 백과사전&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;ko.wikipedia.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://developer.mozilla.org/ko/docs/Web/API/Web_Storage_API&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer.mozilla.org/ko/docs/Web/API/Web_Storage_API&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732461801157&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;Web Storage API - Web API | MDN&quot; data-og-description=&quot;Web Storage API는 브라우저에서 키/값 쌍을 쿠키보다 훨씬 직관적으로 저장할 수 있는 방법을 제공합니다.&quot; data-og-host=&quot;developer.mozilla.org&quot; data-og-source-url=&quot;https://developer.mozilla.org/ko/docs/Web/API/Web_Storage_API&quot; data-og-url=&quot;https://developer.mozilla.org/ko/docs/Web/API/Web_Storage_API&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/drJ1HO/hyXDlkyp4t/3hzAztZKgNNJYbjDE4xFXk/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/API/Web_Storage_API&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.mozilla.org/ko/docs/Web/API/Web_Storage_API&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/drJ1HO/hyXDlkyp4t/3hzAztZKgNNJYbjDE4xFXk/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&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;Web Storage API - Web API | MDN&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Web Storage API는 브라우저에서 키/값 쌍을 쿠키보다 훨씬 직관적으로 저장할 수 있는 방법을 제공합니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.mozilla.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://www.w3schools.com/js/js_api_web_storage.asp&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.w3schools.com/js/js_api_web_storage.asp&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732461802722&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;W3Schools.com&quot; data-og-description=&quot;W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.&quot; data-og-host=&quot;www.w3schools.com&quot; data-og-source-url=&quot;https://www.w3schools.com/js/js_api_web_storage.asp&quot; data-og-url=&quot;https://www.w3schools.com/js/js_api_web_storage.asp&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/TV01s/hyXC8yJK9C/hb5rFl02TAhnkOXQyaCAy1/img.png?width=436&amp;amp;height=228&amp;amp;face=0_0_436_228,https://scrap.kakaocdn.net/dn/BPRM1/hyXDmX3i6p/6PkeQdKXhyxLEKNjThtTd1/img.png?width=300&amp;amp;height=300&amp;amp;face=0_0_300_300&quot;&gt;&lt;a href=&quot;https://www.w3schools.com/js/js_api_web_storage.asp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.w3schools.com/js/js_api_web_storage.asp&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/TV01s/hyXC8yJK9C/hb5rFl02TAhnkOXQyaCAy1/img.png?width=436&amp;amp;height=228&amp;amp;face=0_0_436_228,https://scrap.kakaocdn.net/dn/BPRM1/hyXDmX3i6p/6PkeQdKXhyxLEKNjThtTd1/img.png?width=300&amp;amp;height=300&amp;amp;face=0_0_300_300');&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;W3Schools.com&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.w3schools.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.youtube.com/watch?v=-4Sa7nTrXr4&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://www.youtube.com/watch?v=-4Sa7nTrXr4&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/Javascript</category>
      <category>local storage</category>
      <category>session storage</category>
      <category>Web Storage</category>
      <category>로컬 스토리지</category>
      <category>세션 스토리지</category>
      <category>오블완</category>
      <category>웹 스토리지</category>
      <category>티스토리챌린지</category>
      <author>다니니니</author>
      <guid isPermaLink="true">https://daddda3232.tistory.com/126</guid>
      <comments>https://daddda3232.tistory.com/126#entry126comment</comments>
      <pubDate>Sun, 24 Nov 2024 18:58:46 +0900</pubDate>
    </item>
    <item>
      <title>[React] React Hook Form</title>
      <link>https://daddda3232.tistory.com/125</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목을 입력해주세요_-001 (38).png&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;891&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvD58p/btsKUelCDW7/aJJIbD6JKltLSBjmTE2VJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvD58p/btsKUelCDW7/aJJIbD6JKltLSBjmTE2VJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvD58p/btsKUelCDW7/aJJIbD6JKltLSBjmTE2VJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvD58p%2FbtsKUelCDW7%2FaJJIbD6JKltLSBjmTE2VJ1%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;600&quot; height=&quot;424&quot; data-filename=&quot;제목을 입력해주세요_-001 (38).png&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;891&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;React Hook Form 은 비제어 컴포넌트를 기반으로 동작하는 폼 관리 라이브러리다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React 에서 form 을 쉽게 관리할 수 있도록 해주며, form의 상태 관리와 유효성 검사를 간단하게 만들어준다.&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;React Hook Form&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React Hook Form 은 다음의 커맨드로 설치할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1732351850991&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install react-hook-form&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;React Hook Form 은 useForm 이라는 훅을 통해 폼 상태, 검증 및 제출 로직을 관리한다.&lt;/p&gt;
&lt;pre id=&quot;code_1732365137126&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { useForm } from 'react-hook-form'&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;React Hook Form 에서 주로 사용되는 메서드는 아래와 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;register : 입력 요소에 연결하기 위한 함수. 이 함수를 통해서 입력 요소에 유효성 검사 규칙을 설정할 수 있다&lt;/li&gt;
&lt;li&gt;handleSubmit : 폼의 제출을 처리하기 위한 함수. 이 함수에 전달된 콜백은 유효성 검사를 통과한 데이터를 인자로 받아서 실행한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;watch :&amp;nbsp; 특정 폼 필드의 값을 실시간으로 관찰하는 함수&amp;nbsp;&lt;/li&gt;
&lt;li&gt;formState : 폼의 상태를 나타내는 객체 (ex. errors, isValid, isDirty, isSubmitted 등의 상태 포함)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예시 코드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1732369293031&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React from &quot;react&quot;;
import { useForm } from &quot;react-hook-form&quot;;

const errorMsgStyle = {
  fontSize: &quot;12px&quot;,
  color: &quot;red&quot;,
};

export default function Form() {
  const {
    register, // input 할당, value 변경 감지
    handleSubmit, // form submit 시 호출
    formState: { errors }, // 폼 상태 객체
    watch, // 특정 폼 필드의 값을 실시간으로 사용
  } = useForm();

  // handleSubmit(func A[, func B]) - 두개의 함수를 인자로 받는다. (두번째인자는 생략 가능)
  // func A는 필수 값, 유효할 때 실행
  // func B는 선택, 유효하지 않을 때 실행

  // func A -&amp;gt; 유효할 떄 실행
  const onValid = (data) =&amp;gt; {
    console.log(&quot;onValid &amp;gt;&amp;gt;&amp;gt; &quot;, data);
  };

  // func B -&amp;gt; 유효하지 않을 때 실행
  const onInValid = (err) =&amp;gt; {
    console.log(&quot;onInValid &amp;gt;&amp;gt;&amp;gt; &quot;, err);
  };

  console.log(&quot;errors&amp;gt;&amp;gt;&amp;gt;&quot;, errors);
  console.log(&quot;watch&amp;gt;&amp;gt;&amp;gt;&quot;, watch(&quot;username&quot;));

  return (
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;react-hook-form 라이브러리 DEMO&amp;lt;/h1&amp;gt;
      &amp;lt;form onSubmit={handleSubmit(onValid, onInValid)}&amp;gt;
        &amp;lt;div&amp;gt;
          &amp;lt;input
            type=&quot;text&quot;
            placeholder=&quot;username&quot;
            {...register(&quot;username&quot;, {
              required: &quot;이름은 필수항목입니다.&quot;,
              minLength: {
                message: &quot;이름은 최소 2글자 이상 작성해주세요&quot;,
                value: 2,
              },
            })}
            // 'username'이라는 필드명 / required, minLengh 라는 유효성 검사 규칙
            // 'username' 이라는 input 필드를 RHF(react-hook-form)에 등록
          /&amp;gt;
          {errors.username &amp;amp;&amp;amp; (
            &amp;lt;div style={errorMsgStyle}&amp;gt;{errors.username.message}&amp;lt;/div&amp;gt;
          )}
        &amp;lt;/div&amp;gt;
        {/* 이 표현은 조건부 렌더링과 옵셔널 체이닝을 활용하여 폼 필드의 오류 메시지를 표시하는 방법 */}
        {/* errors = formState 객체 중 하나 각 폼 필드에 대한 오류 메시지를 담고, 유효성 검사가 실패한 경우에만 해당 필드의 오류 메시지가 저장됨 */}
        {/* 옵셔널 체이닝 연산자 '?.'
                JS에서 객체의 속성에 접근할 때 해당 속성이 존재하는지 확인하고, 없을 경우 undefined 반환하는 연산자 */}

        &amp;lt;div&amp;gt;
          &amp;lt;input
            type=&quot;email&quot;
            placeholder=&quot;email(gmail)&quot;
            {...register(&quot;email&quot;, {
              required: &quot;이메일을 입력해주세요&quot;,
              validate: {
                useGmail: (v) =&amp;gt;
                  v.includes(&quot;gmail.com&quot;) || &quot;gmail로만 가입 가능합니다.&quot;,
              },
            })}
          /&amp;gt;
          {/* validate : reat hook form 에서 제공하는 유효성 검사 옵션 중 하나,
                폼 필드에 대하 커스텀 유효성 검사를 수행할 수 있도록 함,
                함수 또는 함수들을 포함하는 객체를 받을 수 있음 */}
          {/* validate 가 객체로 사용될 경우, 객체의 각 속성에 대해 개별적인 유효성 검사 수행 가능
                각 속성은 함수 형태로 정의, 이 함수들이 개별적인 유효성 검사 규칙 적용 */}
          {/* 
                useGmail : validate 옵션의 객체 내부에서 useGmail 이라는 이름의 함수로 정의, 특정 유효성 검사 규칙 설정 
                v : 사용자가 email 필드에 입력한 값(이메일 주소)을 의미
            */}

          {errors.email &amp;amp;&amp;amp; (
            &amp;lt;div style={errorMsgStyle}&amp;gt;{errors.email.message}&amp;lt;/div&amp;gt;
          )}
        &amp;lt;/div&amp;gt;
        &amp;lt;div&amp;gt;
          &amp;lt;input
            type=&quot;password&quot;
            placeholder=&quot;password&quot;
            {...register(&quot;password&quot;, {
              required: &quot;비밀번호를 입력해주세요&quot;,
              pattern: {
                value: /^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{2,8}$/,
                message: &quot;2~8글자의 영어+숫자 조합으로 입력해주세요&quot;,
              },
            })}
          /&amp;gt;
          {/* pattern 을 사용해서 정규식으로 유효성 검사 가능 */}
          {errors.password &amp;amp;&amp;amp; (
            &amp;lt;div style={errorMsgStyle}&amp;gt;{errors.password.message}&amp;lt;/div&amp;gt;
          )}
        &amp;lt;/div&amp;gt;
        &amp;lt;button type=&quot;submit&quot;&amp;gt;Submit&amp;lt;/button&amp;gt;
      &amp;lt;/form&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;&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&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;rhf.gif&quot; data-origin-width=&quot;317&quot; data-origin-height=&quot;214&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bge9ER/btsKTpONdE3/ufpSlTN0Vm9vwHmtLmYR11/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bge9ER/btsKTpONdE3/ufpSlTN0Vm9vwHmtLmYR11/img.gif&quot; data-alt=&quot;유효성 검사 및 폼 제출&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bge9ER/btsKTpONdE3/ufpSlTN0Vm9vwHmtLmYR11/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bge9ER/btsKTpONdE3/ufpSlTN0Vm9vwHmtLmYR11/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;317&quot; height=&quot;214&quot; data-filename=&quot;rhf.gif&quot; data-origin-width=&quot;317&quot; data-origin-height=&quot;214&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;유효성 검사 및 폼 제출&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2024-11-23 224600.jpg&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;98&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vrGnj/btsKUA9wvjc/4XrCbefOsGVavKnQlClTKk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vrGnj/btsKUA9wvjc/4XrCbefOsGVavKnQlClTKk/img.jpg&quot; data-alt=&quot;폼 제출 결과&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vrGnj/btsKUA9wvjc/4XrCbefOsGVavKnQlClTKk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvrGnj%2FbtsKUA9wvjc%2F4XrCbefOsGVavKnQlClTKk%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;320&quot; height=&quot;98&quot; data-filename=&quot;화면 캡처 2024-11-23 224600.jpg&quot; data-origin-width=&quot;320&quot; data-origin-height=&quot;98&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;폼 제출 결과&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;React Hook Form 의 특징&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React Hook Form 은 비제어 컴포넌트 기반으로 동작하기 때문에&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;또한, HTML5 의 기본적인 검증 속성인 required, minLength, maxLength 등을 사용할 수 있어,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검증 로직을 쉽고 간편하게 구현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또, error 등 상태를 나타낼 수 있는 객체를 사용해서 간단하게 에러 메시지를 관리할 수 있다.&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;React Hook Form 의 동작 방식&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서, React Hook Form 은 비제어 컴포넌트 기반으로 동작한다고 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 input 이나 form 의 값을 react state 에서 직접 관리하는 것이 아니라, 브라우저의 DOM 상태를 참조한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이로 인해 최소한의 리렌더링을 하여 성능을 향상 시킬 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;register 함수가 input 요소를 등록해서 DOM 참조를 생성하고, 이를 통해 값을 관리한다.&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;React Hook Form 과 일반 Form 작성 비교&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;일반 Form&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;각 입력 필드의 상태를 useState 로 관리해야함&lt;/li&gt;
&lt;li&gt;값이 바뀔 때마다 전체 컴포넌트가 리렌더링 될 수 있다.&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;&lt;b&gt;React Hook Form&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;useForm이라는 단일 훅을 이용해서&amp;nbsp; 폼 상태, 검증 및 제출 로직을 관리하므로, 사용법이 직관적이고 코드가 간결하다.&lt;/li&gt;
&lt;li&gt;비제어 컴포넌트 기반으로 동작하여 필요한 경우에만 리렌더링 한다.&lt;/li&gt;
&lt;li&gt;다양한 검증 규칙을 쉽게 설정할 수 있다&lt;/li&gt;
&lt;li&gt;handleSubmit 함수 하나로 모든 폼 데이터를 쉽게 관리할 수 있다.&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;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.1705%;&quot;&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 36.124%;&quot;&gt;&lt;b&gt;일반 Form&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 41.7054%;&quot;&gt;&lt;b&gt;React Hook Form&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.1705%;&quot;&gt;&lt;b&gt;상태 관리&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 36.124%;&quot;&gt;React State 로 직접 관리&lt;/td&gt;
&lt;td style=&quot;width: 41.7054%;&quot;&gt;비제어 컴포넌트를 사용하여 상태를 DOM 에서 관리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.1705%;&quot;&gt;&lt;b&gt;유효성 검사&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 36.124%;&quot;&gt;별도의 검증 로직을 작성&lt;/td&gt;
&lt;td style=&quot;width: 41.7054%;&quot;&gt;register 등을 사용해서 간단하게 구현 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.1705%;&quot;&gt;&lt;b&gt;리렌더링&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 36.124%;&quot;&gt;입력값 변경 시마다 리렌더링 발생&lt;/td&gt;
&lt;td style=&quot;width: 41.7054%;&quot;&gt;비제어 컴포넌트 기반으로 리렌더링 최소화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.1705%;&quot;&gt;&lt;b&gt;코드 복잡도&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 36.124%;&quot;&gt;state 관리 및 이벤트 핸들러로 인해 코드가 길어질 수 있음&lt;/td&gt;
&lt;td style=&quot;width: 41.7054%;&quot;&gt;간결한 코드로 작성 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.1705%;&quot;&gt;&lt;b&gt;성능&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 36.124%;&quot;&gt;대규모 폼 양식 작성 시 성능 저하 문제 발생할 수 있음&lt;/td&gt;
&lt;td style=&quot;width: 41.7054%;&quot;&gt;최소한의 리렌더링으로 인한 성능 향상&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;따라서 일반 Form 양식은 간단한 폼 양식 작성 시에 사용하기 적합하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React Hook Form 복잡하고 대규모 폼 양식을 작성할 떄 사용하기 적합하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(ex. 회원가입/로그인 폼 등)&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;따라서 리액트 프로젝트에서 form 을 사용할 일이 있으면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트의 규모, form 을 사용하는 곳의 규모를 생각해서 적절한 것을 사용하면 되겠다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Reference&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;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>Study/React</category>
      <category>REACT</category>
      <category>react hook form</category>
      <category>rhf</category>
      <category>비제어 컴포넌트</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>다니니니</author>
      <guid isPermaLink="true">https://daddda3232.tistory.com/125</guid>
      <comments>https://daddda3232.tistory.com/125#entry125comment</comments>
      <pubDate>Sat, 23 Nov 2024 16:10:30 +0900</pubDate>
    </item>
    <item>
      <title>[React] 제어 컴포넌트와 비제어 컴포넌트</title>
      <link>https://daddda3232.tistory.com/124</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목을 입력해주세요_-001 (37).png&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;891&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biZE6H/btsKUgJhFH5/ZKwBINc9ntKzQ4J04jMEdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biZE6H/btsKUgJhFH5/ZKwBINc9ntKzQ4J04jMEdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biZE6H/btsKUgJhFH5/ZKwBINc9ntKzQ4J04jMEdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiZE6H%2FbtsKUgJhFH5%2FZKwBINc9ntKzQ4J04jMEdK%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;600&quot; height=&quot;424&quot; data-filename=&quot;제목을 입력해주세요_-001 (37).png&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;891&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;React 로 form 을 구현할 때 제어 컴포넌트와(Controlled Component) 와 비제어 컴포넌트(Uncontrolled Component) 라는 개념을 접할 수 있다.&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;h3 data-ke-size=&quot;size23&quot;&gt;제어 컴포넌트와 비제어 컴포넌트&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;제어 컴포넌트(Controlled Component)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력 값이 React 의 state에 의해서 제어되는 컴포넌트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력 값이 변경될 때마다 onChange 이벤트로 상태 업데이트하고, 업데이트된 상태로 다시 렌더링 한다.&lt;/p&gt;
&lt;p 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;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;사용자가 input 에 값을 입력하면 onChange 이벤트가 호출된다.&lt;/li&gt;
&lt;li&gt;이벤트 핸들러가 새로운 입력 값을 React 의 state 로 업데이트한다.&lt;/li&gt;
&lt;li&gt;React 는 상태를 기반으로 컴포넌트를 재렌더링하고, input 의 value 속성을 새 값으로 설정한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;제어 컴포넌트의 특징&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;React 의 state 를 통해 데이터 흐름을 제어한다.&lt;/li&gt;
&lt;li&gt;입력 값 변경에 따라 컴포넌트가 재렌더링된다.&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;&lt;b&gt;예시 코드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1732264306092&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React, { useState } from &quot;react&quot;;

export default function ControlledInput() {
  const [value, setValue] = useState(&quot;&quot;);
  const [submittedValue, setSubmittedValue] = useState(&quot;&quot;);

  const handleChange = (e) =&amp;gt; {
    setValue(e.target.value);
  };

  const handleSubmit = () =&amp;gt; {
    setSubmittedValue(value);
  }

  return (
    &amp;lt;div style={{marginLeft : '100px'}}&amp;gt;
      &amp;lt;h1&amp;gt;제어 컴포넌트&amp;lt;/h1&amp;gt;
      &amp;lt;input type=&quot;text&quot; value={value} onChange={handleChange} /&amp;gt;
      &amp;lt;h5&amp;gt;State : {value}&amp;lt;/h5&amp;gt;
      &amp;lt;button onClick={handleSubmit} type=&quot;button&quot;&amp;gt;전송&amp;lt;/button&amp;gt;
      &amp;lt;p&amp;gt;전송된 값 : {submittedValue}&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;&lt;b&gt;결과&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;controlledComponent.gif&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;214&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buqKiF/btsKTY3DZiJ/4ouo9RtWKifQfSxhgzrphK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buqKiF/btsKTY3DZiJ/4ouo9RtWKifQfSxhgzrphK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buqKiF/btsKTY3DZiJ/4ouo9RtWKifQfSxhgzrphK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/buqKiF/btsKTY3DZiJ/4ouo9RtWKifQfSxhgzrphK/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;290&quot; height=&quot;214&quot; data-filename=&quot;controlledComponent.gif&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;214&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;useState로 입력 값을 제어했기 때문에, 입력 값이 바뀔 때마다 리렌더링되면서 값이 실시간으로 반영된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전송버튼을 누르면 해당되는 함수가 호출되며 submiitedValue 상태가 저장되고, 화면에 전송된 값이 표시된다.&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;비제어 컴포넌트(Uncontrolled Component)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DOM 요소 자체가 상태를 관리하는 방식으로, React 가 제어하는 것이 아니라&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ref 를 사용해서 DOM 에 접근해 값을 읽거나 조작한다.&lt;/p&gt;
&lt;p 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;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;사용자가 input 에 값을 입력하면 DOM 이 자체적으로 값을 관리한다.&lt;/li&gt;
&lt;li&gt;React 는 ref 를 통해 DOM 요소에 접근하고 value 를 읽는다.&lt;/li&gt;
&lt;li&gt;상태를 React 에서 관리하지 않아도 된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;비제어 컴포넌트의 특징&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;DOM 요소가 입력 값을 보유하며, React 와 독립적으로 동작한다.&lt;/li&gt;
&lt;li&gt;defaultValue 속성을 사용해 초기값을 설정할 수 있다.&lt;/li&gt;
&lt;li&gt;간단한 입력 값 처리나 초기화 로직이 적은 경우 적합하다.&lt;/li&gt;
&lt;li&gt;입력 값이 실시간으로 반영되지는 않지만, 과도한 리렌더링을 방지할 수 있어서 성능적으로 이득을 얻을 수 있다.&lt;/li&gt;
&lt;li&gt;DOM 요소에서 제어하기 때문에 form 의 기본 동작을 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예시 코드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1732266283210&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import React, { useRef, useState } from &quot;react&quot;;

export default function UncontrolledInput() {
  const inputRef = useRef();
  const [submittedValue, setSubmittedValue] = useState(&quot;&quot;);

  const handleSubmit = () =&amp;gt; {
    if (inputRef.current) {
      setSubmittedValue(inputRef.current.value);
    }
  };

  return (
    &amp;lt;div style={{ marginLeft: &quot;100px&quot; }}&amp;gt;
      &amp;lt;h1&amp;gt;비제어 컴포넌트&amp;lt;/h1&amp;gt;
      &amp;lt;input type=&quot;text&quot; ref={inputRef} /&amp;gt;
      &amp;lt;h5&amp;gt;Ref : {inputRef.current?.value}&amp;lt;/h5&amp;gt;
      &amp;lt;button onClick={handleSubmit} type=&quot;button&quot;&amp;gt;
        전송
      &amp;lt;/button&amp;gt;
      &amp;lt;p&amp;gt;전송된 값 : {submittedValue}&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;&lt;b&gt;결과&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;uncontrolledComponent.gif&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;214&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Hy0VS/btsKTwzNvHB/Xt0MMkVMiKxH49NTqsPU8K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Hy0VS/btsKTwzNvHB/Xt0MMkVMiKxH49NTqsPU8K/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Hy0VS/btsKTwzNvHB/Xt0MMkVMiKxH49NTqsPU8K/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/Hy0VS/btsKTwzNvHB/Xt0MMkVMiKxH49NTqsPU8K/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;290&quot; height=&quot;214&quot; data-filename=&quot;uncontrolledComponent.gif&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;214&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결과 해석&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;ref 를 사용하여 DOM을 참조했기 때문에 DOM 에는 입력값이 저장되나, 재렌더링은 되지 않아서&amp;nbsp;&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;다만 전송 버튼을 눌렀을 때 submittedValue state 가 저장되면서 리렌더링므로&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 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;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;제어 컴포넌트와 비제어 컴포넌트 비교&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 81.6273%; height: 100px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 10.814%; height: 20px;&quot;&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 14.5459%; height: 20px;&quot;&gt;&lt;b&gt;제어 컴포넌트&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 15.3144%; height: 20px;&quot;&gt;&lt;b&gt;비제어 컴포넌트&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 16px;&quot;&gt;
&lt;td style=&quot;width: 10.814%; height: 16px;&quot;&gt;&lt;b&gt;상태 관리&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 14.5459%; height: 16px;&quot;&gt;React state 로 관리&lt;/td&gt;
&lt;td style=&quot;width: 15.3144%; height: 16px;&quot;&gt;DOM 요소가 자체 상태 관리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 16px;&quot;&gt;
&lt;td style=&quot;width: 10.814%; height: 16px;&quot;&gt;&lt;b&gt;초기값 설정&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 14.5459%; height: 16px;&quot;&gt;value 속성과 상태로 설정&lt;/td&gt;
&lt;td style=&quot;width: 15.3144%; height: 16px;&quot;&gt;defaultValue 로 설정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 16px;&quot;&gt;
&lt;td style=&quot;width: 10.814%; height: 16px;&quot;&gt;&lt;b&gt;데이터 접근 방식&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 14.5459%; height: 16px;&quot;&gt;상태(state) 기반&lt;/td&gt;
&lt;td style=&quot;width: 15.3144%; height: 16px;&quot;&gt;ref 를 사용하여 DOM 에 직접 접근&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 10.814%;&quot;&gt;&lt;b&gt;실시간 반영(동적 입력)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 14.5459%;&quot;&gt;O&lt;/td&gt;
&lt;td style=&quot;width: 15.3144%;&quot;&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력 값을 실시간으로 검증해야 하거나 여러 필드 간 동기화가 필요한 경우 &lt;br /&gt;(ex. 비밀번호 입력 필드 값과 비밀번호 확인 입력 필드 값을 실시간으로 비교할 때)&lt;/li&gt;
&lt;li&gt;사용자 입력에 따라 다른 컴포넌트 상태를 동기화해야 하는 경우&lt;br /&gt;(입력값 변경에 따른 버튼 활성화 상태를 조정할 때)&lt;/li&gt;
&lt;li&gt;값의 변경이 실시간으로 반영되어야 하는 경우&lt;br /&gt;(입력 값이 바로 반영되는 실시간 검색)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;비제어 컴포넌트를 사용할 경우&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;단순한 폼이나 초기 렌더링 이후 값 관리를 신경 쓰지 않아도 되는 경우&lt;br /&gt;(회원가입 시 이름, 이메일 드으이 단순 입력 필드)&lt;/li&gt;
&lt;li&gt;외부 라이브러리와 연동하는 경우&amp;nbsp;&lt;br /&gt;(파일 선택 필드나 드래그 앤 드롭 파일 업로드 등의 외부 라이브러리 사용 시)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서&lt;/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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Reference&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.legacy.reactjs.org/docs/forms.html#controlled-components&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ko.legacy.reactjs.org/docs/forms.html#controlled-components&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732262548857&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;폼 &amp;ndash; React&quot; data-og-description=&quot;A JavaScript library for building user interfaces&quot; data-og-host=&quot;ko.legacy.reactjs.org&quot; data-og-source-url=&quot;https://ko.legacy.reactjs.org/docs/forms.html#controlled-components&quot; data-og-url=&quot;https://ko.legacy.reactjs.org/docs/forms.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dPV54S/hyXDj7IqFq/T7tMzzkge4OcdcWvqlU9nK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://ko.legacy.reactjs.org/docs/forms.html#controlled-components&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.legacy.reactjs.org/docs/forms.html#controlled-components&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dPV54S/hyXDj7IqFq/T7tMzzkge4OcdcWvqlU9nK/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;폼 &amp;ndash; React&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A JavaScript library for building user interfaces&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ko.legacy.reactjs.org&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ko.legacy.reactjs.org/docs/uncontrolled-components.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://ko.legacy.reactjs.org/docs/uncontrolled-components.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732262524012&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;비제어 컴포넌트 &amp;ndash; React&quot; data-og-description=&quot;A JavaScript library for building user interfaces&quot; data-og-host=&quot;ko.legacy.reactjs.org&quot; data-og-source-url=&quot;https://ko.legacy.reactjs.org/docs/uncontrolled-components.html&quot; data-og-url=&quot;https://ko.legacy.reactjs.org/docs/uncontrolled-components.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bhOGfA/hyXDaXfgNE/HIaDpbS2IKHjPxe4usyeT1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://ko.legacy.reactjs.org/docs/uncontrolled-components.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.legacy.reactjs.org/docs/uncontrolled-components.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bhOGfA/hyXDaXfgNE/HIaDpbS2IKHjPxe4usyeT1/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;비제어 컴포넌트 &amp;ndash; React&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A JavaScript library for building user interfaces&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ko.legacy.reactjs.org&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@thumb_hyeok/%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-vs-%EB%B9%84%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@thumb_hyeok/%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-vs-%EB%B9%84%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732262521391&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;제어 컴포넌트 vs 비제어 컴포넌트&quot; data-og-description=&quot;결론부터 말하고 가자면 React에 의해서 값이 제어되는 컴포넌트를 제어 컴포넌트, React에 의해서 값이 제어되지 않는 컴포넌트를 비제어 컴포넌트라고 한다.우리는 form 이나 input 요소를 다룰 때,&quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@thumb_hyeok/%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-vs-%EB%B9%84%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8&quot; data-og-url=&quot;https://velog.io/@thumb_hyeok/제어-컴포넌트-vs-비제어-컴포넌트&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/wMMmj/hyXDeSSKUB/kF9d468yTlOVPgqCeKhWkK/img.png?width=700&amp;amp;height=235&amp;amp;face=0_0_700_235,https://scrap.kakaocdn.net/dn/noWqz/hyXDeSSKWg/R5eYzue8BXhB5eA8jM00s1/img.png?width=700&amp;amp;height=235&amp;amp;face=0_0_700_235,https://scrap.kakaocdn.net/dn/cZydzt/hyXzWl1uKz/aSKmxYMmLKaL2VCarFBLT0/img.jpg?width=1507&amp;amp;height=1507&amp;amp;face=0_0_1507_1507&quot;&gt;&lt;a href=&quot;https://velog.io/@thumb_hyeok/%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-vs-%EB%B9%84%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@thumb_hyeok/%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-vs-%EB%B9%84%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/wMMmj/hyXDeSSKUB/kF9d468yTlOVPgqCeKhWkK/img.png?width=700&amp;amp;height=235&amp;amp;face=0_0_700_235,https://scrap.kakaocdn.net/dn/noWqz/hyXDeSSKWg/R5eYzue8BXhB5eA8jM00s1/img.png?width=700&amp;amp;height=235&amp;amp;face=0_0_700_235,https://scrap.kakaocdn.net/dn/cZydzt/hyXzWl1uKz/aSKmxYMmLKaL2VCarFBLT0/img.jpg?width=1507&amp;amp;height=1507&amp;amp;face=0_0_1507_1507');&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;제어 컴포넌트 vs 비제어 컴포넌트&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;결론부터 말하고 가자면 React에 의해서 값이 제어되는 컴포넌트를 제어 컴포넌트, React에 의해서 값이 제어되지 않는 컴포넌트를 비제어 컴포넌트라고 한다.우리는 form 이나 input 요소를 다룰 때,&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;
&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://velog.io/@yukyung/React-%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%99%80-%EB%B9%84%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90-%ED%86%BA%EC%95%84%EB%B3%B4%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@yukyung/React-%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%99%80-%EB%B9%84%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90-%ED%86%BA%EC%95%84%EB%B3%B4%EA%B8%B0&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732262513272&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: 제어 컴포넌트와 비제어 컴포넌트의 차이점&quot; data-og-description=&quot;  제어 컴포넌트와 비제어 컴포넌트의 차이점, 활용 방법에 대해 알아봅시다&quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@yukyung/React-%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%99%80-%EB%B9%84%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90-%ED%86%BA%EC%95%84%EB%B3%B4%EA%B8%B0&quot; data-og-url=&quot;https://velog.io/@yukyung/React-제어-컴포넌트와-비제어-컴포넌트의-차이점-톺아보기&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ce9EeA/hyXDaCWp9Y/nxTkyjjqDqk8FYcLHzOuW1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/beYsqT/hyXDgJUss7/0mJcCXb4sNKkTA5dhleUKk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bIvFwO/hyXC70uTgc/IACkeOWKZkwIuIQsUtOBj1/img.jpg?width=1080&amp;amp;height=1080&amp;amp;face=0_0_1080_1080&quot;&gt;&lt;a href=&quot;https://velog.io/@yukyung/React-%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%99%80-%EB%B9%84%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90-%ED%86%BA%EC%95%84%EB%B3%B4%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@yukyung/React-%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%99%80-%EB%B9%84%EC%A0%9C%EC%96%B4-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90-%ED%86%BA%EC%95%84%EB%B3%B4%EA%B8%B0&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ce9EeA/hyXDaCWp9Y/nxTkyjjqDqk8FYcLHzOuW1/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/beYsqT/hyXDgJUss7/0mJcCXb4sNKkTA5dhleUKk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bIvFwO/hyXC70uTgc/IACkeOWKZkwIuIQsUtOBj1/img.jpg?width=1080&amp;amp;height=1080&amp;amp;face=0_0_1080_1080');&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: 제어 컴포넌트와 비제어 컴포넌트의 차이점&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;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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://goshacmd.com/controlled-vs-uncontrolled-inputs-react/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://goshacmd.com/controlled-vs-uncontrolled-inputs-react/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732267215597&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;https://goshacmd.com/controlled-vs-uncontrolled-inputs-react/&quot; data-og-description=&quot;&quot; data-og-host=&quot;goshacmd.com&quot; data-og-source-url=&quot;https://goshacmd.com/controlled-vs-uncontrolled-inputs-react/&quot; data-og-url=&quot;https://goshacmd.com/controlled-vs-uncontrolled-inputs-react/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://goshacmd.com/controlled-vs-uncontrolled-inputs-react/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://goshacmd.com/controlled-vs-uncontrolled-inputs-react/&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;https://goshacmd.com/controlled-vs-uncontrolled-inputs-react/&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;goshacmd.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>Study/React</category>
      <category>form</category>
      <category>REACT</category>
      <category>비제어컴포넌트</category>
      <category>오블완</category>
      <category>제어컴포넌트</category>
      <category>티스토리챌린지</category>
      <author>다니니니</author>
      <guid isPermaLink="true">https://daddda3232.tistory.com/124</guid>
      <comments>https://daddda3232.tistory.com/124#entry124comment</comments>
      <pubDate>Fri, 22 Nov 2024 14:42:32 +0900</pubDate>
    </item>
    <item>
      <title>CORS 에 대해서 알아보기</title>
      <link>https://daddda3232.tistory.com/123</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목을 입력해주세요_-001 (36).png&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;891&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6gg8w/btsKQ7mr07q/KOGZiK6JCXWfJKXykBfQc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6gg8w/btsKQ7mr07q/KOGZiK6JCXWfJKXykBfQc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6gg8w/btsKQ7mr07q/KOGZiK6JCXWfJKXykBfQc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6gg8w%2FbtsKQ7mr07q%2FKOGZiK6JCXWfJKXykBfQc1%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;600&quot; height=&quot;424&quot; data-filename=&quot;제목을 입력해주세요_-001 (36).png&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;891&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;CORS(Cross-Origin Resource Sharing)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CORS 란 교차 출처 리소스 공유를 의미한다.&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;브라우저는 기본적으로 SOP(Same-Origin Policy) 정책을 따르는데, 이 정책은 같은 출처에서만 리소스를 공유할 수 있다고 정한 정책이다.&lt;/p&gt;
&lt;p 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;그러나 개발을 하다보면, 클라이언트와 서버의 출처(Origin)가 서로 다를 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 리액트 서버(포트 번호 3000) 와 스프링부트 혹은 익스프레스 서버(포트 번호 8080) 가 리소스를 주고받으려 하면 서로 다른 출처로 판단되어서 CORS 위반 에러가 난다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;693&quot; data-origin-height=&quot;384&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctVvld/btsKSwZH6Ep/yA51M9Qguc5nNgIqnYkPsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctVvld/btsKSwZH6Ep/yA51M9Qguc5nNgIqnYkPsk/img.png&quot; data-alt=&quot;출처 : 코딩온 교안 자료&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctVvld/btsKSwZH6Ep/yA51M9Qguc5nNgIqnYkPsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FctVvld%2FbtsKSwZH6Ep%2FyA51M9Qguc5nNgIqnYkPsk%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;693&quot; height=&quot;384&quot; data-origin-width=&quot;693&quot; data-origin-height=&quot;384&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;&lt;br /&gt;참고로 출처(Origin) 는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로토콜(http 또는 https)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인(test.com)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포트 번호(:8080, :3030 등)&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;942&quot; data-origin-height=&quot;313&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bY2iTX/btsKQHBHoLz/cMOEKBjcMtGCjZC6YRUkH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bY2iTX/btsKQHBHoLz/cMOEKBjcMtGCjZC6YRUkH0/img.png&quot; data-alt=&quot;출처 : https://docs.tosspayments.com/resources/glossary/cors&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bY2iTX/btsKQHBHoLz/cMOEKBjcMtGCjZC6YRUkH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbY2iTX%2FbtsKQHBHoLz%2FcMOEKBjcMtGCjZC6YRUkH0%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;942&quot; height=&quot;313&quot; data-origin-width=&quot;942&quot; data-origin-height=&quot;313&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : https://docs.tosspayments.com/resources/glossary/cors&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;https://www.test.com:8080&lt;/b&gt; 이라는 url 이 있을 때&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;https://test.com:8080 -&amp;gt; 같은 출처로 간주&lt;/li&gt;
&lt;li&gt;http://www.test.com:8080 -&amp;gt; 프로토콜이 다르므로 다른 출처로 간주&lt;/li&gt;
&lt;li&gt;http://sub.test.com -&amp;gt; 도메인이 다르므로 다른 출처로 간주&lt;/li&gt;
&lt;li&gt;https://www.test.com:3030 -&amp;gt; 포트번호가 다르므로 다른 출처로 간주&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;CORS 요청 종류&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1) Simple Request (단순 요청)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저가 사전 요청없이 바로 요청을 보내는 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청 메서드는 GET, POST, HEAD 만 허용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Request Header 에는 다음 속성만 허용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Accept, Accept-Language, Content-Language,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Content-Type(application/x-www-form-urlencoded, multipart/form-data, text/plain)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;** application/json 은 simple request 에 해당하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;** 클라이언트에서 임의로 커스텀 헤더를 추가하면 simple request 에 해당하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 클라이언트 요청&lt;/p&gt;
&lt;pre id=&quot;code_1732172673930&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 클라이언트 요청
fetch('https://example.com/api/message', {
  method: 'POST',
  headers: {
    'Content-Type': 'text/plain', // 허용된 Content-Type
  },
  body: 'Hello World!', // 단순 텍스트
})
  .then(response =&amp;gt; response.text())
  .then(data =&amp;gt; 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;2. 서버 응답 헤더&lt;/p&gt;
&lt;pre id=&quot;code_1732172698658&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HTTP/1.1 200 OK
Content-Type: text/plain
Access-Control-Allow-Origin: https://example.com&lt;/code&gt;&lt;/pre&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) Preflight Request (사전 요청)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청이 더 복잡하거나 보안적으로 민감할 경우, 브라우저는 &lt;b&gt;OPTIONS 메서드&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;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. 사전 요청(OPTIONS) : 브라우저는 OPTIONS 메서드로 서버에 요청&lt;/p&gt;
&lt;pre id=&quot;code_1732172803688&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;OPTIONS /api/data HTTP/1.1
Origin: https://example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Authorization&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;pre id=&quot;code_1732172836710&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Headers: Authorization
Access-Control-Allow-Credentials: true&lt;/code&gt;&lt;/pre&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;Access-Control-Allow-Origin: 허용할 출처 명시&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Access-Control-Allow-Methods: 허용할 HTTP 메서드 (GET, POST, PUT 등)&lt;/li&gt;
&lt;li&gt;Access-Control-Allow-Headers: 허용할 요청 헤더 (예: Authorization, Content-Type)&lt;/li&gt;
&lt;li&gt;Access-Control-Allow-Credentials: 인증 정보(쿠키, 인증 헤더 등) 허용 여부&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 실제 요청 : 브라우저는 서버의 허용 여부를 확인 후, 실제 요청을 보냄&lt;/p&gt;
&lt;pre id=&quot;code_1732172871787&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;PUT /api/data HTTP/1.1
Authorization: Bearer &amp;lt;token&amp;gt;
Content-Type: application/json
Origin: https://example.com&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;4. 서버 응답&lt;/p&gt;
&lt;pre id=&quot;code_1732172883929&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Content-Type: application/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;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;CORS 설정 하기 (feat. Express.js)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CORS 설정은 서버에서 하는 것이 일반적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브라우저는 보안 정책으로 CORS 강제한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버에서 응답 헤더를 통해 특정 출처를 허용한다고 명시하지 않으면, 브라우저는 요청이 성공하더라도 응답을 차단한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 Express.js 로 서버를 구축했다면 cors 미들웨어로 간단하게 CORS 설정을 할 수 있다.&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;다음의 커맨드로 cors 패키지를 설치한다.&lt;/p&gt;
&lt;pre id=&quot;code_1732174273175&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install cors&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;cors 미들웨어를 등록한다.&lt;/p&gt;
&lt;pre id=&quot;code_1732174387618&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const express = require('express');
const cors = require('cors');
const app = express();

// 기본 CORS 설정
app.use(cors());

app.get('/api/data', (req, res) =&amp;gt; {
  res.json({ message: 'CORS enabled for all origins!' });
});

app.listen(8080, () =&amp;gt; {
  console.log('Server is running on port 8080');
});&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;#1. 모든 출처에서 요청 허용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cors 는 기본적으로 모든 출처에서의 요청을 허용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1732174552850&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;app.use(cors());&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;origin 옵션에 허용할 출처를 명시하면 특정 출처에서의 요청만 허용할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1732174594362&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;app.use(cors({
    origin : 'http://ex.com' -&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;#3. 특정 옵션 설정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 출처를 허용하고 싶다면 origin 옵션에 배열로 출처를 적어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;methods 에 허용할 메서드를 명시할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;allowedHeaders 로 허용할 요청 헤더를 명시할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1732174682608&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;app.use({
    origin : ['http://ex.com', 'https://ex2.com'],
    methods : ['GET', 'POST'],
    allowedHeaders : ['Content-Type', 'Authorizaion']
})&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;#4. 인증 정보를 포함한 요청 허용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠키와 같은 인증 정보를 전달하려면&amp;nbsp; credentials 옵션을 설정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우 origin 은 반드시 명시적으로 설정해야 한다. ( * 사용 불가 )&lt;/p&gt;
&lt;pre id=&quot;code_1732174859759&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;app.use(cors({
  origin: 'http://ex.com', // 허용할 출처
  credentials: 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;이 경우에는 클라이언트 측 코드에서 요청을 보낼 때 withCredentials : true 를 설정해야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1732174983345&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;axios.get('http://server.com/api/data', { withCredentials: 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;&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;Reference&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;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.tosspayments.com/resources/glossary/cors&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://docs.tosspayments.com/resources/glossary/cors&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732169540585&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;CORS(교차 출처 리소스 공유) | 토스페이먼츠 개발자센터&quot; data-og-description=&quot;CORS를 번역하면 &amp;ldquo;교차 출처 리소스 공유&amp;rdquo;에요. &amp;lsquo;두 출처가 서로 다르다&amp;rsquo;는 뜻인데요. CORS를 설정한다는 건 &amp;lsquo;출처가 다른 서버 간의 리소스 공유&amp;rsquo;를 허용한다는 거죠.&quot; data-og-host=&quot;docs.tosspayments.com&quot; data-og-source-url=&quot;https://docs.tosspayments.com/resources/glossary/cors&quot; data-og-url=&quot;https://docs.tosspayments.com/resources/glossary/cors&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/d7MUEr/hyXzMDAaqX/1YbpHF4eLHKnKErtpU4Oxk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/edyuMZ/hyXDaW4oJ0/tBon2QZsqjn5TyjPVtYcWk/img.png?width=2816&amp;amp;height=986&amp;amp;face=0_0_2816_986&quot;&gt;&lt;a href=&quot;https://docs.tosspayments.com/resources/glossary/cors&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.tosspayments.com/resources/glossary/cors&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/d7MUEr/hyXzMDAaqX/1YbpHF4eLHKnKErtpU4Oxk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/edyuMZ/hyXDaW4oJ0/tBon2QZsqjn5TyjPVtYcWk/img.png?width=2816&amp;amp;height=986&amp;amp;face=0_0_2816_986');&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;CORS(교차 출처 리소스 공유) | 토스페이먼츠 개발자센터&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;CORS를 번역하면 &amp;ldquo;교차 출처 리소스 공유&amp;rdquo;에요. &amp;lsquo;두 출처가 서로 다르다&amp;rsquo;는 뜻인데요. CORS를 설정한다는 건 &amp;lsquo;출처가 다른 서버 간의 리소스 공유&amp;rsquo;를 허용한다는 거죠.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.tosspayments.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://developer.mozilla.org/ko/docs/Web/HTTP/CORS&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer.mozilla.org/ko/docs/Web/HTTP/CORS&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732169559668&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;교차 출처 리소스 공유 (CORS) - HTTP | MDN&quot; data-og-description=&quot;교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 브라우저가 자신의 출처가 아닌 다른 어떤 출처(도메인, 스킴 혹은 포트)로부터 자원을 로딩하는 것을 허용하도록 서버가 허가 해주는 HTTP &quot; data-og-host=&quot;developer.mozilla.org&quot; data-og-source-url=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/CORS&quot; data-og-url=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/CORS&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/OZ4Bl/hyXDjfpexD/XFl8A2UzTtBzkm20pQv3qK/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/CORS&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.mozilla.org/ko/docs/Web/HTTP/CORS&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/OZ4Bl/hyXDjfpexD/XFl8A2UzTtBzkm20pQv3qK/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&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;교차 출처 리소스 공유 (CORS) - HTTP | MDN&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 브라우저가 자신의 출처가 아닌 다른 어떤 출처(도메인, 스킴 혹은 포트)로부터 자원을 로딩하는 것을 허용하도록 서버가 허가 해주는 HTTP&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.mozilla.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://velog.io/@effirin/CORS%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://velog.io/@effirin/CORS%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1732169562082&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;CORS란 무엇인가?&quot; data-og-description=&quot;CORS가 무엇인지 알기 전에, 이 CORS가 등장하게 된 배경을 먼저 알아보자.SOP는 2011년 RFC 6454에서 등장한 보안 정책으로 &amp;quot;같은 출처에서만 리소스를 공유할 수 있다&amp;quot;라는 규칙을 가진 정책이다.그러&quot; data-og-host=&quot;velog.io&quot; data-og-source-url=&quot;https://velog.io/@effirin/CORS%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80&quot; data-og-url=&quot;https://velog.io/@effirin/CORS란-무엇인가&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bAZOIq/hyXzIHUXCo/4MYLlcA3T9BVUXcqkxsmh1/img.png?width=787&amp;amp;height=461&amp;amp;face=0_0_787_461,https://scrap.kakaocdn.net/dn/j7qQW/hyXDcUSOJ0/z07K79nxMFIJ2lkg691tj1/img.png?width=787&amp;amp;height=461&amp;amp;face=0_0_787_461,https://scrap.kakaocdn.net/dn/bLs0w3/hyXzJGO9Oj/egTdczbBK7weYnJXAfq1vk/img.jpg?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot;&gt;&lt;a href=&quot;https://velog.io/@effirin/CORS%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://velog.io/@effirin/CORS%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bAZOIq/hyXzIHUXCo/4MYLlcA3T9BVUXcqkxsmh1/img.png?width=787&amp;amp;height=461&amp;amp;face=0_0_787_461,https://scrap.kakaocdn.net/dn/j7qQW/hyXDcUSOJ0/z07K79nxMFIJ2lkg691tj1/img.png?width=787&amp;amp;height=461&amp;amp;face=0_0_787_461,https://scrap.kakaocdn.net/dn/bLs0w3/hyXzJGO9Oj/egTdczbBK7weYnJXAfq1vk/img.jpg?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&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;CORS란 무엇인가?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;CORS가 무엇인지 알기 전에, 이 CORS가 등장하게 된 배경을 먼저 알아보자.SOP는 2011년 RFC 6454에서 등장한 보안 정책으로 &quot;같은 출처에서만 리소스를 공유할 수 있다&quot;라는 규칙을 가진 정책이다.그러&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>Study/Node.js</category>
      <category>Cors</category>
      <category>Express</category>
      <category>오블완</category>
      <category>티스토리챌린지</category>
      <author>다니니니</author>
      <guid isPermaLink="true">https://daddda3232.tistory.com/123</guid>
      <comments>https://daddda3232.tistory.com/123#entry123comment</comments>
      <pubDate>Thu, 21 Nov 2024 14:12:48 +0900</pubDate>
    </item>
  </channel>
</rss>