<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발자의 끄적거림</title>
    <link>https://play-with.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Wed, 10 Jun 2026 14:31:45 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>끄적잉</managingEditor>
    <image>
      <title>개발자의 끄적거림</title>
      <url>https://tistory1.daumcdn.net/tistory/5928334/attach/7dd5f9ea6ef648f3812020b0143a2271</url>
      <link>https://play-with.tistory.com</link>
    </image>
    <item>
      <title>[Docker] Docker 완벽 정리</title>
      <link>https://play-with.tistory.com/417</link>
      <description>&lt;h2 data-path-to-node=&quot;2&quot; data-ke-size=&quot;size26&quot;&gt;내 컴퓨터에선 됐는데 왜 서버에선 안 될까? (도커 입문 가이드)&lt;/h2&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이1 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;5734766380&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;안녕하세요! 오늘은 개발자라면 누구나 한 번쯤 겪어봤을, 아니 어쩌면 지금 이 순간에도 여러분의 뒷목을 잡게 만들고 있을 그 주제에 대해 이야기해보려 합니다. 바로 **도커(Docker)**입니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;우리가 개발을 하다 보면 가장 많이 하는 거짓말(?) 중 하나가 뭔지 아세요? 바로 이겁니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-path-to-node=&quot;5&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;5,0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,0&quot;&gt;&quot;어? 내 컴퓨터에선 분명히 잘 됐는데요?&quot;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;분명 내 로컬 환경(맥북, 윈도우)에서는 쌩쌩 돌아가던 코드가, 배포 서버에만 올라가면 에러를 뿜어냅니다. 자바 버전이 다르다느니, 환경 변수가 안 잡혔다느니, 리눅스 패키지 뭐가 없다느니... 이런 '환경 지옥'에서 우리를 구원해 줄 고래 한 마리, 지금부터 제대로 파헤쳐 보겠습니다.&lt;/p&gt;
&lt;hr data-path-to-node=&quot;7&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size23&quot;&gt;1. 도커는 왜 태어났을까? (환경 지옥의 종말)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;우리가 흔히 겪는 문제를 떠올려봅시다. 새로 합류한 팀원에게 개발 환경을 세팅해줘야 할 때, 우리는 보통 이런 가이드를 줍니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;10&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&quot;자바 17 깔으시고요.&quot;&lt;/li&gt;
&lt;li&gt;&quot;환경 변수 JAVA_HOME 잡으세요.&quot;&lt;/li&gt;
&lt;li&gt;&quot;아, 아나콘다 쓰시나요? 그럼 가상환경부터 만드시고...&quot;&lt;/li&gt;
&lt;li&gt;&quot;DB는 포스트그레스(Postgres) 13버전인데, 설정 파일은 제가 카톡으로 보내드릴게요.&quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;이 과정에서 꼭 한두 명은 &quot;저 에러 나는데요?&quot;라고 말하죠. 운영체제마다 파일 경로가 다르고, 이미 설치된 다른 소프트웨어와 충돌이 나기 때문입니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;도커는 여기서 **&quot;그냥 내가 돌아가는 환경을 통째로 박스에 담아서 줄게!&quot;**라는 기발한 생각을 합니다. 이 박스 안에는 코드뿐만 아니라 운영체제 핵심 기능, 라이브러리, 설정값까지 싹 다 들어있습니다. 이 박스만 있으면 윈도우든 리눅스든 맥이든, 어디서든 똑같이 실행됩니다. 이게 바로 도커의 본질입니다.&lt;/p&gt;
&lt;hr data-path-to-node=&quot;13&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-path-to-node=&quot;14&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이2 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;3108603048&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;14&quot; data-ke-size=&quot;size23&quot;&gt;2. 가상 머신(VM)과 도커, 뭐가 다른데?&lt;/h3&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;보통 도커를 처음 배우면 &quot;어, 그럼 VMware나 VirtualBox 같은 가상 머신이랑 똑같은 거 아니야?&quot;라고 묻습니다. 결론부터 말씀드리면 **&quot;비슷하지만 훨씬 가볍고 빠르다&quot;**입니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;이해를 돕기 위해 &lt;b data-index-in-node=&quot;10&quot; data-path-to-node=&quot;16&quot;&gt;아파트와 고시원&lt;/b&gt; 비유를 들어볼게요.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;17&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,0,0&quot;&gt;가상 머신 (Virtual Machine):&lt;/b&gt; 아파트를 한 채 통째로 짓는 것입니다. 집마다 전용 현관문, 부엌, 화장실, 배관이 다 따로 있죠. 안전하고 독립적이지만, 짓는 데 오래 걸리고 자원(땅)을 많이 차지합니다. OS 위에 또 OS를 올리는 격이라 굉장히 무겁습니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,1,0&quot;&gt;도커 컨테이너 (Docker Container):&lt;/b&gt; 이미 지어진 건물에 방만 빌리는 방식입니다. 수도나 전기는 같이 쓰되(OS 커널 공유), 내 방 안에서는 내가 뭘 하든 간섭받지 않습니다. 방만 꾸미면 되니까 만드는 속도가 엄청나게 빠르고, 아파트 한 채 지을 자원에 방 수십 개를 만들 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;실제로 VM은 부팅하는 데 몇 분씩 걸리지만, 도커 컨테이너는 실행 명령을 내리는 즉시 1초 만에 뜹니다. 개발자에게 이 '속도'는 엄청난 축복이죠.&lt;/p&gt;
&lt;hr data-path-to-node=&quot;19&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-path-to-node=&quot;20&quot; data-ke-size=&quot;size23&quot;&gt;3. 도커의 핵심 삼인방: Dockerfile, Image, Container&lt;/h3&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;도커를 공부하다 보면 이 세 단어가 계속 나올 텐데요. 요리 과정에 비유하면 뇌에 박제할 수 있습니다.&lt;/p&gt;
&lt;h4 data-path-to-node=&quot;22&quot; data-ke-size=&quot;size20&quot;&gt;① Dockerfile (레시피)&lt;/h4&gt;
&lt;p data-path-to-node=&quot;23&quot; data-ke-size=&quot;size16&quot;&gt;&quot;라면을 끓이려면 물 500ml를 넣고, 스프를 먼저 넣고, 면을 넣어라&quot;라고 적힌 텍스트 파일입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;24&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FROM python:3.9 (파이썬 3.9 환경에서 시작해!)&lt;/li&gt;
&lt;li&gt;COPY . /app (내 소스 코드를 복사해 넣어!)&lt;/li&gt;
&lt;li&gt;CMD [&quot;python&quot;, &quot;main.py&quot;] (이걸 실행해!) 이렇게 명령어를 적어두는 설계도입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-path-to-node=&quot;25&quot; data-ke-size=&quot;size20&quot;&gt;② Image (밀키트)&lt;/h4&gt;
&lt;p data-path-to-node=&quot;26&quot; data-ke-size=&quot;size16&quot;&gt;설계도(레시피)를 바탕으로 실제 요리 재료들을 다 모아서 얼려놓은 &lt;b data-index-in-node=&quot;37&quot; data-path-to-node=&quot;26&quot;&gt;밀키트&lt;/b&gt;입니다. 이 밀키트는 변하지 않습니다(Immutable). 누가 사 가든, 어디서 뜯든 그 안의 재료는 항상 똑같죠. 이미지는 실행되기 전의 '상태'를 의미합니다.&lt;/p&gt;
&lt;h4 data-path-to-node=&quot;27&quot; data-ke-size=&quot;size20&quot;&gt;③ Container (완성된 요리)&lt;/h4&gt;
&lt;p data-path-to-node=&quot;28&quot; data-ke-size=&quot;size16&quot;&gt;밀키트를 뜯어서 냄비에 끓인 상태입니다. 실제로 서비스가 돌아가고 있는 &lt;b data-index-in-node=&quot;40&quot; data-path-to-node=&quot;28&quot;&gt;실체&lt;/b&gt;죠. 우리는 하나의 밀키트(이미지)로 수십 개의 요리(컨테이너)를 동시에 만들어낼 수 있습니다. 배달 주문이 밀리면(트래픽이 늘어나면) 냄비 수만 늘리면 되는 거죠.&lt;/p&gt;
&lt;hr data-path-to-node=&quot;29&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-path-to-node=&quot;30&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이1 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;5734766380&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;30&quot; data-ke-size=&quot;size23&quot;&gt;4. 개발자가 도커를 쓰면 얻는 개이득(Advantage) 3가지&lt;/h3&gt;
&lt;h4 data-path-to-node=&quot;31&quot; data-ke-size=&quot;size20&quot;&gt;첫째, &quot;Clean &amp;amp; Clear&quot; 내 컴퓨터가 깨끗해집니다.&lt;/h4&gt;
&lt;p data-path-to-node=&quot;32&quot; data-ke-size=&quot;size16&quot;&gt;예전에는 새로운 프로젝트를 할 때마다 온갖 DB와 라이브러리를 내 컴퓨터에 직접 깔았습니다. 프로젝트가 끝나도 지우기 귀찮아서 방치하다 보면 어느새 내 맥북은 쓰레기장이 되죠. 도커를 쓰면? 컨테이너만 지우면 끝입니다. 내 컴퓨터 본체는 언제나 쾌적합니다.&lt;/p&gt;
&lt;h4 data-path-to-node=&quot;33&quot; data-ke-size=&quot;size20&quot;&gt;둘째, 협업 효율의 극대화&lt;/h4&gt;
&lt;p data-path-to-node=&quot;34&quot; data-ke-size=&quot;size16&quot;&gt;&quot;저기, 제 컴퓨터에선 되는데...&quot;라는 말을 원천 봉쇄합니다. 모든 팀원이 동일한 이미지를 내려받아 실행하기 때문에, &quot;환경 설정 때문에 하루 버렸어요&quot;라는 핑계가 사라집니다. (이건 좀 슬픈 일일 수도 있겠네요...)&lt;/p&gt;
&lt;h4 data-path-to-node=&quot;35&quot; data-ke-size=&quot;size20&quot;&gt;셋째, 배포의 혁명&lt;/h4&gt;
&lt;p data-path-to-node=&quot;36&quot; data-ke-size=&quot;size16&quot;&gt;로컬에서 테스트 완료한 이미지를 그대로 서버에 올리기만 하면 됩니다. &quot;서버 가니까 라이브러리 버전이 다르네?&quot; 같은 공포스러운 상황에서 해방됩니다. CI/CD 파이프라인의 핵심이 바로 이 도커입니다.&lt;/p&gt;
&lt;hr data-path-to-node=&quot;37&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-path-to-node=&quot;38&quot; data-ke-size=&quot;size23&quot;&gt;5. 마치며: 고래 등에 올라타는 것을 두려워하지 마세요&lt;/h3&gt;
&lt;p data-path-to-node=&quot;39&quot; data-ke-size=&quot;size16&quot;&gt;처음엔 터미널에 명령어를 치는 게 낯설고, 네트워크 설정이나 볼륨 마운트 같은 개념이 어렵게 느껴질 수 있습니다. 하지만 한 번 익숙해지고 나면, 도커 없는 개발 인생으로는 절대 돌아갈 수 없을 겁니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;40&quot; data-ke-size=&quot;size16&quot;&gt;마치 피처폰을 쓰다가 스마트폰을 처음 썼을 때의 충격 같달까요? 여러분의 소중한 코드가 어떤 환경에서도 당당하게 돌아갈 수 있도록, 오늘 당장 docker run 한 번 쳐보시는 건 어떨까요?&lt;/p&gt;
&lt;p data-path-to-node=&quot;41&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;41&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-format=&quot;autorelaxed&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;1002348295&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;</description>
      <category>게으른 개발자의 끄적거림</category>
      <category>Docker</category>
      <category>docker 설명</category>
      <category>docker 설정</category>
      <category>docker 이미지</category>
      <category>docker 컨테이너</category>
      <category>docker 환경</category>
      <category>Docker란</category>
      <category>도커</category>
      <category>독커</category>
      <author>끄적잉</author>
      <guid isPermaLink="true">https://play-with.tistory.com/417</guid>
      <comments>https://play-with.tistory.com/417#entry417comment</comments>
      <pubDate>Tue, 10 Feb 2026 22:55:46 +0900</pubDate>
    </item>
    <item>
      <title>외부망없이 드라이버 설치 방법 총정리</title>
      <link>https://play-with.tistory.com/416</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;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이1 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;5734766380&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  1. 설치가 필요한 드라이버 파악&lt;/h3&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;b&gt;필요한 드라이버 예시:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그래픽 카드 드라이버&lt;/li&gt;
&lt;li&gt;사운드 드라이버&lt;/li&gt;
&lt;li&gt;LAN/Wi-Fi 드라이버&lt;/li&gt;
&lt;li&gt;칩셋 드라이버&lt;/li&gt;
&lt;li&gt;터치패드/기타 장치 드라이버&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;방법:&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;노트북을 켜고 장치 관리자를 실행 (Win + X &amp;rarr; 장치 관리자)&lt;/li&gt;
&lt;li&gt;노란 느낌표가 있는 장치를 확인&lt;/li&gt;
&lt;li&gt;장치 이름을 메모하거나, 하드웨어 ID로 검색&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이2 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;3108603048&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  2. 드라이버 설치 파일 준비 (인터넷 연결 가능한 다른 PC에서)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터넷이 되는 다른 PC나 노트북에서 해당 드라이버 설치 파일을 다운로드합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✅ 방법 A: 제조사 공식 홈페이지 이용&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;다른 PC에서 노트북 제조사 홈페이지 접속&lt;/li&gt;
&lt;li&gt;제품 모델명을 입력하여 검색&lt;/li&gt;
&lt;li&gt;드라이버 및 유틸리티 다운로드 항목에서 필요한 드라이버들을 다운로드&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&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;Lenovo: &lt;a href=&quot;https://support.lenovo.com&quot;&gt;https://support.lenovo.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;HP: &lt;a href=&quot;https://support.hp.com&quot;&gt;https://support.hp.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Dell: &lt;a href=&quot;https://www.dell.com/support&quot;&gt;https://www.dell.com/support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ASUS: &lt;a href=&quot;https://www.asus.com/support&quot;&gt;https://www.asus.com/support&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;✅ 방법 B: 드라이버 백업 (이미 설치된 동일 모델 노트북이 있을 때)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Double Driver 또는 DriverBackup! 같은 프로그램을 이용해, 동일 모델 노트북에서 드라이버를 백업해 복사할 수 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이1 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;5734766380&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  3. 설치 파일을 오프라인 노트북으로 복사&lt;/h3&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;USB 메모리&lt;/li&gt;
&lt;li&gt;외장 하드&lt;/li&gt;
&lt;li&gt;SD 카드 등&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ 바이러스가 없도록 사전에 USB를 검사하세요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  4. 노트북에 드라이버 설치&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;USB 또는 저장장치를 오프라인 노트북에 연결&lt;/li&gt;
&lt;li&gt;복사한 드라이버 설치 파일 실행 (.exe 파일이면 직접 실행, .inf 파일이면 오른쪽 클릭 &amp;rarr; 설치)&lt;/li&gt;
&lt;li&gt;필요한 경우 재부팅&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이1 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;5734766380&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  5. 자동 드라이버 설치 프로그램 사용 (선택사항)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오프라인에서도 사용 가능한 드라이버 패키지를 준비할 수 있습니다.&lt;/p&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;&lt;b&gt;Snappy Driver Installer Origin (SDIO)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;공식 사이트: &lt;a href=&quot;https://www.snappy-driver-installer.org/&quot;&gt;https://www.snappy-driver-installer.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Full&amp;rdquo; 버전을 다른 PC에서 받아 USB에 넣으면 오프라인으로 설치 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  장점: 모든 드라이버를 한 번에 검색 및 설치 가능&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-format=&quot;autorelaxed&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;1002348295&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;</description>
      <category>게으른 개발자의 끄적거림</category>
      <category>노트북 드라이버 설치</category>
      <category>노트북 드라이버 외부망</category>
      <category>드라이버 설치</category>
      <category>외부망 없이 드라이버 설치</category>
      <category>외부망없이 노트북 드라이버</category>
      <category>인터넷없이 노트북 드라이버</category>
      <category>인터넷없이 노트북 드라이버 설치</category>
      <category>인터넷없이 드라이버</category>
      <category>인터넷없이 드라이버 설치</category>
      <author>끄적잉</author>
      <guid isPermaLink="true">https://play-with.tistory.com/416</guid>
      <comments>https://play-with.tistory.com/416#entry416comment</comments>
      <pubDate>Wed, 27 Aug 2025 20:57:17 +0900</pubDate>
    </item>
    <item>
      <title>Map, HashMap, TreeMap 완벽 정리</title>
      <link>https://play-with.tistory.com/415</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Map (인터페이스)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 먼저 이해해야 할 것은 Map이 인터페이스(Interface)라는 점입니다. 자바 컬렉션 프레임워크에서 Map은 **키(key)**와 **값(value)**을 한 쌍으로 묶어 저장하는 데이터 구조의 규약(청사진)을 정의합니다. Map 자체는 객체로 생성할 수 없으며, 이 인터페이스를 구현하는 구체적인 클래스들(예: HashMap, TreeMap, LinkedHashMap)을 통해 기능을 사용할 수 있습니다.&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;b&gt;키(Key)의 고유성:&lt;/b&gt; 모든 키는 유일해야 합니다. 동일한 키로 값을 추가하면 기존의 값은 새로운 값으로 덮어쓰여집니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;키-값 쌍:&lt;/b&gt; 키를 통해 값에 빠르게 접근할 수 있습니다. 마치 사전에서 단어를 찾아 그 의미를 확인하는 것과 같습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;순서 없음:&lt;/b&gt; Map 인터페이스 자체는 요소의 순서를 보장하지 않습니다. (TreeMap은 예외적으로 정렬된 순서를 가집니다.)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;null 허용:&lt;/b&gt; 대부분의 구현체는 키나 값에 null을 허용합니다. (단, TreeMap은 키에 null을 허용하지 않습니다.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Map 인터페이스가 제공하는 주요 메서드는 다음과 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;put(key, value): 키와 값을 저장합니다.&lt;/li&gt;
&lt;li&gt;get(key): 주어진 키에 해당하는 값을 반환합니다.&lt;/li&gt;
&lt;li&gt;remove(key): 키에 해당하는 키-값 쌍을 삭제합니다.&lt;/li&gt;
&lt;li&gt;containsKey(key): 해당 키가 존재하는지 확인합니다.&lt;/li&gt;
&lt;li&gt;keySet(): Map에 있는 모든 키들을 Set 형태로 반환합니다.&lt;/li&gt;
&lt;li&gt;entrySet(): Map에 있는 모든 키-값 쌍(Entry)을 Set 형태로 반환합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이1 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;5734766380&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Map은 키를 사용하여 데이터를 조회하는 작업이 빈번할 때 매우 효율적입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. HashMap (빠른 비정렬 맵)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HashMap은 Map 인터페이스의 가장 대표적인 구현체입니다. &lt;b&gt;키를 기반으로 데이터를 빠르게 탐색해야 할 때&lt;/b&gt; 사용되며, 내부적으로 &lt;b&gt;해시 테이블(Hash Table)&lt;/b&gt; 자료구조를 사용합니다.&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;HashMap은 키에 대해 **해시 함수(Hash Function)**를 적용하여 해시 코드를 생성하고, 이 해시 코드를 통해 배열의 인덱스(버킷)를 결정합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;키-값 저장 시:&lt;/b&gt; put(key, value)를 호출하면, 먼저 키의 hashCode() 메서드를 호출하여 해시 코드를 얻습니다. 이 해시 코드를 배열의 크기에 맞게 가공하여 인덱스를 계산하고, 해당 인덱스에 키-값 쌍을 저장합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;충돌(Collision) 처리:&lt;/b&gt; 여러 개의 키가 동일한 인덱스로 매핑되는 &lt;b&gt;해시 충돌&lt;/b&gt;이 발생할 수 있습니다. HashMap은 이를 해결하기 위해 각 배열 인덱스에 연결 리스트(Linked List)나 트리(Tree)를 사용하여 충돌을 처리합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;키-값 조회 시:&lt;/b&gt; get(key)를 호출하면, 저장할 때와 마찬가지로 키의 hashCode()를 통해 인덱스를 찾습니다. 해당 인덱스에 저장된 요소들 중에서 equals() 메서드를 이용해 찾는 키와 동일한 요소를 찾아 반환합니다.&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;&lt;b&gt;성능:&lt;/b&gt; 평균적으로 put, get, remove 연산의 시간 복잡도는 &lt;b&gt;O(1)&lt;/b&gt; 입니다. 해시 함수가 키를 고르게 분산시킬 경우 매우 빠릅니다. 최악의 경우(모든 키가 동일한 해시 코드를 가질 경우)는 O(n)까지 느려질 수 있지만, 일반적으로는 발생하지 않습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;순서 없음:&lt;/b&gt; HashMap은 저장된 순서를 보장하지 않으며, 정렬되어 있지도 않습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;null 허용:&lt;/b&gt; 하나의 null 키와 여러 개의 null 값을 가질 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동기화:&lt;/b&gt; &lt;b&gt;스레드에 안전하지 않습니다(Non-Synchronized).&lt;/b&gt; 멀티스레드 환경에서 사용하려면 Collections.synchronizedMap()을 사용하거나, ConcurrentHashMap을 사용해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HashMap은 데이터의 삽입, 삭제, 조회가 가장 빠른 맵으로, 일반적인 용도에서 가장 많이 사용됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이2 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;3108603048&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. TreeMap (정렬된 맵)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TreeMap은 Map 인터페이스를 구현하며, &lt;b&gt;데이터를 키를 기준으로 정렬하여 저장&lt;/b&gt;합니다. 내부적으로는 **레드-블랙 트리(Red-Black Tree)**라는 균형 이진 탐색 트리를 사용합니다.&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;TreeMap은 키-값 쌍을 트리에 저장하며, 새로운 요소가 추가될 때마다 트리의 균형을 유지하고 정렬된 상태를 만듭니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;정렬 기준:&lt;/b&gt; 키의 &lt;b&gt;자연적 순서(Natural Ordering)&lt;/b&gt; 또는 생성 시 제공된 **Comparator**에 따라 정렬됩니다. Integer, String 같은 기본 클래스는 자연적 순서가 정의되어 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;탐색:&lt;/b&gt; 트리의 루트 노드에서 시작하여 키를 비교하며 내려가기 때문에, 삽입, 삭제, 검색에 일정한 성능을 보장합니다.&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;&lt;b&gt;성능:&lt;/b&gt; put, get, remove 연산의 시간 복잡도는 항상 &lt;b&gt;O(log n)&lt;/b&gt; 입니다. HashMap의 평균적인 성능(O(1))보다는 느리지만, HashMap의 최악의 경우(O(n))보다는 빠르고 안정적입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;순서 보장:&lt;/b&gt; 키를 기준으로 오름차순으로 정렬된 상태를 항상 유지합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;null 키 불가능:&lt;/b&gt; 키를 비교해야 하므로 null 키는 허용하지 않습니다. null 값은 허용합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동기화:&lt;/b&gt; HashMap과 마찬가지로 &lt;b&gt;스레드에 안전하지 않습니다(Non-Synchronized).&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TreeMap은 키의 순서&lt;/p&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이1 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;5734766380&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가 중요하거나, 정렬된 데이터를 반복적으로 조회해야 할 때 유용합니다. 예를 들어, 특정 범위 내의 키-값 쌍을 찾거나(subMap), 최소/최대 키를 찾는 등의 작업에 적합합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 핵심 비교 및 요약&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;구분&lt;/td&gt;
&lt;td&gt;HashMap&lt;/td&gt;
&lt;td&gt;TreeMap&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;내부 자료구조&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;해시 테이블(Hash Table)&lt;/td&gt;
&lt;td&gt;레드-블랙 트리(Red-Black Tree)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;성능 (시간 복잡도)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;삽입, 삭제, 검색 평균 O(1)&lt;/td&gt;
&lt;td&gt;삽입, 삭제, 검색 O(log n)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;데이터 순서&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;보장하지 않음 (무작위)&lt;/td&gt;
&lt;td&gt;키를 기준으로 오름차순 정렬&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;null 키 허용&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;허용 (단, 1개만)&lt;/td&gt;
&lt;td&gt;허용하지 않음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;주요 활용 사례&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;- 순서가 중요하지 않은 일반적인 맵 &amp;lt;br&amp;gt; - 빠른 조회/삽입/삭제가 필요한 경우&lt;/td&gt;
&lt;td&gt;- 키의 순서가 중요한 경우 &amp;lt;br&amp;gt; - 정렬된 데이터를 반복적으로 조회해야 할 때 &amp;lt;br&amp;gt; - 범위 검색(range search)이 필요한 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;- 가장 빠른 성능 &amp;lt;br&amp;gt; - 범용적으로 사용 가능&lt;/td&gt;
&lt;td&gt;- 항상 정렬된 상태 유지 &amp;lt;br&amp;gt; - 예측 가능한 안정적인 성능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;- 순서가 없어 순차 접근 시 비효율적 &amp;lt;br&amp;gt; - 해시 충돌 시 성능 저하 가능성&lt;/td&gt;
&lt;td&gt;- HashMap보다 느림 &amp;lt;br&amp;gt; - 메모리 사용량이 상대적으로 많음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 결론: 언제 무엇을 사용해야 하는가?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;HashMap을 사용하세요:&lt;/b&gt; 대부분의 경우 HashMap이 가장 좋은 선택입니다. &lt;b&gt;데이터의 순서가 중요하지 않고, 가장 빠른 데이터 접근 및 조작 성능이 필요할 때&lt;/b&gt; 사용합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;TreeMap을 사용하세요:&lt;/b&gt; &lt;b&gt;키를 기준으로 정렬된 상태로 데이터를 유지해야 할 필요가 있거나, 키를 기준으로 범위 검색(예: &quot;100~200번 키에 해당하는 데이터&quot;)을 해야 할 때&lt;/b&gt; 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-format=&quot;autorelaxed&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;1002348295&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>게으른 개발자의 끄적거림</category>
      <category>Hash Tree</category>
      <category>hash vs tree Map</category>
      <category>HashMap</category>
      <category>HashMap TreeMap</category>
      <category>hashMap vs TreeMap</category>
      <category>map</category>
      <category>map hashmap treemap</category>
      <category>TreeMap</category>
      <category>맵이란?</category>
      <category>해시맵 트리맵</category>
      <author>끄적잉</author>
      <guid isPermaLink="true">https://play-with.tistory.com/415</guid>
      <comments>https://play-with.tistory.com/415#entry415comment</comments>
      <pubDate>Tue, 5 Aug 2025 14:17:39 +0900</pubDate>
    </item>
    <item>
      <title>.xfdl 파일이란? (넥사크로 파일이란?)</title>
      <link>https://play-with.tistory.com/414</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;.xfdl 파일은 주로 **넥사크로플랫폼(nexacro platform)**에서 사용되는 UI(사용자 인터페이스) 정의 파일입니다. 넥사크로플랫폼은 투비소프트(TOBESOFT)에서 개발한 &lt;b&gt;RIA(Rich Internet Application) 개발 도구이자 프레임워크&lt;/b&gt;입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이1 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;5734766380&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;.xfdl 파일의 특징 및 역할&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;UI/UX 화면 정의:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;.xfdl 파일은 넥사크로플랫폼에서 사용자에게 보여지는 화면의 레이아웃, 컴포넌트(버튼, 그리드, 텍스트박스, 콤보박스 등), 그리고 이 컴포넌트들의 속성(크기, 위치, 색상, 글꼴 등)을 정의하는 XML 기반의 파일입니다.&lt;/li&gt;
&lt;li&gt;비주얼 스튜디오(Visual Studio)나 이클립스(Eclipse) 같은 IDE에서 GUI(Graphical User Interface) 기반의 넥사크로 스튜디오(nexacro studio)를 사용하여 화면을 디자인하면, 그 결과물이 .xfdl 파일로 저장됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;XML 기반 구조:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파일 내용은 XML(eXtensible Markup Language) 형식으로 작성되어 있습니다. 따라서 텍스트 편집기로도 열어볼 수 있지만, 사람이 직접 편집하기보다는 넥사크로 스튜디오를 통해 시각적으로 편집하는 것이 일반적입니다.&lt;/li&gt;
&lt;li&gt;XML 태그와 속성을 통해 각 컴포넌트의 종류, 이름, 위치, 크기, 이벤트 핸들러 연결 등을 명시합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 바인딩 및 이벤트 처리 정의:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;.xfdl 파일 내에서는 화면 컴포넌트와 데이터셋(Dataset) 간의 데이터 바인딩 정보도 정의할 수 있습니다. 예를 들어, 그리드 컴포넌트가 어떤 데이터셋의 데이터를 표시할지, 특정 입력 필드가 어떤 데이터셋의 특정 컬럼과 연결될지 등을 설정합니다.&lt;/li&gt;
&lt;li&gt;버튼 클릭 시, 데이터 변경 시 등과 같은 **이벤트 처리 로직(스크립트)**도 .xfdl 파일 내에 또는 별도의 .js 파일로 연결하여 정의됩니다. (주로 JavaScript를 사용)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;클라이언트 런타임 환경:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;넥사크로플랫폼으로 개발된 애플리케이션은 웹(HTML5), 데스크톱(넥사크로 런타임), 모바일(앱) 등 다양한 환경에서 실행될 수 있습니다. .xfdl 파일은 이 런타임 환경에서 화면을 구성하고 동작을 제어하는 데 사용되는 핵심 자원입니다.&lt;/li&gt;
&lt;li&gt;사용자가 넥사크로 애플리케이션에 접속하면 서버로부터 .xfdl 파일을 다운로드하여 클라이언트 런타임 엔진이 이를 해석하고 화면을 구성하게 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다국어 지원 및 확장성:&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;.xfdl 파일은 다국어 처리를 위한 리소스 관리 기능도 포함할 수 있으며, 개발자가 직접 정의한 사용자 정의 컴포넌트나 라이브러리를 포함하여 확장성을 가집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이2 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;3108603048&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;넥사크로플랫폼과 .xfdl 파일의 역할&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;넥사크로플랫폼은 &quot;One Source Multi Use&quot;를 지향하며, 하나의 소스 코드(여기서 .xfdl 파일 및 관련 스크립트)로 웹, 모바일, 데스크톱 환경에 대응하는 애플리케이션을 개발할 수 있도록 합니다. .xfdl 파일은 이러한 유연한 아키텍처의 중심에 있습니다.&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;b&gt;무엇인가?&lt;/b&gt; 넥사크로플랫폼에서 사용하는 XML 기반의 UI 화면 정의 파일.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;어떤 내용을 담고 있는가?&lt;/b&gt; 화면 레이아웃, 컴포넌트 정보, 데이터 바인딩, 이벤트 스크립트 등.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;왜 사용하는가?&lt;/b&gt; 넥사크로 스튜디오를 통해 시각적으로 빠르게 UI를 디자인하고, One Source Multi Use 환경에서 다양한 플랫폼에 대응하는 애플리케이션을 구축하기 위함.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 넥사크로플랫폼 개발 환경에 계신다면, 이 .xfdl 파일을 통해 화면을 구현하고 백엔드와 연동하는 작업을 하실 것입니다.&lt;/p&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;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-format=&quot;autorelaxed&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;1002348295&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;</description>
      <category>게으른 개발자의 끄적거림</category>
      <category>.xfdl</category>
      <category>.xfdl이란?</category>
      <category>xfdl</category>
      <category>xfdl 넥사크로</category>
      <category>xfdl 파일 넥사크로</category>
      <category>xfdl 파일 사용법</category>
      <category>xfdl 파일 예제</category>
      <category>xfdl파일</category>
      <category>xfdl파일이란?</category>
      <author>끄적잉</author>
      <guid isPermaLink="true">https://play-with.tistory.com/414</guid>
      <comments>https://play-with.tistory.com/414#entry414comment</comments>
      <pubDate>Wed, 30 Jul 2025 15:09:09 +0900</pubDate>
    </item>
    <item>
      <title>리덕스란? (Redux 완벽 정리)</title>
      <link>https://play-with.tistory.com/413</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;리덕스란!???&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;웹 개발의 세계는 끊임없이 진화하고 있으며, 특히 사용자 인터랙션이 많아지고 데이터 흐름이 복잡해지는 현대 웹 애플리케이션에서는 &lt;b&gt;'상태 관리(State Management)'&lt;/b&gt; 가 개발의 성패를 좌우하는 핵심 요소가 되었습니다. 오늘 이 블로그 포스팅에서는 React와 같은 프런트엔드 라이브러리/프레임워크와 환상의 궁합을 자랑하며, 전역 상태 관리에 있어 독보적인 위치를 차지하고 있는 라이브러리, &lt;b&gt;Redux&lt;/b&gt;에 대해 깊이 있게 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 사용법을 나열하는 것을 넘어, Redux가 왜 필요하고 어떤 철학을 가지고 있으며, 여러분의 애플리케이션에 어떻게 강력한 힘을 실어줄 수 있는지 자세히 파헤쳐 보겠습니다. 이 글을 통해 Redux의 본질을 이해하고, 여러분의 다음 프로젝트에 자신 있게 적용할 수 있기를 바랍니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. Redux, 왜 필요한가요? - 상태 관리의 복잡성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모던 웹 애플리케이션은 사용자 로그인 상태, 장바구니 품목, UI 테마, 데이터 로딩 상태 등 다양한 종류의 '상태'를 가집니다. 애플리케이션의 규모가 커지고 컴포넌트 간의 관계가 복잡해질수록 다음과 같은 문제가 발생합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;컴포넌트 간의 상태 공유 어려움 (Prop Drilling):&lt;/b&gt; 상위 컴포넌트에서 하위 컴포넌트로 상태를 전달하기 위해 여러 단계를 거쳐 Props를 '드릴'처럼 뚫고 내려가야 합니다. 이는 코드를 읽기 어렵게 만들고 유지보수를 힘들게 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;예측 불가능한 상태 변화:&lt;/b&gt; 여러 컴포넌트에서 동일한 상태를 변경할 수 있게 되면, 어떤 컴포넌트가 언제 어떻게 상태를 변경했는지 추적하기 어려워집니다. 이는 버그 발생의 주원인이 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디버깅의 어려움:&lt;/b&gt; 상태가 여기저기 흩어져 있거나 비동기적으로 복잡하게 변경되면, 버그 발생 시 문제의 원인을 찾아내기가 매우 어려워집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux는 이러한 문제들을 해결하기 위해 탄생했습니다. 애플리케이션의 모든 상태를 예측 가능하고 일관된 방식으로 관리하는 단일 저장소(Store)를 제공하는 것이 핵심입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이1 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;5734766380&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. Redux의 세 가지 핵심 원칙 (Principles)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux는 세 가지 매우 중요한 원칙을 기반으로 합니다. 이 원칙들을 이해하는 것이 Redux를 제대로 활용하는 첫걸음입니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;단일 진실 공급원 (Single Source of Truth):&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;애플리케이션의 모든 상태는 &lt;b&gt;하나의 커다란 자바스크립트 객체 트리&lt;/b&gt; 형태로 &lt;b&gt;하나의 Store&lt;/b&gt; 안에 저장됩니다.&lt;/li&gt;
&lt;li&gt;마치 은행에 하나의 중앙 데이터베이스가 모든 고객의 잔액 정보를 관리하듯이, Redux는 애플리케이션의 모든 데이터를 한 곳에서 관리합니다. 이는 상태의 일관성과 예측 가능성을 극대화합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;상태는 읽기 전용이다 (State is Read-Only):&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상태를 직접 변경할 수 없습니다. 상태를 변경하고 싶다면, 반드시 &lt;b&gt;액션(Action)&lt;/b&gt; 이라는 일반 자바스크립트 객체를 통해 변경 의도를 표현해야 합니다.&lt;/li&gt;
&lt;li&gt;마치 법률 시스템에서 모든 변경 요청이 공식적인 서류(액션)를 통해 이루어지는 것처럼, Redux의 상태 변경은 투명하고 기록 가능합니다. 이는 어떤 변경이 왜 일어났는지 추적하기 쉽게 만듭니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;변화는 리듀서에 의해 이루어져야 한다 (Changes are Made with Pure Functions / Reducers):&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;액션에 의해 상태가 어떻게 변경될지는 &lt;b&gt;리듀서(Reducer)&lt;/b&gt; 라는 &lt;b&gt;순수 함수(Pure Function)&lt;/b&gt; 에 의해 정의됩니다.&lt;/li&gt;
&lt;li&gt;순수 함수란:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동일한 입력(State와 Action)에는 항상 동일한 출력(새로운 State)을 반환합니다.&lt;/li&gt;
&lt;li&gt;함수 외부의 어떤 것도 변경하지 않습니다 (Side Effect 없음).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;리듀서는 현재 상태와 액션을 받아서, 새로운 상태를 반환합니다. 이 과정에서 &lt;b&gt;기존 상태를 직접 변경(Mutation)하지 않고, 항상 새로운 상태 객체를 생성하여 반환&lt;/b&gt;해야 합니다.&lt;/li&gt;
&lt;li&gt;이는 예측 가능한 상태 변화를 보장하고, 디버깅을 용이하게 하며, 시간 여행 디버깅(Time-Travel Debugging)과 같은 강력한 도구를 가능하게 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이2 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;3108603048&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. Redux의 주요 구성 요소 (Core Components)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux는 몇 가지 핵심적인 구성 요소들이 유기적으로 연결되어 동작합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Store (스토어):&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Redux의 핵심이자 모든 상태를 담고 있는 &lt;b&gt;단 하나의 객체&lt;/b&gt;입니다.&lt;/li&gt;
&lt;li&gt;상태를 저장하고, 상태를 업데이트하며, 상태 변경을 구독(Subscribe)할 수 있는 메서드를 제공합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Action (액션):&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상태 변경을 위한 &lt;b&gt;&quot;무엇이 일어났는지&quot;를 설명하는 객체&lt;/b&gt;입니다.&lt;/li&gt;
&lt;li&gt;필수적으로 type 속성을 가져야 하며, 이 type은 어떤 종류의 액션인지 문자열로 정의합니다. (예: { type: 'ADD_TODO', text: 'Learn Redux' })&lt;/li&gt;
&lt;li&gt;액션은 상태를 직접 변경하지 않고, 단지 변경 &quot;의도&quot;만을 전달합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Reducer (리듀서):&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;액션을 받아서 &lt;b&gt;&quot;상태를 어떻게 변경할지&quot;를 정의하는 순수 함수&lt;/b&gt;입니다.&lt;/li&gt;
&lt;li&gt;(previousState, action) =&amp;gt; newState 형태를 가집니다.&lt;/li&gt;
&lt;li&gt;이전 상태와 액션을 인자로 받아 새로운 상태를 반환합니다. &lt;b&gt;절대 이전 상태를 직접 변경해서는 안 됩니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Dispatcher (디스패처 - Store의 메서드):&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;store.dispatch(action) 메서드를 통해 액션을 Redux Store로 보내는(전달하는) 역할을 합니다.&lt;/li&gt;
&lt;li&gt;이 메서드가 호출되면, Redux는 해당 액션을 모든 리듀서에게 전달하여 상태를 업데이트합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Selector (셀렉터):&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Store의 상태(State)에서 &lt;b&gt;원하는 데이터를 추출하는 함수&lt;/b&gt;입니다.&lt;/li&gt;
&lt;li&gt;UI 컴포넌트가 Store에서 필요한 데이터만 효율적으로 가져올 수 있도록 돕습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. Redux의 동작 흐름 (Flow)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux의 데이터 흐름은 단방향(Unidirectional Data Flow)입니다. 이 일관된 흐름은 상태 변화를 예측 가능하게 만듭니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;사용자 인터랙션 발생:&lt;/b&gt; UI(React 컴포넌트)에서 사용자의 클릭, 입력 등 어떤 이벤트가 발생합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Action Dispatch:&lt;/b&gt; 이벤트 핸들러는 store.dispatch(action) 메서드를 호출하여 상태 변경을 위한 &lt;b&gt;Action 객체&lt;/b&gt;를 Store로 보냅니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Reducer 호출:&lt;/b&gt; Store는 전달받은 Action을 모든 &lt;b&gt;Reducer 함수&lt;/b&gt;에게 전달합니다. (실제로는 Root Reducer에게 전달되고, Root Reducer가 하위 Reducer들에게 전달합니다.)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;State 변경:&lt;/b&gt; Reducer는 현재 상태와 Action을 기반으로 &lt;b&gt;새로운 상태 객체를 생성하여 반환&lt;/b&gt;합니다. (기존 상태는 변경하지 않음)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Store 업데이트:&lt;/b&gt; Store는 Reducer가 반환한 새로운 상태로 자신의 상태를 업데이트합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;UI 렌더링:&lt;/b&gt; Store의 상태가 변경되면, Store를 구독(Subscribe)하고 있던 UI 컴포넌트들이 변경된 상태를 감지하고, 필요한 경우 새로운 데이터로 &lt;b&gt;다시 렌더링&lt;/b&gt;됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 흐름은 항상 동일하게 반복되며, 어떤 상태 변화든 이 흐름을 따라가기 때문에 디버깅이 매우 용이합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이1 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;5734766380&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5. Redux의 장점 (Advantages)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;예측 가능한 상태 관리:&lt;/b&gt; 단일 진실 공급원, 읽기 전용 상태, 순수 리듀서라는 원칙 덕분에 상태 변화가 매우 예측 가능하며 일관적입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;쉬운 디버깅:&lt;/b&gt; 모든 상태 변화가 액션이라는 기록으로 남아 있기 때문에, Redux DevTools를 사용하면 상태 변화의 과정을 시간 여행하듯이 추적하고 재현할 수 있습니다. 이는 버그를 찾는 데 엄청난 도움이 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;중앙 집중식 상태:&lt;/b&gt; 모든 상태가 한 곳에 모여 있어 컴포넌트 간의 상태 공유가 매우 효율적입니다. Props Drilling 문제를 해결할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;유지보수 용이성:&lt;/b&gt; 상태 변화 로직이 리듀서에 명확히 분리되어 있어, 코드의 가독성이 높아지고 유지보수가 용이해집니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서버 사이드 렌더링(SSR) 지원:&lt;/b&gt; 서버와 클라이언트 간의 상태 동기화를 쉽게 할 수 있어 SSR에 유리합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;강력한 미들웨어 생태계:&lt;/b&gt; 비동기 작업(API 호출 등)을 처리하기 위한 Redux Thunk, Redux Saga와 같은 미들웨어와, 로깅, 크래시 리포팅 등을 위한 다양한 미들웨어를 활용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;6. Redux의 단점 및 고려 사항 (Disadvantages &amp;amp; Considerations)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux는 만능이 아니며, 모든 프로젝트에 필수적인 것은 아닙니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;보일러플레이트 코드 (Boilerplate Code):&lt;/b&gt; 특히 초기 설정 시 액션 타입, 액션 생성자, 리듀서 등 작성해야 할 코드가 많아 복잡하게 느껴질 수 있습니다. 이는 Redux Toolkit의 등장으로 많이 해소되었습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;학습 곡선:&lt;/b&gt; 초보 개발자에게는 Redux의 개념(액션, 리듀서, 미들웨어 등)과 단방향 데이터 흐름을 이해하는 데 시간이 필요할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;과도한 사용:&lt;/b&gt; 작은 규모의 애플리케이션에서는 Redux를 도입하는 것이 오히려 복잡성을 증가시킬 수 있습니다. 컴포넌트 내부 상태(Local State)나 React Context API만으로도 충분한 경우가 많습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능 최적화:&lt;/b&gt; 상태가 변경될 때마다 관련 컴포넌트가 다시 렌더링될 수 있으므로, React.memo, useCallback, useMemo 등을 활용한 렌더링 최적화에 신경 써야 합니다. (물론 React 자체의 문제입니다.)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;7. Redux Toolkit: Redux 개발을 더 쉽고 효율적으로!&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux의 보일러플레이트와 복잡성 문제를 해결하기 위해 공식적으로 권장되는 도구 모음이 바로 &lt;b&gt;Redux Toolkit (RTK)&lt;/b&gt; 입니다. RTK는 다음과 같은 주요 기능들을 제공하여 Redux 개발 경험을 획기적으로 개선합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;configureStore:&lt;/b&gt; Redux Store를 쉽게 설정할 수 있으며, Redux Thunk와 Redux DevTools Extension이 기본으로 포함됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;createSlice:&lt;/b&gt; 액션 타입, 액션 생성자, 리듀서를 한 번에 정의할 수 있게 해주는 함수입니다. 이를 통해 보일러플레이트 코드를 대폭 줄일 수 있습니다. (상태를 '슬라이스' 단위로 관리)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;createAsyncThunk:&lt;/b&gt; 비동기 로직(API 호출 등)을 쉽게 처리할 수 있는 액션 생성자를 생성합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;createEntityAdapter:&lt;/b&gt; 정규화된 상태를 관리할 때 유용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux를 새로 시작하거나 기존 프로젝트에 도입한다면, &lt;b&gt;반드시 Redux Toolkit을 사용하는 것을 강력히 권장합니다.&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;마무리하며&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redux는 복잡한 웹 애플리케이션의 상태 관리를 위한 매우 강력하고 성숙한 라이브러리입니다. 그 예측 가능한 단방향 데이터 흐름과 단일 진실 공급원이라는 철학은 대규모 프로젝트에서 빛을 발하며, 효율적인 디버깅과 유지보수를 가능하게 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론, Redux가 모든 프로젝트의 만병통치약은 아니며, 작은 규모의 애플리케이션에서는 과도한 오버헤드일 수 있습니다. 하지만 여러분의 애플리케이션이 성장하고 상태 관리가 점점 더 복잡해진다면, Redux는 여러분에게 질서와 통제력을 제공하는 든든한 아군이 될 것입니다.&lt;/p&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;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-format=&quot;autorelaxed&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;1002348295&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>게으른 개발자의 끄적거림</category>
      <category>Redux</category>
      <category>redux 설명</category>
      <category>redux 예제</category>
      <category>redux가 뭔가요</category>
      <category>redux란?</category>
      <category>리덕스</category>
      <category>리덕스 설명</category>
      <category>리덕스 예제</category>
      <category>리덕스가 뭔가요</category>
      <category>리덕스란?</category>
      <author>끄적잉</author>
      <guid isPermaLink="true">https://play-with.tistory.com/413</guid>
      <comments>https://play-with.tistory.com/413#entry413comment</comments>
      <pubDate>Wed, 30 Jul 2025 09:54:46 +0900</pubDate>
    </item>
    <item>
      <title>FIDO 인증이란? (FIDO 완벽 정리)</title>
      <link>https://play-with.tistory.com/412</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;##&amp;nbsp;FIDO&amp;nbsp;인증에&amp;nbsp;대한&amp;nbsp;심층&amp;nbsp;분석:&amp;nbsp;비밀번호&amp;nbsp;없는&amp;nbsp;강력하고&amp;nbsp;편리한&amp;nbsp;인증의&amp;nbsp;미래 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이1 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;5734766380&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;###&amp;nbsp;1.&amp;nbsp;서론:&amp;nbsp;FIDO의&amp;nbsp;등장&amp;nbsp;배경과&amp;nbsp;미션 &lt;br /&gt;&lt;br /&gt;오늘날&amp;nbsp;디지털&amp;nbsp;세상에서&amp;nbsp;우리는&amp;nbsp;수많은&amp;nbsp;온라인&amp;nbsp;서비스에&amp;nbsp;접근하기&amp;nbsp;위해&amp;nbsp;비밀번호를&amp;nbsp;사용하고&amp;nbsp;있습니다.&amp;nbsp;그러나&amp;nbsp;비밀번호는&amp;nbsp;**피싱(Phishing),&amp;nbsp;자격&amp;nbsp;증명&amp;nbsp;스터핑(Credential&amp;nbsp;Stuffing),&amp;nbsp;무작위&amp;nbsp;대입&amp;nbsp;공격(Brute-force&amp;nbsp;Attacks),&amp;nbsp;재사용(Reuse)&amp;nbsp;및&amp;nbsp;대규모&amp;nbsp;데이터&amp;nbsp;유출(Data&amp;nbsp;Breaches)**&amp;nbsp;등&amp;nbsp;다양한&amp;nbsp;보안&amp;nbsp;위협에&amp;nbsp;끊임없이&amp;nbsp;노출되어&amp;nbsp;있습니다.&amp;nbsp;사용자들은&amp;nbsp;너무&amp;nbsp;많은&amp;nbsp;비밀번호를&amp;nbsp;기억해야&amp;nbsp;하는&amp;nbsp;부담과&amp;nbsp;함께,&amp;nbsp;복잡한&amp;nbsp;비밀번호를&amp;nbsp;만들어야&amp;nbsp;하는&amp;nbsp;스트레스,&amp;nbsp;그리고&amp;nbsp;주기적인&amp;nbsp;비밀번호&amp;nbsp;변경&amp;nbsp;요구에&amp;nbsp;시달리고&amp;nbsp;있습니다. &lt;br /&gt;&lt;br /&gt;이러한&amp;nbsp;문제들을&amp;nbsp;해결하기&amp;nbsp;위해&amp;nbsp;**FIDO&amp;nbsp;(Fast&amp;nbsp;IDentity&amp;nbsp;Online)&amp;nbsp;Alliance**라는&amp;nbsp;글로벌&amp;nbsp;산업&amp;nbsp;협회가&amp;nbsp;등장했습니다.&amp;nbsp;FIDO의&amp;nbsp;핵심&amp;nbsp;미션은&amp;nbsp;**비밀번호&amp;nbsp;없는(passwordless)**,&amp;nbsp;더&amp;nbsp;**강력하고(stronger)**,&amp;nbsp;더&amp;nbsp;**간단한(simpler)**&amp;nbsp;인증&amp;nbsp;방식을&amp;nbsp;제공하여&amp;nbsp;온라인&amp;nbsp;보안과&amp;nbsp;사용자&amp;nbsp;경험을&amp;nbsp;혁신하는&amp;nbsp;것입니다.&amp;nbsp;FIDO&amp;nbsp;인증은&amp;nbsp;전통적인&amp;nbsp;비밀번호&amp;nbsp;기반의&amp;nbsp;인증&amp;nbsp;모델을&amp;nbsp;공개키&amp;nbsp;암호&amp;nbsp;방식(Public-key&amp;nbsp;Cryptography)&amp;nbsp;기반의&amp;nbsp;혁신적인&amp;nbsp;프로토콜로&amp;nbsp;대체합니다. &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이2 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;3108603048&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;###&amp;nbsp;2.&amp;nbsp;FIDO&amp;nbsp;Alliance와&amp;nbsp;그&amp;nbsp;목표 &lt;br /&gt;&lt;br /&gt;FIDO&amp;nbsp;Alliance는&amp;nbsp;2013년에&amp;nbsp;설립된&amp;nbsp;비영리&amp;nbsp;산업&amp;nbsp;협회로,&amp;nbsp;전&amp;nbsp;세계&amp;nbsp;수백&amp;nbsp;개의&amp;nbsp;기술,&amp;nbsp;금융,&amp;nbsp;보안,&amp;nbsp;통신&amp;nbsp;기업들이&amp;nbsp;참여하고&amp;nbsp;있습니다.&amp;nbsp;이들은&amp;nbsp;공통의&amp;nbsp;오픈&amp;nbsp;표준을&amp;nbsp;개발하고&amp;nbsp;전파하여&amp;nbsp;강력한&amp;nbsp;인증을&amp;nbsp;위한&amp;nbsp;상호&amp;nbsp;운용&amp;nbsp;가능한&amp;nbsp;기술&amp;nbsp;스택을&amp;nbsp;구축하는&amp;nbsp;것을&amp;nbsp;목표로&amp;nbsp;합니다. &lt;br /&gt;&lt;br /&gt;FIDO&amp;nbsp;Alliance의&amp;nbsp;주요&amp;nbsp;목표는&amp;nbsp;다음과&amp;nbsp;같습니다: &lt;br /&gt;*&amp;nbsp;**강력한&amp;nbsp;인증:**&amp;nbsp;피싱,&amp;nbsp;중간자&amp;nbsp;공격(Man-in-the-Middle),&amp;nbsp;재전송&amp;nbsp;공격에&amp;nbsp;매우&amp;nbsp;강한&amp;nbsp;인증&amp;nbsp;방식을&amp;nbsp;제공합니다. &lt;br /&gt;*&amp;nbsp;**간단한&amp;nbsp;사용자&amp;nbsp;경험:**&amp;nbsp;비밀번호&amp;nbsp;없이&amp;nbsp;빠르고&amp;nbsp;직관적인&amp;nbsp;인증&amp;nbsp;절차를&amp;nbsp;제공합니다. &lt;br /&gt;*&amp;nbsp;**프라이버시&amp;nbsp;보호:**&amp;nbsp;사용자&amp;nbsp;생체&amp;nbsp;정보가&amp;nbsp;기기&amp;nbsp;외부로&amp;nbsp;유출되거나&amp;nbsp;서버에&amp;nbsp;저장되지&amp;nbsp;않도록&amp;nbsp;보장합니다. &lt;br /&gt;*&amp;nbsp;**상호&amp;nbsp;운용성:**&amp;nbsp;다양한&amp;nbsp;기기,&amp;nbsp;플랫폼,&amp;nbsp;서비스&amp;nbsp;간에&amp;nbsp;인증&amp;nbsp;기술이&amp;nbsp;호환되도록&amp;nbsp;표준화합니다. &lt;br /&gt;&lt;br /&gt;###&amp;nbsp;3.&amp;nbsp;FIDO&amp;nbsp;인증의&amp;nbsp;핵심&amp;nbsp;원리&amp;nbsp;및&amp;nbsp;철학 &lt;br /&gt;&lt;br /&gt;FIDO&amp;nbsp;인증은&amp;nbsp;기존&amp;nbsp;비밀번호&amp;nbsp;인증과&amp;nbsp;근본적으로&amp;nbsp;다른&amp;nbsp;원리를&amp;nbsp;가집니다. &lt;br /&gt;&lt;br /&gt;*&amp;nbsp;**비밀번호&amp;nbsp;없는&amp;nbsp;인증&amp;nbsp;(Passwordless):**&amp;nbsp;FIDO는&amp;nbsp;사용자가&amp;nbsp;비밀번호를&amp;nbsp;입력하는&amp;nbsp;대신,&amp;nbsp;기기&amp;nbsp;내에서&amp;nbsp;사용자의&amp;nbsp;신원을&amp;nbsp;로컬로&amp;nbsp;확인(예:&amp;nbsp;지문,&amp;nbsp;얼굴&amp;nbsp;인식,&amp;nbsp;PIN&amp;nbsp;입력)하고,&amp;nbsp;이를&amp;nbsp;바탕으로&amp;nbsp;암호화된&amp;nbsp;인증&amp;nbsp;정보를&amp;nbsp;생성하여&amp;nbsp;서버에&amp;nbsp;보냅니다.&amp;nbsp;서버는&amp;nbsp;비밀번호를&amp;nbsp;저장하거나&amp;nbsp;검증할&amp;nbsp;필요가&amp;nbsp;없습니다. &lt;br /&gt;*&amp;nbsp;**공개키&amp;nbsp;암호&amp;nbsp;방식&amp;nbsp;(Public-key&amp;nbsp;Cryptography):**&amp;nbsp;FIDO&amp;nbsp;인증의&amp;nbsp;핵심은&amp;nbsp;공개키&amp;nbsp;암호&amp;nbsp;방식입니다.&amp;nbsp;각&amp;nbsp;사용자&amp;nbsp;계정마다&amp;nbsp;고유한&amp;nbsp;암호화&amp;nbsp;키&amp;nbsp;쌍(개인키/공개키)이&amp;nbsp;생성됩니다.&amp;nbsp;개인키는&amp;nbsp;사용자&amp;nbsp;기기에&amp;nbsp;안전하게&amp;nbsp;보관되고,&amp;nbsp;공개키만&amp;nbsp;서버에&amp;nbsp;등록됩니다. &lt;br /&gt;*&amp;nbsp;**로컬&amp;nbsp;인증&amp;nbsp;(Local&amp;nbsp;Authentication):**&amp;nbsp;사용자는&amp;nbsp;자신의&amp;nbsp;기기(스마트폰,&amp;nbsp;PC)에&amp;nbsp;내장된&amp;nbsp;생체&amp;nbsp;인식&amp;nbsp;센서(지문&amp;nbsp;인식기,&amp;nbsp;얼굴&amp;nbsp;인식&amp;nbsp;카메라)나&amp;nbsp;PIN/패턴&amp;nbsp;입력과&amp;nbsp;같은&amp;nbsp;익숙한&amp;nbsp;방식으로&amp;nbsp;본인임을&amp;nbsp;인증합니다.&amp;nbsp;이&amp;nbsp;인증은&amp;nbsp;기기&amp;nbsp;내부에서만&amp;nbsp;이루어지며,&amp;nbsp;사용자의&amp;nbsp;생체&amp;nbsp;정보는&amp;nbsp;절대&amp;nbsp;기기&amp;nbsp;외부로&amp;nbsp;전송되거나&amp;nbsp;서버에&amp;nbsp;저장되지&amp;nbsp;않습니다. &lt;br /&gt;*&amp;nbsp;**피싱&amp;nbsp;저항성&amp;nbsp;(Phishing&amp;nbsp;Resistance):**&amp;nbsp;FIDO는&amp;nbsp;인증&amp;nbsp;정보를&amp;nbsp;특정&amp;nbsp;웹사이트의&amp;nbsp;도메인(Origin)에&amp;nbsp;묶어둡니다.&amp;nbsp;즉,&amp;nbsp;A&amp;nbsp;사이트용으로&amp;nbsp;생성된&amp;nbsp;인증&amp;nbsp;정보는&amp;nbsp;B&amp;nbsp;사이트에서는&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;없습니다.&amp;nbsp;이로&amp;nbsp;인해&amp;nbsp;사용자가&amp;nbsp;피싱&amp;nbsp;사이트에&amp;nbsp;속아&amp;nbsp;인증&amp;nbsp;정보를&amp;nbsp;입력하더라도,&amp;nbsp;해커는&amp;nbsp;그&amp;nbsp;정보를&amp;nbsp;진짜&amp;nbsp;사이트에서&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;없어&amp;nbsp;피싱&amp;nbsp;공격이&amp;nbsp;원천적으로&amp;nbsp;차단됩니다. &lt;br /&gt;*&amp;nbsp;**개인정보&amp;nbsp;보호:**&amp;nbsp;사용자의&amp;nbsp;생체&amp;nbsp;정보는&amp;nbsp;기기&amp;nbsp;내의&amp;nbsp;보안&amp;nbsp;영역(Secure&amp;nbsp;Enclave,&amp;nbsp;TEE/Trusted&amp;nbsp;Execution&amp;nbsp;Environment)에서만&amp;nbsp;처리되고,&amp;nbsp;기기를&amp;nbsp;떠나지&amp;nbsp;않습니다.&amp;nbsp;서버는&amp;nbsp;생체&amp;nbsp;정보를&amp;nbsp;알&amp;nbsp;수&amp;nbsp;없으며,&amp;nbsp;단지&amp;nbsp;사용자가&amp;nbsp;올바르게&amp;nbsp;인증했음을&amp;nbsp;증명하는&amp;nbsp;암호화된&amp;nbsp;서명만을&amp;nbsp;받게&amp;nbsp;됩니다. &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이1 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;5734766380&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;###&amp;nbsp;4.&amp;nbsp;주요&amp;nbsp;FIDO&amp;nbsp;표준&amp;nbsp;(프로토콜) &lt;br /&gt;&lt;br /&gt;FIDO&amp;nbsp;Alliance는&amp;nbsp;여러&amp;nbsp;가지&amp;nbsp;오픈&amp;nbsp;표준&amp;nbsp;프로토콜을&amp;nbsp;개발했습니다. &lt;br /&gt;&lt;br /&gt;*&amp;nbsp;**FIDO&amp;nbsp;UAF&amp;nbsp;(Universal&amp;nbsp;Authentication&amp;nbsp;Framework):** &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;앱&amp;nbsp;내에서&amp;nbsp;비밀번호&amp;nbsp;없이&amp;nbsp;인증하기&amp;nbsp;위해&amp;nbsp;설계된&amp;nbsp;초기&amp;nbsp;FIDO&amp;nbsp;표준입니다.&amp;nbsp;사용자의&amp;nbsp;생체&amp;nbsp;인식이나&amp;nbsp;PIN&amp;nbsp;등으로&amp;nbsp;인증하고,&amp;nbsp;기기&amp;nbsp;내에서&amp;nbsp;생성된&amp;nbsp;키를&amp;nbsp;사용해&amp;nbsp;서버에&amp;nbsp;인증합니다. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;초기&amp;nbsp;모바일&amp;nbsp;앱&amp;nbsp;중심의&amp;nbsp;무비밀번호&amp;nbsp;인증에&amp;nbsp;주로&amp;nbsp;사용되었습니다. &lt;br /&gt;&lt;br /&gt;*&amp;nbsp;**FIDO&amp;nbsp;U2F&amp;nbsp;(Universal&amp;nbsp;2nd&amp;nbsp;Factor):** &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;두&amp;nbsp;번째&amp;nbsp;인증&amp;nbsp;요소(2FA)로&amp;nbsp;사용하기&amp;nbsp;위해&amp;nbsp;개발되었습니다.&amp;nbsp;주로&amp;nbsp;USB&amp;nbsp;보안&amp;nbsp;키와&amp;nbsp;같은&amp;nbsp;하드웨어&amp;nbsp;토큰을&amp;nbsp;통해&amp;nbsp;간단하고&amp;nbsp;강력한&amp;nbsp;2단계&amp;nbsp;인증을&amp;nbsp;제공합니다.&amp;nbsp;(예:&amp;nbsp;Google&amp;nbsp;계정&amp;nbsp;로그인&amp;nbsp;시&amp;nbsp;YubiKey&amp;nbsp;사용) &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;웹&amp;nbsp;브라우저에서&amp;nbsp;주로&amp;nbsp;사용되었으며,&amp;nbsp;WebAuthn의&amp;nbsp;기반이&amp;nbsp;되었습니다. &lt;br /&gt;&lt;br /&gt;*&amp;nbsp;**FIDO2&amp;nbsp;(WebAuthn&amp;nbsp;+&amp;nbsp;CTAP):** &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;현재&amp;nbsp;가장&amp;nbsp;중요하고&amp;nbsp;널리&amp;nbsp;확산되는&amp;nbsp;FIDO&amp;nbsp;표준입니다.&amp;nbsp;웹&amp;nbsp;브라우저와&amp;nbsp;운영체제에서&amp;nbsp;비밀번호&amp;nbsp;없는&amp;nbsp;강력한&amp;nbsp;인증을&amp;nbsp;지원하도록&amp;nbsp;설계되었습니다. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;**WebAuthn&amp;nbsp;(Web&amp;nbsp;Authentication&amp;nbsp;API):**&amp;nbsp;W3C(World&amp;nbsp;Wide&amp;nbsp;Web&amp;nbsp;Consortium)&amp;nbsp;표준으로,&amp;nbsp;웹&amp;nbsp;브라우저와&amp;nbsp;운영체제가&amp;nbsp;FIDO&amp;nbsp;인증자(Authenticator)와&amp;nbsp;통신하는&amp;nbsp;표준&amp;nbsp;API를&amp;nbsp;정의합니다.&amp;nbsp;웹사이트가&amp;nbsp;사용자&amp;nbsp;기기의&amp;nbsp;생체&amp;nbsp;인식&amp;nbsp;기능이나&amp;nbsp;보안&amp;nbsp;키를&amp;nbsp;통해&amp;nbsp;사용자를&amp;nbsp;인증할&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;해줍니다. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;**CTAP&amp;nbsp;(Client&amp;nbsp;to&amp;nbsp;Authenticator&amp;nbsp;Protocol):**&amp;nbsp;인증자(Authenticator,&amp;nbsp;예:&amp;nbsp;USB&amp;nbsp;보안&amp;nbsp;키,&amp;nbsp;휴대폰)가&amp;nbsp;클라이언트(웹&amp;nbsp;브라우저,&amp;nbsp;OS)와&amp;nbsp;통신하는&amp;nbsp;방법을&amp;nbsp;정의하는&amp;nbsp;프로토콜입니다. &lt;br /&gt;&lt;br /&gt;###&amp;nbsp;5.&amp;nbsp;FIDO&amp;nbsp;(WebAuthn/CTAP)&amp;nbsp;인증의&amp;nbsp;상세&amp;nbsp;작동&amp;nbsp;방식 &lt;br /&gt;&lt;br /&gt;FIDO2&amp;nbsp;기반의&amp;nbsp;인증&amp;nbsp;흐름은&amp;nbsp;크게&amp;nbsp;'등록(Registration)'과&amp;nbsp;'인증(Authentication)'&amp;nbsp;두&amp;nbsp;단계로&amp;nbsp;나뉩니다. &lt;br /&gt;&lt;br /&gt;**5.1.&amp;nbsp;등록&amp;nbsp;(Registration):&amp;nbsp;사용자의&amp;nbsp;키&amp;nbsp;쌍&amp;nbsp;생성&amp;nbsp;및&amp;nbsp;등록** &lt;br /&gt;&lt;br /&gt;1.&amp;nbsp;&amp;nbsp;**사용자&amp;nbsp;의도:**&amp;nbsp;사용자가&amp;nbsp;서비스(웹사이트/앱)에서&amp;nbsp;&quot;FIDO&amp;nbsp;인증&amp;nbsp;등록&quot;을&amp;nbsp;선택합니다. &lt;br /&gt;2.&amp;nbsp;&amp;nbsp;**서비스&amp;nbsp;요청:**&amp;nbsp;서비스(서버)는&amp;nbsp;사용자&amp;nbsp;기기(클라이언트)에&amp;nbsp;FIDO&amp;nbsp;인증자(Authenticator)를&amp;nbsp;등록하라는&amp;nbsp;요청(챌린지&amp;nbsp;포함)을&amp;nbsp;보냅니다. &lt;br /&gt;3.&amp;nbsp;&amp;nbsp;**사용자&amp;nbsp;확인:**&amp;nbsp;기기(운영체제)는&amp;nbsp;사용자에게&amp;nbsp;지문,&amp;nbsp;얼굴,&amp;nbsp;PIN&amp;nbsp;등&amp;nbsp;익숙한&amp;nbsp;방식으로&amp;nbsp;본인임을&amp;nbsp;확인해&amp;nbsp;달라고&amp;nbsp;요청합니다. &lt;br /&gt;4.&amp;nbsp;&amp;nbsp;**키&amp;nbsp;쌍&amp;nbsp;생성:**&amp;nbsp;사용자의&amp;nbsp;확인이&amp;nbsp;성공하면,&amp;nbsp;기기&amp;nbsp;내부의&amp;nbsp;보안&amp;nbsp;영역(예:&amp;nbsp;Secure&amp;nbsp;Enclave)에서&amp;nbsp;해당&amp;nbsp;서비스에만&amp;nbsp;연결된&amp;nbsp;새로운&amp;nbsp;**공개키/개인키&amp;nbsp;쌍**이&amp;nbsp;생성됩니다. &lt;br /&gt;5.&amp;nbsp;&amp;nbsp;**공개키&amp;nbsp;전송:**&amp;nbsp;기기는&amp;nbsp;생성된&amp;nbsp;공개키와&amp;nbsp;함께&amp;nbsp;'Attestation'(선택&amp;nbsp;사항:&amp;nbsp;기기가&amp;nbsp;진짜임을&amp;nbsp;증명하는&amp;nbsp;서명)을&amp;nbsp;서비스(서버)로&amp;nbsp;전송합니다. &lt;br /&gt;6.&amp;nbsp;&amp;nbsp;**서버&amp;nbsp;저장:**&amp;nbsp;서비스(서버)는&amp;nbsp;받은&amp;nbsp;공개키를&amp;nbsp;사용자&amp;nbsp;계정과&amp;nbsp;연결하여&amp;nbsp;안전하게&amp;nbsp;저장합니다.&amp;nbsp;**개인키는&amp;nbsp;절대&amp;nbsp;서버로&amp;nbsp;전송되지&amp;nbsp;않습니다.** &lt;br /&gt;&lt;br /&gt;**5.2.&amp;nbsp;인증&amp;nbsp;(Authentication):&amp;nbsp;사용자의&amp;nbsp;신원&amp;nbsp;확인** &lt;br /&gt;&lt;br /&gt;1.&amp;nbsp;&amp;nbsp;**사용자&amp;nbsp;의도:**&amp;nbsp;사용자가&amp;nbsp;서비스에&amp;nbsp;로그인하려&amp;nbsp;합니다&amp;nbsp;(예:&amp;nbsp;로그인&amp;nbsp;화면에서&amp;nbsp;&quot;FIDO&amp;nbsp;로그인&quot;&amp;nbsp;버튼&amp;nbsp;클릭). &lt;br /&gt;2.&amp;nbsp;&amp;nbsp;**서비스&amp;nbsp;요청:**&amp;nbsp;서비스(서버)는&amp;nbsp;기기(클라이언트)에&amp;nbsp;사용자에게&amp;nbsp;인증을&amp;nbsp;요청하는&amp;nbsp;'챌린지(Challenge)'를&amp;nbsp;보냅니다. &lt;br /&gt;3.&amp;nbsp;&amp;nbsp;**사용자&amp;nbsp;확인:**&amp;nbsp;기기는&amp;nbsp;사용자에게&amp;nbsp;지문,&amp;nbsp;얼굴,&amp;nbsp;PIN&amp;nbsp;등으로&amp;nbsp;본인임을&amp;nbsp;확인해&amp;nbsp;달라고&amp;nbsp;요청합니다. &lt;br /&gt;4.&amp;nbsp;&amp;nbsp;**서명&amp;nbsp;생성:**&amp;nbsp;사용자의&amp;nbsp;확인이&amp;nbsp;성공하면,&amp;nbsp;기기는&amp;nbsp;저장된&amp;nbsp;**개인키를&amp;nbsp;사용하여&amp;nbsp;서버가&amp;nbsp;보낸&amp;nbsp;'챌린지'에&amp;nbsp;암호학적으로&amp;nbsp;서명(Sign)**합니다. &lt;br /&gt;5.&amp;nbsp;&amp;nbsp;**서명&amp;nbsp;전송:**&amp;nbsp;기기는&amp;nbsp;생성된&amp;nbsp;서명된&amp;nbsp;응답을&amp;nbsp;서비스(서버)로&amp;nbsp;전송합니다. &lt;br /&gt;6.&amp;nbsp;&amp;nbsp;**서버&amp;nbsp;검증:**&amp;nbsp;서비스(서버)는&amp;nbsp;자신이&amp;nbsp;저장하고&amp;nbsp;있는&amp;nbsp;사용자의&amp;nbsp;**공개키를&amp;nbsp;사용하여&amp;nbsp;받은&amp;nbsp;서명&amp;nbsp;응답이&amp;nbsp;유효한지&amp;nbsp;검증**합니다. &lt;br /&gt;7.&amp;nbsp;&amp;nbsp;**인증&amp;nbsp;성공:**&amp;nbsp;서명&amp;nbsp;검증이&amp;nbsp;성공하면,&amp;nbsp;서비스는&amp;nbsp;사용자가&amp;nbsp;올바르게&amp;nbsp;인증되었음을&amp;nbsp;확인하고&amp;nbsp;로그인을&amp;nbsp;허용합니다. &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이2 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;3108603048&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;###&amp;nbsp;6.&amp;nbsp;FIDO&amp;nbsp;에코시스템의&amp;nbsp;구성&amp;nbsp;요소 &lt;br /&gt;&lt;br /&gt;*&amp;nbsp;**Relying&amp;nbsp;Party&amp;nbsp;(RP,&amp;nbsp;서비스&amp;nbsp;제공자):**&amp;nbsp;웹사이트,&amp;nbsp;웹&amp;nbsp;애플리케이션,&amp;nbsp;모바일&amp;nbsp;앱&amp;nbsp;등&amp;nbsp;FIDO&amp;nbsp;인증을&amp;nbsp;통해&amp;nbsp;사용자를&amp;nbsp;인증하려는&amp;nbsp;서비스입니다.&amp;nbsp;(예:&amp;nbsp;Google,&amp;nbsp;Apple,&amp;nbsp;금융&amp;nbsp;앱&amp;nbsp;서버) &lt;br /&gt;*&amp;nbsp;**Client&amp;nbsp;(클라이언트):**&amp;nbsp;사용자&amp;nbsp;기기(스마트폰,&amp;nbsp;PC)의&amp;nbsp;운영체제&amp;nbsp;및&amp;nbsp;웹&amp;nbsp;브라우저입니다.&amp;nbsp;FIDO&amp;nbsp;인증자와&amp;nbsp;통신하고&amp;nbsp;사용자&amp;nbsp;인터페이스를&amp;nbsp;제공합니다.&amp;nbsp;(예:&amp;nbsp;Chrome,&amp;nbsp;Safari,&amp;nbsp;Windows,&amp;nbsp;Android,&amp;nbsp;iOS) &lt;br /&gt;*&amp;nbsp;**Authenticator&amp;nbsp;(인증자):**&amp;nbsp;사용자의&amp;nbsp;개인키를&amp;nbsp;안전하게&amp;nbsp;저장하고&amp;nbsp;생체&amp;nbsp;인증/PIN을&amp;nbsp;통해&amp;nbsp;인증&amp;nbsp;서명을&amp;nbsp;생성하는&amp;nbsp;하드웨어&amp;nbsp;또는&amp;nbsp;소프트웨어&amp;nbsp;모듈입니다. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;**플랫폼&amp;nbsp;인증자&amp;nbsp;(Platform&amp;nbsp;Authenticator):**&amp;nbsp;기기에&amp;nbsp;내장된&amp;nbsp;인증자&amp;nbsp;(예:&amp;nbsp;스마트폰의&amp;nbsp;지문&amp;nbsp;센서,&amp;nbsp;Face&amp;nbsp;ID&amp;nbsp;모듈). &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;**로밍&amp;nbsp;인증자&amp;nbsp;(Roaming&amp;nbsp;Authenticator):**&amp;nbsp;기기&amp;nbsp;외부에&amp;nbsp;있는&amp;nbsp;인증자&amp;nbsp;(예:&amp;nbsp;USB&amp;nbsp;YubiKey,&amp;nbsp;Bluetooth&amp;nbsp;보안&amp;nbsp;키). &lt;br /&gt;&lt;br /&gt;###&amp;nbsp;7.&amp;nbsp;FIDO&amp;nbsp;인증의&amp;nbsp;주요&amp;nbsp;이점&amp;nbsp;(종합) &lt;br /&gt;&lt;br /&gt;*&amp;nbsp;**강력한&amp;nbsp;보안:** &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;**피싱&amp;nbsp;저항성:**&amp;nbsp;가장&amp;nbsp;큰&amp;nbsp;장점입니다.&amp;nbsp;인증&amp;nbsp;정보가&amp;nbsp;특정&amp;nbsp;도메인에&amp;nbsp;묶여&amp;nbsp;있어&amp;nbsp;피싱&amp;nbsp;사이트에서&amp;nbsp;탈취될&amp;nbsp;수&amp;nbsp;없습니다. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;**자격&amp;nbsp;증명&amp;nbsp;유출&amp;nbsp;방지:**&amp;nbsp;서버에&amp;nbsp;비밀번호가&amp;nbsp;저장되지&amp;nbsp;않으므로,&amp;nbsp;서버&amp;nbsp;해킹으로&amp;nbsp;인한&amp;nbsp;비밀번호&amp;nbsp;유출&amp;nbsp;위험이&amp;nbsp;없습니다. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;**중간자&amp;nbsp;공격,&amp;nbsp;재전송&amp;nbsp;공격&amp;nbsp;방지:**&amp;nbsp;강력한&amp;nbsp;암호학적&amp;nbsp;프로토콜로&amp;nbsp;이러한&amp;nbsp;공격을&amp;nbsp;차단합니다. &lt;br /&gt;*&amp;nbsp;**탁월한&amp;nbsp;사용자&amp;nbsp;경험:** &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;**비밀번호&amp;nbsp;없는&amp;nbsp;편리함:**&amp;nbsp;비밀번호를&amp;nbsp;기억하거나&amp;nbsp;입력할&amp;nbsp;필요&amp;nbsp;없이&amp;nbsp;생체&amp;nbsp;인식이나&amp;nbsp;PIN으로&amp;nbsp;빠르게&amp;nbsp;로그인합니다. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;**간편하고&amp;nbsp;직관적:**&amp;nbsp;기기&amp;nbsp;잠금&amp;nbsp;해제와&amp;nbsp;동일한&amp;nbsp;방식으로&amp;nbsp;익숙하게&amp;nbsp;인증할&amp;nbsp;수&amp;nbsp;있습니다. &lt;br /&gt;*&amp;nbsp;**강화된&amp;nbsp;프라이버시:** &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;사용자의&amp;nbsp;생체&amp;nbsp;정보는&amp;nbsp;기기를&amp;nbsp;떠나지&amp;nbsp;않고&amp;nbsp;로컬에서만&amp;nbsp;처리됩니다.&amp;nbsp;서버는&amp;nbsp;생체&amp;nbsp;정보에&amp;nbsp;대해&amp;nbsp;알&amp;nbsp;수&amp;nbsp;없습니다. &lt;br /&gt;*&amp;nbsp;**광범위한&amp;nbsp;상호&amp;nbsp;운용성:** &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;오픈&amp;nbsp;표준이므로,&amp;nbsp;다양한&amp;nbsp;제조사의&amp;nbsp;기기,&amp;nbsp;운영체제,&amp;nbsp;브라우저,&amp;nbsp;서비스에서&amp;nbsp;FIDO&amp;nbsp;인증이&amp;nbsp;호환되어&amp;nbsp;작동합니다. &lt;br /&gt;*&amp;nbsp;**운영&amp;nbsp;비용&amp;nbsp;절감:** &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;사용자의&amp;nbsp;비밀번호&amp;nbsp;분실/재설정&amp;nbsp;관련&amp;nbsp;헬프데스크&amp;nbsp;호출&amp;nbsp;감소. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;데이터&amp;nbsp;유출로&amp;nbsp;인한&amp;nbsp;피해&amp;nbsp;및&amp;nbsp;복구&amp;nbsp;비용&amp;nbsp;감소. &lt;br /&gt;&lt;br /&gt;###&amp;nbsp;8.&amp;nbsp;FIDO와&amp;nbsp;패스키(Passkeys)의&amp;nbsp;관계 &lt;br /&gt;&lt;br /&gt;앞서&amp;nbsp;언급했듯이,&amp;nbsp;**패스키(Passkeys)**는&amp;nbsp;FIDO&amp;nbsp;표준,&amp;nbsp;특히&amp;nbsp;WebAuthn의&amp;nbsp;사용자&amp;nbsp;친화적인&amp;nbsp;이름이자&amp;nbsp;구현체입니다.&amp;nbsp;패스키의&amp;nbsp;목표는&amp;nbsp;여러&amp;nbsp;기기&amp;nbsp;간에&amp;nbsp;FIDO&amp;nbsp;인증&amp;nbsp;정보를&amp;nbsp;동기화하여,&amp;nbsp;마치&amp;nbsp;비밀번호처럼&amp;nbsp;편리하게&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있으면서도&amp;nbsp;훨씬&amp;nbsp;강력한&amp;nbsp;보안을&amp;nbsp;제공하는&amp;nbsp;것입니다.&amp;nbsp;사용자는&amp;nbsp;하나의&amp;nbsp;패스키를&amp;nbsp;생성하면&amp;nbsp;iCloud&amp;nbsp;키체인이나&amp;nbsp;Google&amp;nbsp;비밀번호&amp;nbsp;관리자와&amp;nbsp;같은&amp;nbsp;클라우드&amp;nbsp;동기화&amp;nbsp;서비스를&amp;nbsp;통해&amp;nbsp;자신의&amp;nbsp;다른&amp;nbsp;기기에서도&amp;nbsp;해당&amp;nbsp;패스키를&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있습니다. &lt;br /&gt;&lt;br /&gt;###&amp;nbsp;9.&amp;nbsp;도입&amp;nbsp;및&amp;nbsp;확산 &lt;br /&gt;&lt;br /&gt;FIDO&amp;nbsp;인증은&amp;nbsp;이미&amp;nbsp;Google,&amp;nbsp;Apple,&amp;nbsp;Microsoft,&amp;nbsp;Amazon,&amp;nbsp;Meta(Facebook)&amp;nbsp;등&amp;nbsp;전&amp;nbsp;세계&amp;nbsp;주요&amp;nbsp;IT&amp;nbsp;기업에서&amp;nbsp;자사의&amp;nbsp;서비스에&amp;nbsp;활발하게&amp;nbsp;적용하고&amp;nbsp;있습니다.&amp;nbsp;웹&amp;nbsp;브라우저(Chrome,&amp;nbsp;Firefox,&amp;nbsp;Safari,&amp;nbsp;Edge)와&amp;nbsp;모바일&amp;nbsp;운영체제(Android,&amp;nbsp;iOS)에&amp;nbsp;기본&amp;nbsp;기능으로&amp;nbsp;내장되어&amp;nbsp;있으며,&amp;nbsp;금융,&amp;nbsp;통신,&amp;nbsp;공공&amp;nbsp;서비스&amp;nbsp;등&amp;nbsp;다양한&amp;nbsp;산업&amp;nbsp;분야로&amp;nbsp;확산되고&amp;nbsp;있습니다. &lt;br /&gt;&lt;br /&gt;###&amp;nbsp;10.&amp;nbsp;고려사항 &lt;br /&gt;&lt;br /&gt;*&amp;nbsp;**기존&amp;nbsp;시스템&amp;nbsp;통합:**&amp;nbsp;레거시&amp;nbsp;시스템에&amp;nbsp;FIDO&amp;nbsp;인증을&amp;nbsp;통합하는&amp;nbsp;것은&amp;nbsp;추가적인&amp;nbsp;개발&amp;nbsp;및&amp;nbsp;연동&amp;nbsp;작업이&amp;nbsp;필요할&amp;nbsp;수&amp;nbsp;있습니다. &lt;br /&gt;*&amp;nbsp;**사용자&amp;nbsp;교육:**&amp;nbsp;새로운&amp;nbsp;인증&amp;nbsp;방식에&amp;nbsp;대한&amp;nbsp;사용자&amp;nbsp;교육이&amp;nbsp;필요할&amp;nbsp;수&amp;nbsp;있습니다. &lt;br /&gt;*&amp;nbsp;**기기&amp;nbsp;분실/손상&amp;nbsp;시&amp;nbsp;복구:**&amp;nbsp;인증&amp;nbsp;수단인&amp;nbsp;기기를&amp;nbsp;분실하거나&amp;nbsp;손상했을&amp;nbsp;때&amp;nbsp;안전하고&amp;nbsp;편리하게&amp;nbsp;계정을&amp;nbsp;복구하는&amp;nbsp;메커니즘이&amp;nbsp;중요합니다.&lt;/p&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;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-format=&quot;autorelaxed&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;1002348295&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;</description>
      <category>게으른 개발자의 끄적거림</category>
      <category>FIDO</category>
      <category>FIDO 구현</category>
      <category>FIDO 국제인증</category>
      <category>FIDO 리액트 구현</category>
      <category>FIDO 생체인증</category>
      <category>FIDO란?</category>
      <category>fido인증</category>
      <author>끄적잉</author>
      <guid isPermaLink="true">https://play-with.tistory.com/412</guid>
      <comments>https://play-with.tistory.com/412#entry412comment</comments>
      <pubDate>Mon, 28 Jul 2025 17:25:27 +0900</pubDate>
    </item>
    <item>
      <title>IT 프로젝트 포지션 완벽 정리(feat. PM PL AA DA 등)</title>
      <link>https://play-with.tistory.com/411</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;##&amp;nbsp; &amp;nbsp;1.&amp;nbsp;**PM&amp;nbsp;(Project&amp;nbsp;Manager)&amp;nbsp;&amp;ndash;&amp;nbsp;프로젝트&amp;nbsp;관리자**&lt;br /&gt;&lt;br /&gt;###&amp;nbsp;▶️&amp;nbsp;역할:&lt;br /&gt;&lt;br /&gt;*&amp;nbsp;프로젝트&amp;nbsp;전반의&amp;nbsp;**관리&amp;nbsp;책임자**로,&amp;nbsp;일정,&amp;nbsp;예산,&amp;nbsp;자원,&amp;nbsp;품질,&amp;nbsp;범위&amp;nbsp;등을&amp;nbsp;조율&lt;br /&gt;*&amp;nbsp;고객과의&amp;nbsp;커뮤니케이션&amp;nbsp;창구&amp;nbsp;역할&lt;br /&gt;*&amp;nbsp;프로젝트의&amp;nbsp;리스크를&amp;nbsp;식별하고&amp;nbsp;관리&lt;br /&gt;*&amp;nbsp;팀원&amp;nbsp;간의&amp;nbsp;업무&amp;nbsp;조율&amp;nbsp;및&amp;nbsp;일정&amp;nbsp;계획&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;###&amp;nbsp;▶️&amp;nbsp;주요&amp;nbsp;업무:&lt;br /&gt;&lt;br /&gt;*&amp;nbsp;프로젝트&amp;nbsp;계획&amp;nbsp;수립&amp;nbsp;(WBS,&amp;nbsp;일정표,&amp;nbsp;자원계획)&lt;br /&gt;*&amp;nbsp;고객&amp;nbsp;요구사항&amp;nbsp;수집&amp;nbsp;및&amp;nbsp;관리&lt;br /&gt;*&amp;nbsp;프로젝트&amp;nbsp;예산&amp;nbsp;산정&amp;nbsp;및&amp;nbsp;통제&lt;br /&gt;*&amp;nbsp;프로젝트&amp;nbsp;진행&amp;nbsp;현황&amp;nbsp;보고&lt;br /&gt;*&amp;nbsp;QA&amp;nbsp;및&amp;nbsp;테스트&amp;nbsp;결과&amp;nbsp;보고&amp;nbsp;관리&lt;br /&gt;&lt;br /&gt;###&amp;nbsp;▶️&amp;nbsp;요구&amp;nbsp;역량:&lt;br /&gt;&lt;br /&gt;*&amp;nbsp;커뮤니케이션&amp;nbsp;능력,&amp;nbsp;리더십,&amp;nbsp;일정관리&amp;nbsp;능력&lt;br /&gt;*&amp;nbsp;다양한&amp;nbsp;개발&amp;nbsp;방법론&amp;nbsp;(Waterfall,&amp;nbsp;Agile&amp;nbsp;등)에&amp;nbsp;대한&amp;nbsp;이해&lt;br /&gt;*&amp;nbsp;이슈&amp;nbsp;및&amp;nbsp;리스크&amp;nbsp;관리&amp;nbsp;능력&lt;br /&gt;&lt;br /&gt;---&lt;/p&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이1 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;5734766380&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;##&amp;nbsp; &amp;zwj; &amp;nbsp;2.&amp;nbsp;**PL&amp;nbsp;(Project&amp;nbsp;Leader)&amp;nbsp;&amp;ndash;&amp;nbsp;기술&amp;nbsp;리더/팀&amp;nbsp;리더**&lt;br /&gt;&lt;br /&gt;###&amp;nbsp;▶️&amp;nbsp;역할:&lt;br /&gt;&lt;br /&gt;*&amp;nbsp;기술적인&amp;nbsp;관점에서&amp;nbsp;프로젝트를&amp;nbsp;리딩하는&amp;nbsp;사람&lt;br /&gt;*&amp;nbsp;팀원들의&amp;nbsp;작업을&amp;nbsp;분배하고&amp;nbsp;기술&amp;nbsp;방향을&amp;nbsp;제시&lt;br /&gt;*&amp;nbsp;PM의&amp;nbsp;보조&amp;nbsp;역할을&amp;nbsp;하면서&amp;nbsp;개발자&amp;nbsp;간&amp;nbsp;기술&amp;nbsp;중재자&amp;nbsp;역할&amp;nbsp;수행&lt;br /&gt;&lt;br /&gt;###&amp;nbsp;▶️&amp;nbsp;주요&amp;nbsp;업무:&lt;br /&gt;&lt;br /&gt;*&amp;nbsp;개발&amp;nbsp;일정에&amp;nbsp;따른&amp;nbsp;업무&amp;nbsp;분장&amp;nbsp;및&amp;nbsp;진척도&amp;nbsp;관리&lt;br /&gt;*&amp;nbsp;기술&amp;nbsp;이슈&amp;nbsp;해결&amp;nbsp;및&amp;nbsp;기술&amp;nbsp;스택&amp;nbsp;선정&lt;br /&gt;*&amp;nbsp;코드&amp;nbsp;리뷰&amp;nbsp;및&amp;nbsp;품질&amp;nbsp;관리&lt;br /&gt;*&amp;nbsp;개발&amp;nbsp;표준&amp;nbsp;정의&amp;nbsp;및&amp;nbsp;문서화&lt;br /&gt;&lt;br /&gt;###&amp;nbsp;▶️&amp;nbsp;요구&amp;nbsp;역량:&lt;br /&gt;&lt;br /&gt;*&amp;nbsp;풍부한&amp;nbsp;개발&amp;nbsp;경험&lt;br /&gt;*&amp;nbsp;아키텍처&amp;nbsp;설계&amp;nbsp;능력&lt;br /&gt;*&amp;nbsp;팀&amp;nbsp;관리&amp;nbsp;및&amp;nbsp;기술&amp;nbsp;멘토링&amp;nbsp;능력&lt;br /&gt;&lt;br /&gt;---&lt;/p&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이2 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;3108603048&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;##&amp;nbsp; &amp;nbsp;3.&amp;nbsp;**AA&amp;nbsp;(Application&amp;nbsp;Architect)&amp;nbsp;&amp;ndash;&amp;nbsp;응용&amp;nbsp;아키텍트**&lt;br /&gt;&lt;br /&gt;###&amp;nbsp;▶️&amp;nbsp;역할:&lt;br /&gt;&lt;br /&gt;*&amp;nbsp;시스템의&amp;nbsp;전반적인&amp;nbsp;**기능&amp;nbsp;설계와&amp;nbsp;구조&amp;nbsp;설계**를&amp;nbsp;담당&lt;br /&gt;*&amp;nbsp;비즈니스&amp;nbsp;요구사항을&amp;nbsp;토대로&amp;nbsp;시스템의&amp;nbsp;모듈화와&amp;nbsp;구조를&amp;nbsp;정의&lt;br /&gt;&lt;br /&gt;###&amp;nbsp;▶️&amp;nbsp;주요&amp;nbsp;업무:&lt;br /&gt;&lt;br /&gt;*&amp;nbsp;어플리케이션&amp;nbsp;구조&amp;nbsp;설계&amp;nbsp;(MVC,&amp;nbsp;MSA&amp;nbsp;등)&lt;br /&gt;*&amp;nbsp;공통&amp;nbsp;모듈&amp;nbsp;및&amp;nbsp;재사용&amp;nbsp;가능한&amp;nbsp;컴포넌트&amp;nbsp;설계&lt;br /&gt;*&amp;nbsp;성능,&amp;nbsp;보안,&amp;nbsp;유지보수성을&amp;nbsp;고려한&amp;nbsp;설계&lt;br /&gt;*&amp;nbsp;PL&amp;nbsp;및&amp;nbsp;개발자들과&amp;nbsp;협업하여&amp;nbsp;구현&amp;nbsp;지시&lt;br /&gt;&lt;br /&gt;###&amp;nbsp;▶️&amp;nbsp;요구&amp;nbsp;역량:&lt;br /&gt;&lt;br /&gt;*&amp;nbsp;설계&amp;nbsp;패턴,&amp;nbsp;소프트웨어&amp;nbsp;아키텍처에&amp;nbsp;대한&amp;nbsp;깊은&amp;nbsp;이해&lt;br /&gt;*&amp;nbsp;다양한&amp;nbsp;플랫폼/프레임워크&amp;nbsp;경험&lt;br /&gt;*&amp;nbsp;대규모&amp;nbsp;시스템&amp;nbsp;구축&amp;nbsp;경험&lt;br /&gt;&lt;br /&gt;---&lt;br /&gt;&lt;br /&gt;##&amp;nbsp; &amp;nbsp;4.&amp;nbsp;**DA&amp;nbsp;(Data&amp;nbsp;Architect)&amp;nbsp;&amp;ndash;&amp;nbsp;데이터&amp;nbsp;아키텍트**&lt;br /&gt;&lt;br /&gt;###&amp;nbsp;▶️&amp;nbsp;역할:&lt;br /&gt;&lt;br /&gt;*&amp;nbsp;시스템에서&amp;nbsp;사용하는&amp;nbsp;**데이터&amp;nbsp;구조를&amp;nbsp;설계**하는&amp;nbsp;전문가&lt;br /&gt;*&amp;nbsp;데이터베이스의&amp;nbsp;논리적,&amp;nbsp;물리적&amp;nbsp;모델을&amp;nbsp;정의&lt;br /&gt;&lt;br /&gt;###&amp;nbsp;▶️&amp;nbsp;주요&amp;nbsp;업무:&lt;br /&gt;&lt;br /&gt;*&amp;nbsp;ERD&amp;nbsp;작성&amp;nbsp;(Entity&amp;nbsp;Relationship&amp;nbsp;Diagram)&lt;br /&gt;*&amp;nbsp;데이터&amp;nbsp;표준&amp;nbsp;정의&amp;nbsp;및&amp;nbsp;메타데이터&amp;nbsp;관리&lt;br /&gt;*&amp;nbsp;성능을&amp;nbsp;고려한&amp;nbsp;테이블&amp;nbsp;구조&amp;nbsp;및&amp;nbsp;인덱스&amp;nbsp;설계&lt;br /&gt;*&amp;nbsp;데이터&amp;nbsp;보안&amp;nbsp;및&amp;nbsp;무결성&amp;nbsp;확보&lt;br /&gt;&lt;br /&gt;###&amp;nbsp;▶️&amp;nbsp;요구&amp;nbsp;역량:&lt;br /&gt;&lt;br /&gt;*&amp;nbsp;RDBMS,&amp;nbsp;NoSQL&amp;nbsp;등&amp;nbsp;다양한&amp;nbsp;DBMS에&amp;nbsp;대한&amp;nbsp;이해&lt;br /&gt;*&amp;nbsp;데이터&amp;nbsp;모델링&amp;nbsp;툴&amp;nbsp;(ERwin,&amp;nbsp;PowerDesigner&amp;nbsp;등)&amp;nbsp;사용&amp;nbsp;능력&lt;br /&gt;*&amp;nbsp;데이터&amp;nbsp;흐름&amp;nbsp;및&amp;nbsp;ETL&amp;nbsp;설계&amp;nbsp;경험&lt;br /&gt;&lt;br /&gt;---&lt;/p&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이1 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;5734766380&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;##&amp;nbsp;그&amp;nbsp;외에도&amp;nbsp;존재하는&amp;nbsp;관련&amp;nbsp;포지션들&lt;br /&gt;&lt;br /&gt;|&amp;nbsp;포지션&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;|&amp;nbsp;설명&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;|&lt;br /&gt;|&amp;nbsp;----------------------------------------&amp;nbsp;|&amp;nbsp;---------------------------&amp;nbsp;|&lt;br /&gt;|&amp;nbsp;**BA&amp;nbsp;(Business&amp;nbsp;Analyst)**&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;|&amp;nbsp;고객의&amp;nbsp;비즈니스&amp;nbsp;요구사항을&amp;nbsp;정의하고&amp;nbsp;분석하는&amp;nbsp;역할&amp;nbsp;|&lt;br /&gt;|&amp;nbsp;**QA&amp;nbsp;(Quality&amp;nbsp;Assurance)**&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;|&amp;nbsp;테스트&amp;nbsp;전략&amp;nbsp;수립&amp;nbsp;및&amp;nbsp;품질&amp;nbsp;보증&amp;nbsp;업무&amp;nbsp;담당&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;|&lt;br /&gt;|&amp;nbsp;**FE/BE&amp;nbsp;(Frontend&amp;nbsp;/&amp;nbsp;Backend&amp;nbsp;Developer)**&amp;nbsp;|&amp;nbsp;사용자&amp;nbsp;인터페이스&amp;nbsp;/&amp;nbsp;서버&amp;nbsp;사이드&amp;nbsp;로직&amp;nbsp;개발자&amp;nbsp;&amp;nbsp;&amp;nbsp;|&lt;br /&gt;|&amp;nbsp;**UX/UI&amp;nbsp;디자이너**&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;|&amp;nbsp;사용자&amp;nbsp;경험&amp;nbsp;및&amp;nbsp;인터페이스&amp;nbsp;설계&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;|&lt;br /&gt;|&amp;nbsp;**DevOps&amp;nbsp;엔지니어**&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;|&amp;nbsp;개발-운영&amp;nbsp;환경&amp;nbsp;자동화&amp;nbsp;및&amp;nbsp;인프라&amp;nbsp;구축&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;|&lt;br /&gt;|&amp;nbsp;**Tester**&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;|&amp;nbsp;실제&amp;nbsp;테스트&amp;nbsp;시나리오&amp;nbsp;작성&amp;nbsp;및&amp;nbsp;기능&amp;nbsp;확인&amp;nbsp;수행&amp;nbsp;&amp;nbsp;&amp;nbsp;|&lt;br /&gt;&lt;br /&gt;---&lt;br /&gt;&lt;br /&gt;##&amp;nbsp; &amp;nbsp;정리:&amp;nbsp;각&amp;nbsp;포지션의&amp;nbsp;관계도&lt;br /&gt;&lt;br /&gt;```&lt;br /&gt;고객&amp;nbsp;──────&amp;nbsp;BA&amp;nbsp;────────&amp;nbsp;PM&amp;nbsp;──────&amp;nbsp;PL&amp;nbsp;─────&amp;nbsp;개발자들&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;│&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;│&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;AA&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;DA&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;QA&lt;br /&gt;```&lt;br /&gt;&lt;br /&gt;*&amp;nbsp;**BA&amp;nbsp;&amp;rarr;&amp;nbsp;PM/AA**:&amp;nbsp;비즈니스&amp;nbsp;요구를&amp;nbsp;기술요건으로&amp;nbsp;변환&lt;br /&gt;*&amp;nbsp;**PM&amp;nbsp;&amp;harr;&amp;nbsp;PL**:&amp;nbsp;프로젝트&amp;nbsp;일정&amp;middot;품질&amp;nbsp;관리를&amp;nbsp;위한&amp;nbsp;협업&lt;br /&gt;*&amp;nbsp;**AA&amp;nbsp;&amp;harr;&amp;nbsp;DA**:&amp;nbsp;구조와&amp;nbsp;데이터&amp;nbsp;설계를&amp;nbsp;함께&amp;nbsp;조율&lt;br /&gt;*&amp;nbsp;**PL&amp;nbsp;&amp;harr;&amp;nbsp;개발자**:&amp;nbsp;개발&amp;nbsp;방향,&amp;nbsp;코드&amp;nbsp;품질&amp;nbsp;지도&lt;br /&gt;*&amp;nbsp;**QA&amp;nbsp;&amp;harr;&amp;nbsp;전체**:&amp;nbsp;품질&amp;nbsp;확보를&amp;nbsp;위한&amp;nbsp;협업&lt;br /&gt;&lt;br /&gt;---&lt;br /&gt;&lt;br /&gt;##&amp;nbsp;✅&amp;nbsp;마무리&amp;nbsp;요약&lt;br /&gt;&lt;br /&gt;|&amp;nbsp;역할&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;|&amp;nbsp;주요&amp;nbsp;책임&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;|&lt;br /&gt;|&amp;nbsp;------&amp;nbsp;|&amp;nbsp;-----------------------&amp;nbsp;|&lt;br /&gt;|&amp;nbsp;**PM**&amp;nbsp;|&amp;nbsp;프로젝트&amp;nbsp;전반&amp;nbsp;관리&amp;nbsp;(일정,&amp;nbsp;비용,&amp;nbsp;품질)&amp;nbsp;|&lt;br /&gt;|&amp;nbsp;**PL**&amp;nbsp;|&amp;nbsp;기술&amp;nbsp;리딩,&amp;nbsp;개발팀&amp;nbsp;관리&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;|&lt;br /&gt;|&amp;nbsp;**AA**&amp;nbsp;|&amp;nbsp;애플리케이션&amp;nbsp;구조&amp;nbsp;설계&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;|&lt;br /&gt;|&amp;nbsp;**DA**&amp;nbsp;|&amp;nbsp;데이터베이스&amp;nbsp;설계&amp;nbsp;및&amp;nbsp;데이터&amp;nbsp;구조&amp;nbsp;정의&amp;nbsp;&amp;nbsp;&amp;nbsp;|&lt;br /&gt;&lt;br /&gt;각&amp;nbsp;포지션은&amp;nbsp;유기적으로&amp;nbsp;연결되어&amp;nbsp;있으며,&amp;nbsp;**소프트웨어&amp;nbsp;프로젝트의&amp;nbsp;성공을&amp;nbsp;위해&amp;nbsp;상호&amp;nbsp;협력**해야&amp;nbsp;합니다.&amp;nbsp;프로젝트&amp;nbsp;규모가&amp;nbsp;클수록&amp;nbsp;포지션&amp;nbsp;간의&amp;nbsp;역할&amp;nbsp;분담이&amp;nbsp;더&amp;nbsp;명확해지며,&amp;nbsp;작은&amp;nbsp;프로젝트에서는&amp;nbsp;한&amp;nbsp;사람이&amp;nbsp;여러&amp;nbsp;역할을&amp;nbsp;수행하기도&amp;nbsp;합니다.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-format=&quot;autorelaxed&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;1002348295&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;</description>
      <category>게으른 개발자의 끄적거림</category>
      <category>it aa</category>
      <category>it da</category>
      <category>it pl</category>
      <category>IT PM</category>
      <category>it 포지션</category>
      <category>it 프로젝트 포지션</category>
      <category>개발자 직급</category>
      <category>개발자 포지션</category>
      <author>끄적잉</author>
      <guid isPermaLink="true">https://play-with.tistory.com/411</guid>
      <comments>https://play-with.tistory.com/411#entry411comment</comments>
      <pubDate>Fri, 18 Jul 2025 11:26:54 +0900</pubDate>
    </item>
    <item>
      <title>[React] 하단 메뉴바 생성하는 방법</title>
      <link>https://play-with.tistory.com/410</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;&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;630&quot; data-origin-height=&quot;1107&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bE7CH6/btsPj5cWmej/xbHCRhJ86h3Cs3pgUWEJz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bE7CH6/btsPj5cWmej/xbHCRhJ86h3Cs3pgUWEJz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bE7CH6/btsPj5cWmej/xbHCRhJ86h3Cs3pgUWEJz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbE7CH6%2FbtsPj5cWmej%2FxbHCRhJ86h3Cs3pgUWEJz1%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;630&quot; height=&quot;1107&quot; data-origin-width=&quot;630&quot; data-origin-height=&quot;1107&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 해당 부분 인스톨 하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;npm&amp;nbsp;install&amp;nbsp;@react-navigation/bottom-tabs&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이1 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;5734766380&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tabs메뉴&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;import&amp;nbsp;{&amp;nbsp;createBottomTabNavigator&amp;nbsp;}&amp;nbsp;from&amp;nbsp;'@react-navigation/bottom-tabs';&lt;br /&gt;&lt;br /&gt;const&amp;nbsp;MyTabs&amp;nbsp;=&amp;nbsp;createBottomTabNavigator({&lt;br /&gt;&amp;nbsp;&amp;nbsp;screens:&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Home:&amp;nbsp;HomeScreen,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Profile:&amp;nbsp;ProfileScreen,&lt;br /&gt;&amp;nbsp;&amp;nbsp;},&lt;br /&gt;});&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API 설명&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;backbehavior&quot; style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;backBehavior&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이는&amp;nbsp;goBack내비게이터에서 가 호출될 때 발생하는 동작을 제어합니다. 여기에는 기기의 뒤로 가기 버튼이나 Android의 뒤로 가기 제스처가 포함됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다음 값을 지원합니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #e3e3e3; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;firstRoute- 탐색기에서 정의된 첫 번째 화면으로 돌아갑니다(기본값)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;initialRoute- prop에 전달된 초기 화면으로 돌아가고&amp;nbsp;initialRouteName, 전달되지 않으면 첫 번째 화면으로 기본 설정됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;order- 포커스된 화면 이전에 정의된 화면으로 돌아갑니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;history- 탐색기에서 마지막으로 방문한 화면으로 돌아갑니다. 동일한 화면을 여러 번 방문한 경우 이전 항목은 기록에서 삭제됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;fullHistory- 탐색기에서 마지막으로 방문한 화면으로 돌아갑니다.&amp;nbsp;history- 이 동작은 웹 페이지가 작동하는 방식과 일치하도록 하는 데 유용합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;none- 뒤로가기 버튼을 처리하지 마세요&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;detachinactivescreens&quot; style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;detachInactiveScreens&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;메모리 절약을 위해 비활성 화면을 뷰 계층 구조에서 분리할지 여부를 나타내는 부울 값입니다. 이를 통해&amp;nbsp;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/software-mansion/react-native-screens&quot;&gt;react-native-screens&lt;/a&gt;&amp;nbsp;와 통합할 수 있습니다 . 기본값은 .입니다&amp;nbsp;true.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;tabbar&quot; style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;tabBar&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;탭 표시줄에 표시할 React 요소를 반환하는 함수입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 함수는 다음 속성을 포함하는 객체를 인수로 받습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #e3e3e3; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;state- 탭 탐색기의 상태 개체입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;descriptors- 탭 탐색기에 대한 옵션을 포함하는 설명자 개체입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;navigation- 탭 탐색기의 탐색 개체입니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;배열&amp;nbsp;state.routes에는 탐색기에 정의된 모든 경로가 포함됩니다. 각 경로의 옵션은&amp;nbsp;descriptors[route.key].options.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이2 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;3108603048&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;import&amp;nbsp;{&amp;nbsp;View,&amp;nbsp;Platform&amp;nbsp;}&amp;nbsp;from&amp;nbsp;'react-native';&lt;br /&gt;import&amp;nbsp;{&amp;nbsp;useLinkBuilder,&amp;nbsp;useTheme&amp;nbsp;}&amp;nbsp;from&amp;nbsp;'@react-navigation/native';&lt;br /&gt;import&amp;nbsp;{&amp;nbsp;Text,&amp;nbsp;PlatformPressable&amp;nbsp;}&amp;nbsp;from&amp;nbsp;'@react-navigation/elements';&lt;br /&gt;import&amp;nbsp;{&amp;nbsp;createBottomTabNavigator&amp;nbsp;}&amp;nbsp;from&amp;nbsp;'@react-navigation/bottom-tabs';&lt;br /&gt;&lt;br /&gt;function&amp;nbsp;MyTabBar({&amp;nbsp;state,&amp;nbsp;descriptors,&amp;nbsp;navigation&amp;nbsp;})&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;const&amp;nbsp;{&amp;nbsp;colors&amp;nbsp;}&amp;nbsp;=&amp;nbsp;useTheme();&lt;br /&gt;&amp;nbsp;&amp;nbsp;const&amp;nbsp;{&amp;nbsp;buildHref&amp;nbsp;}&amp;nbsp;=&amp;nbsp;useLinkBuilder();&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;return&amp;nbsp;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;View&amp;nbsp;style={{&amp;nbsp;flexDirection:&amp;nbsp;'row'&amp;nbsp;}}&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{state.routes.map((route,&amp;nbsp;index)&amp;nbsp;=&amp;gt;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;{&amp;nbsp;options&amp;nbsp;}&amp;nbsp;=&amp;nbsp;descriptors[route.key];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;label&amp;nbsp;=&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;options.tabBarLabel&amp;nbsp;!==&amp;nbsp;undefined&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;?&amp;nbsp;options.tabBarLabel&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;options.title&amp;nbsp;!==&amp;nbsp;undefined&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;?&amp;nbsp;options.title&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;route.name;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;isFocused&amp;nbsp;=&amp;nbsp;state.index&amp;nbsp;===&amp;nbsp;index;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;onPress&amp;nbsp;=&amp;nbsp;()&amp;nbsp;=&amp;gt;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;event&amp;nbsp;=&amp;nbsp;navigation.emit({&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;type:&amp;nbsp;'tabPress',&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;target:&amp;nbsp;route.key,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;canPreventDefault:&amp;nbsp;true,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;});&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if&amp;nbsp;(!isFocused&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;!event.defaultPrevented)&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;navigation.navigate(route.name,&amp;nbsp;route.params);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;};&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;const&amp;nbsp;onLongPress&amp;nbsp;=&amp;nbsp;()&amp;nbsp;=&amp;gt;&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;navigation.emit({&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;type:&amp;nbsp;'tabLongPress',&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;target:&amp;nbsp;route.key,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;});&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;};&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return&amp;nbsp;(&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;PlatformPressable&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;href={buildHref(route.name,&amp;nbsp;route.params)}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;accessibilityState={isFocused&amp;nbsp;?&amp;nbsp;{&amp;nbsp;selected:&amp;nbsp;true&amp;nbsp;}&amp;nbsp;:&amp;nbsp;{}}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;accessibilityLabel={options.tabBarAccessibilityLabel}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;testID={options.tabBarButtonTestID}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;onPress={onPress}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;onLongPress={onLongPress}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;style={{&amp;nbsp;flex:&amp;nbsp;1&amp;nbsp;}}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;Text&amp;nbsp;style={{&amp;nbsp;color:&amp;nbsp;isFocused&amp;nbsp;?&amp;nbsp;colors.primary&amp;nbsp;:&amp;nbsp;colors.text&amp;nbsp;}}&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{label}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/Text&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/PlatformPressable&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;})}&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/View&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;const&amp;nbsp;MyTabs&amp;nbsp;=&amp;nbsp;createBottomTabNavigator({&lt;br /&gt;&amp;nbsp;&amp;nbsp;tabBar:&amp;nbsp;(props)&amp;nbsp;=&amp;gt;&amp;nbsp;&amp;lt;MyTabBar&amp;nbsp;{...props}&amp;nbsp;/&amp;gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;screens:&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Home:&amp;nbsp;HomeScreen,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Profile:&amp;nbsp;ProfileScreen,&lt;br /&gt;&amp;nbsp;&amp;nbsp;},&lt;br /&gt;});&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이1 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;5734766380&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다음&amp;nbsp;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://reactnavigation.org/docs/screen-options&quot;&gt;옵션을&lt;/a&gt;&amp;nbsp;사용하여 네비게이터 화면을 구성할 수 있습니다. 이러한 옵션은&amp;nbsp;screenOptionsprop of&amp;nbsp;Tab.navigator또는&amp;nbsp;optionsprop of 에서 지정할 수 있습니다&amp;nbsp;Tab.Screen.&lt;/span&gt;&lt;/p&gt;
&lt;h4 style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;title&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;headerTitle및&amp;nbsp;tabBarLabel.&amp;nbsp;의 대체 제목으로 사용할 수 있는 일반적인 제목입니다 .&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;tabbarlabel&quot; style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;tabBarLabel&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;{ focused: boolean, color: string }탭 막대에 표시되는 탭의 제목 문자열 또는 React.Node를 반환하는&amp;nbsp;함수입니다 . 탭 막대에 표시할 탭의 제목 문자열입니다. 정의되지 않은 경우 scene이&amp;nbsp;title사용됩니다. 숨기려면 .을 참조하세요&amp;nbsp;tabBarShowLabel.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;tabbarshowlabel&quot; style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;tabBarShowLabel&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;탭 레이블을 표시할지 여부입니다. 기본값은 .입니다&amp;nbsp;true.&lt;/span&gt;&lt;/p&gt;
&lt;h4 id=&quot;tabbarlabelposition&quot; style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;tabBarLabelPosition&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;라벨이 아이콘 아래에 표시되는지, 아니면 아이콘 옆에 표시되는지.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #e3e3e3; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;기본적으로 위치는 장치 너비에 따라 자동으로 선택됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #e3e3e3; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;below-icon: 라벨은 아이콘 아래에 표시됩니다(iPhone의 경우 일반적임)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;902&quot; data-origin-height=&quot;189&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dWJr90/btsPkIO4ATC/6Ofebozt7S2rkUJbcbTuO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dWJr90/btsPkIO4ATC/6Ofebozt7S2rkUJbcbTuO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dWJr90/btsPkIO4ATC/6Ofebozt7S2rkUJbcbTuO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdWJr90%2FbtsPkIO4ATC%2F6Ofebozt7S2rkUJbcbTuO1%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;902&quot; height=&quot;189&quot; data-origin-width=&quot;902&quot; data-origin-height=&quot;189&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-format=&quot;autorelaxed&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;1002348295&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;</description>
      <category>게으른 개발자의 끄적거림</category>
      <category>react 네비게이션 만들기</category>
      <category>react 네비게이션바</category>
      <category>react 메뉴 생성</category>
      <category>react 메뉴바</category>
      <category>react 하단 네비게이션</category>
      <category>react 하단 네비게이션 만들기</category>
      <category>react 하단 메뉴 만들기</category>
      <category>react 하단 메뉴 생성</category>
      <category>react 하단 메뉴바</category>
      <author>끄적잉</author>
      <guid isPermaLink="true">https://play-with.tistory.com/410</guid>
      <comments>https://play-with.tistory.com/410#entry410comment</comments>
      <pubDate>Tue, 15 Jul 2025 16:10:57 +0900</pubDate>
    </item>
    <item>
      <title>[React] 네비게이션 메뉴 useState? useSelector?</title>
      <link>https://play-with.tistory.com/409</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;네비게이션 메뉴에 서 쓰일 정보들은 useState useSelector 어디서 관리하는게 좋을까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;무조건 &lt;/span&gt;&lt;span&gt;리덕스(Redux)와 같은 전역 상태 관리 라이브러리를 사용하는 것이 훨씬 효율적이고&lt;/span&gt;&lt;span&gt;&amp;nbsp;useState로도 구현은 가능하지만, 앱의 구조가 복잡해지고 유지보수가 매우 어려워집니다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이1 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;5734766380&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #808080;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;## 왜 리덕스가 더 효율적인가?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;모바일 앱에서 하단 메뉴바(네비게이션 바)는 &lt;/span&gt;&lt;span&gt;어떤 페이지에 있든지 항상 화면에 유지&lt;/span&gt;&lt;span&gt;되는 최상위 컴포넌트 중 하나입니다. 사용자가 메뉴를 커스텀하는 화면은 보통 '설정'이나 '메뉴 편집' 같은 특정 페이지에 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 상황을 정리하면 다음과 같습니다.&lt;/span&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;span&gt;메뉴를 변경하는 곳&lt;/span&gt;&lt;span&gt;: '메뉴 편집' 페이지 (하위 컴포넌트)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;변경된 메뉴가 표시되는 곳&lt;/span&gt;&lt;span&gt;: 하단 메뉴바 (최상위 컴포넌트)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이처럼 서로 다른 위치에 있는 컴포넌트들이 &lt;/span&gt;&lt;span&gt;동일한 데이터(사용자가 선택한 메뉴 목록)를 공유&lt;/span&gt;&lt;span&gt;해야 할 때, 전역 상태 관리가 빛을 발합니다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span&gt;구분&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span&gt;리덕스 (useSelector)&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span&gt;useState&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span&gt;데이터 흐름&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span&gt;간단하고 명확&lt;/span&gt;&lt;span&gt;&lt;br /&gt;메뉴 편집 페이지 &amp;rarr; 리덕스 스토어 &amp;rarr; 하단 메뉴바&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span&gt;복잡하고 비효율적 (Props Drilling)&lt;/span&gt;&lt;span&gt;&lt;br /&gt;메뉴 편집 페이지 &amp;rarr; 부모 &amp;rarr; 부모 ... &amp;rarr; 최상위 App &amp;rarr; 하단 메뉴바&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span&gt;구조&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span&gt;어떤 컴포넌트에서든 스토어에 직접 접근 가능&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span&gt;상태를 공유하려면 수많은 부모 컴포넌트를 거쳐 props를 전달해야 함&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span&gt;유지보수&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span&gt;쉬움&lt;/span&gt;&lt;span&gt;. 상태 변경 로직이 한 곳(리듀서)에 모여있어 관리 용이&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span&gt;어려움&lt;/span&gt;&lt;span&gt;. 앱 구조가 조금만 바뀌어도 props 전달 코드를 전부 수정해야 함&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;&lt;span&gt;추천 상황&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span&gt;바로 이 경우처럼 앱 전반에 걸쳐 공유되는 상태를 다룰 때&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;&lt;span&gt;한두 개의 컴포넌트 내에서만 사용하는 간단한 상태를 다룰 때&lt;/span&gt;&lt;/span&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;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이2 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;3108603048&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;## 구현 시나리오 (리덕스 사용)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span&gt;로그인&lt;/span&gt;&lt;span&gt;: 사용자가 로그인하면, 서버로부터 해당 유저가 설정해놓은 메뉴 목록 데이터를 가져옵니다. (['홈', '환경설정'])&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;리덕스 스토어 저장&lt;/span&gt;&lt;span&gt;: 가져온 메뉴 목록을 리덕스 스토어에 저장합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;하단 메뉴바 렌더링&lt;/span&gt;&lt;span&gt;: 하단 메뉴바 컴포넌트는 useSelector를 사용해 리덕스 스토어에 있는 메뉴 목록을 가져와 화면에 그립니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;메뉴 변경&lt;/span&gt;&lt;span&gt;: 사용자가 '메뉴 편집' 페이지에서 메뉴를 추가하거나 삭제합니다. (예: '마이페이지' 추가)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;리덕스 스토어 업데이트&lt;/span&gt;&lt;span&gt;: '메뉴 편집' 페이지는 변경된 새 메뉴 목록(['홈', '환경설정', '마이페이지'])으로 리덕스 스토어의 상태를 업데이트하는 액션을 발생시킵니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;자동 리렌더링&lt;/span&gt;&lt;span&gt;: 리덕스 스토어의 상태가 변경되었으므로, 해당 데이터를 구독하고 있던 하단 메뉴바 컴포넌트는 &lt;/span&gt;&lt;span&gt;자동으로 리렌더링&lt;/span&gt;&lt;span&gt;되어 즉시 변경 사항을 화면에 반영합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이처럼 리덕스를 사용하면 데이터 흐름이 매우 깔끔하고 효율적으로 관리됩니다. 따라서 고민할 필요 없이 &lt;/span&gt;&lt;span&gt;리덕스(또는 Zustand, Recoil 같은 다른 전역 상태 관리 도구)를 선택&lt;/span&gt;&lt;span&gt;하시는 것이 정답입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-format=&quot;autorelaxed&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;1002348295&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;</description>
      <category>게으른 개발자의 끄적거림</category>
      <category>react navigator</category>
      <category>react useselector</category>
      <category>react useState</category>
      <category>react 네비게이션 useselector</category>
      <category>react 네비게이션 usestate</category>
      <category>react 네비게이션 usestate useselector</category>
      <category>react 네비게이션 정보 관리</category>
      <category>react 메뉴바 정보 관리</category>
      <category>리액트 네비게이션</category>
      <author>끄적잉</author>
      <guid isPermaLink="true">https://play-with.tistory.com/409</guid>
      <comments>https://play-with.tistory.com/409#entry409comment</comments>
      <pubDate>Tue, 15 Jul 2025 15:56:06 +0900</pubDate>
    </item>
    <item>
      <title>[리액트] React.js 생명주기 마운트, 언마운트란?</title>
      <link>https://play-with.tistory.com/408</link>
      <description>&lt;h1&gt;React 생명주기(Lifecycle): 마운트(Mount)와 언마운트(Unmount)의 개념과 이해&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이1 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;5734766380&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 생명주기(Lifecycle)란?&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;React에서 **생명주기(lifecycle)**란 컴포넌트가 &lt;b&gt;생성되고&lt;/b&gt;, &lt;b&gt;화면에 렌더링되며&lt;/b&gt;, &lt;b&gt;업데이트되고&lt;/b&gt;, &lt;b&gt;제거될 때까지&lt;/b&gt;의 일련의 과정을 의미합니다. React 컴포넌트는 이 생명주기 동안 특정 시점에 자동으로 호출되는 메서드나 함수들을 통해 &lt;b&gt;상태 관리&lt;/b&gt;, &lt;b&gt;데이터 처리&lt;/b&gt;, &lt;b&gt;부수 효과(side effects)&lt;/b&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;b&gt;Mounting&lt;/b&gt; (마운트): 컴포넌트가 생성되어 DOM에 삽입되는 단계&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Updating&lt;/b&gt; (업데이트): 컴포넌트의 props나 state가 변경되어 재렌더링되는 단계&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Unmounting&lt;/b&gt; (언마운트): 컴포넌트가 DOM에서 제거되는 단계&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 중, 본 설명에서는 **마운트(Mount)**와 **언마운트(Unmount)**에 집중하여 설명하겠습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 마운트(Mount)란?&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.1 정의&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;**마운트(Mount)**는 컴포넌트가 &lt;b&gt;초기 생성되어 DOM에 추가되는 과정&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;props를 전달받음&lt;/li&gt;
&lt;li&gt;state 초기화 (클래스형: constructor, 함수형: useState)&lt;/li&gt;
&lt;li&gt;DOM 트리에 컴포넌트가 삽입됨&lt;/li&gt;
&lt;li&gt;렌더링 수행&lt;/li&gt;
&lt;li&gt;외부 API 호출, 이벤트 등록 등 부수 효과 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.2 클래스형 컴포넌트의 마운트 생명주기 메서드&lt;/h3&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;class MyComponent extends React.Component {
  constructor(props) {
    super(props); // 초기 props 설정
    this.state = { count: 0 }; // 초기 state 설정
    console.log('constructor');
  }

  componentDidMount() {
    console.log('componentDidMount');
    // API 호출, 이벤트 등록 등
  }

  render() {
    console.log('render');
    return &amp;lt;h1&amp;gt;Hello, world!&amp;lt;/h1&amp;gt;;
  }
}
&lt;/code&gt;&lt;/pre&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;constructor(): 컴포넌트 초기화, state 설정&lt;/li&gt;
&lt;li&gt;render(): JSX 반환&lt;/li&gt;
&lt;li&gt;componentDidMount(): 컴포넌트가 DOM에 삽입된 직후 호출됨&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;componentDidMount()는 특히 다음과 같은 작업에 적합합니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API 데이터를 불러와 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;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이2 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;3108603048&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.3 함수형 컴포넌트에서의 마운트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React Hooks를 사용하는 함수형 컴포넌트에서는 useEffect()를 활용하여 마운트 타이밍을 처리합니다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import React, { useEffect, useState } from 'react';

function MyComponent() {
  const [data, setData] = useState(null);

  useEffect(() =&amp;gt; {
    console.log('컴포넌트 마운트됨');

    fetch('/api/data')
      .then(res =&amp;gt; res.json())
      .then(result =&amp;gt; setData(result));
  }, []); // 빈 배열을 전달하면 마운트 시 1회 실행

  return &amp;lt;div&amp;gt;{data ? data.name : 'Loading...'}&amp;lt;/div&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;useEffect(() =&amp;gt; { ... }, []): 마운트 시점에 한 번만 실행됨&lt;/li&gt;
&lt;li&gt;이 안에서 fetch, WebSocket 연결, 구독 등의 작업 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 언마운트(Unmount)란?&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.1 정의&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;**언마운트(Unmount)**는 컴포넌트가 &lt;b&gt;DOM에서 제거되는 시점&lt;/b&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;타이머 제거 (clearInterval, clearTimeout)&lt;/li&gt;
&lt;li&gt;이벤트 리스너 제거 (removeEventListener)&lt;/li&gt;
&lt;li&gt;WebSocket 종료, 구독 해제&lt;/li&gt;
&lt;li&gt;메모리 누수 방지&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이1 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;5734766380&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.2 클래스형 컴포넌트의 언마운트 메서드&lt;/h3&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;class MyComponent extends React.Component {
  componentWillUnmount() {
    console.log('componentWillUnmount');
    // 타이머 제거, 이벤트 제거 등
  }

  render() {
    return &amp;lt;h1&amp;gt;Goodbye!&amp;lt;/h1&amp;gt;;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;componentWillUnmount()는 컴포넌트가 제거되기 직전에 호출됩니다.&lt;/li&gt;
&lt;li&gt;이 메서드는 주로 &lt;b&gt;정리(clean-up)&lt;/b&gt; 작업에 사용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.3 함수형 컴포넌트에서의 언마운트 처리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;useEffect() 내부에서 return 함수로 정리 작업을 할 수 있습니다. 이 return 함수는 컴포넌트가 언마운트될 때 실행됩니다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;import React, { useEffect } from 'react';

function TimerComponent() {
  useEffect(() =&amp;gt; {
    const timer = setInterval(() =&amp;gt; {
      console.log('타이머 실행');
    }, 1000);

    return () =&amp;gt; {
      clearInterval(timer); // 컴포넌트 언마운트 시 타이머 제거
      console.log('컴포넌트 언마운트됨');
    };
  }, []);

  return &amp;lt;div&amp;gt;1초마다 로그 출력 중&amp;lt;/div&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 return 함수를 통해 컴포넌트가 사라지기 직전에 해야 할 정리 작업을 명확히 관리할 수 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 마운트 &amp;amp; 언마운트의 실전 예시&lt;/h2&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function ChatRoom({ roomId }) {
  useEffect(() =&amp;gt; {
    const connect = () =&amp;gt; console.log(`방 ${roomId}에 연결`);
    const disconnect = () =&amp;gt; console.log(`방 ${roomId} 연결 해제`);

    connect();

    return () =&amp;gt; {
      disconnect(); // 언마운트 시 정리
    };
  }, [roomId]);

  return &amp;lt;h1&amp;gt;{roomId}번 채팅방&amp;lt;/h1&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;roomId가 바뀔 때마다 이전 연결을 해제하고 새로 연결&lt;/li&gt;
&lt;li&gt;이 방식은 실시간 통신, 소켓 연결 등에서 매우 중요&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;!-- 디스플레이2 --&gt;&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;3108603048&quot; data-ad-format=&quot;auto&quot; data-full-width-responsive=&quot;true&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 요약 정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구분 마운트(Mount) 언마운트(Unmount)&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;정의&lt;/td&gt;
&lt;td&gt;컴포넌트가 DOM에 삽입되는 과정&lt;/td&gt;
&lt;td&gt;컴포넌트가 DOM에서 제거되는 과정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;클래스형 메서드&lt;/td&gt;
&lt;td&gt;constructor, componentDidMount&lt;/td&gt;
&lt;td&gt;componentWillUnmount&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;함수형 Hook&lt;/td&gt;
&lt;td&gt;useEffect(() =&amp;gt; {...}, [])&lt;/td&gt;
&lt;td&gt;useEffect(() =&amp;gt; {...}; return () =&amp;gt; {...}, [])&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;주요 작업&lt;/td&gt;
&lt;td&gt;API 호출, 초기화, 구독 시작&lt;/td&gt;
&lt;td&gt;타이머 제거, 구독 해제, 메모리 정리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;사용 예&lt;/td&gt;
&lt;td&gt;초기 데이터 로딩, 이벤트 등록&lt;/td&gt;
&lt;td&gt;자원 정리, 소켓 연결 종료&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React의 마운트와 언마운트는 컴포넌트의 &lt;b&gt;시작과 종료를 제어&lt;/b&gt;하는 중요한 개념입니다. 이를 제대로 이해하면 부수 효과를 안전하게 관리할 수 있으며, 메모리 누수나 성능 저하 문제를 사전에 방지할 수 있습니다. 함수형 컴포넌트에서는 useEffect()를 중심으로 이러한 생명주기를 통제하며, 클래스형에서는 각 메서드를 통해 세밀하게 생애주기를 관리할 수 있습니다.&lt;/p&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;div&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-4084235559561568&quot;&gt;&lt;/script&gt;
&lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-format=&quot;autorelaxed&quot; data-ad-client=&quot;ca-pub-4084235559561568&quot; data-ad-slot=&quot;1002348295&quot;&gt;&lt;/ins&gt;
&lt;script&gt;     (adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
&lt;/div&gt;</description>
      <category>mount unmount</category>
      <category>react mount unmount</category>
      <category>리액트 마운트 언마운트</category>
      <category>리액트 생명주기</category>
      <category>리액트 생명주기 마운트</category>
      <category>리액트 생명주기 마운트 언마운트</category>
      <category>리액트 생명주기 언마운트</category>
      <category>마운트 언마운트</category>
      <category>마운트란?</category>
      <category>언마운트란?</category>
      <author>끄적잉</author>
      <guid isPermaLink="true">https://play-with.tistory.com/408</guid>
      <comments>https://play-with.tistory.com/408#entry408comment</comments>
      <pubDate>Sat, 5 Jul 2025 23:27:04 +0900</pubDate>
    </item>
  </channel>
</rss>