<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>FEDowon</title>
        <link>https://velog.io/</link>
        <description>성장에 미쳐버린 Frontend Developer</description>
        <lastBuildDate>Tue, 31 Dec 2024 12:56:35 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>FEDowon</title>
            <url>https://velog.velcdn.com/images/korea-dollar/profile/b45bac56-d29e-4005-912c-0c4846963ada/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. FEDowon. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/korea-dollar" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[2024년 성장과 도전의 회고]]></title>
            <link>https://velog.io/@korea-dollar/2024%EB%85%84-%EA%B0%9C%EB%B0%9C%EC%9E%90-%ED%9A%8C%EA%B3%A0%EB%A1%9D</link>
            <guid>https://velog.io/@korea-dollar/2024%EB%85%84-%EA%B0%9C%EB%B0%9C%EC%9E%90-%ED%9A%8C%EA%B3%A0%EB%A1%9D</guid>
            <pubDate>Tue, 31 Dec 2024 12:56:35 GMT</pubDate>
            <description><![CDATA[<h2 id="2024년-개발자-회고록-성장과-도전의-기록">2024년 개발자 회고록: 성장과 도전의 기록</h2>
<p>한 해를 마무리하며 돌아보니, 2024년은 제 개발자 커리어에서 가장 극적인 변화와 성장이 있었던 해였습니다. 작은 지방 도시에서 시작해 대한민국 IT의 중심지인 판교까지, 이 여정은 단순한 물리적 이동을 넘어 제 개발자로서의 정체성을 완전히 새롭게 정의한 시간이었습니다.</p>
<p>시니어 개발자의 갑작스러운 퇴사는 큰 위기였지만, 이를 통해 주니어 개발자들과 함께 문제를 해결해나가는 과정에서 오히려 더 큰 성장을 이뤘습니다. 동료들과의 적극적인 소통과 협업을 통해 문제해결 능력이 크게 향상되었고, 주도적으로 프로젝트를 이끌어가는 리더십도 배웠습니다.</p>
<h4 id="문제해결-능력의-향상">문제해결 능력의 향상</h4>
<blockquote>
<p><img src="https://velog.velcdn.com/images/korea-dollar/post/891c5227-3ac0-43df-a20a-845751658125/image.png" alt=""></p>
</blockquote>
<p>이 과정에서 자연스럽게 프로젝트 리더십을 경험하게 되었고, 기술적 의사결정과 팀 관리 능력을 동시에 키울 수 있었습니다. 특히 주니어 개발자들과 함께 성장하는 과정에서, 각자의 잠재력을 끌어내고 시너지를 만들어내는 방법을 배웠습니다.</p>
<h3 id="지역-이동을-통한-환경의-변화">지역 이동을 통한 환경의 변화</h3>
<h4 id="사천에서의-시작">사천에서의 시작</h4>
<p>경남 사천시에서의 1년은 개발자로서의 기초를 다지는 소중한 시간이었습니다. 작은 환경이었지만, 오히려 그렇기에 시스템 전반을 깊이 이해할 수 있었고, 다양한 역할을 경험하며 폭넓은 시야를 갖출 수 있었습니다.</p>
<h4 id="판교로의-도약">판교로의 도약</h4>
<blockquote>
<p><img src="https://velog.velcdn.com/images/korea-dollar/post/79b22cc3-d992-4c6f-93d6-fd22daac43fd/image.png" alt=""></p>
</blockquote>
<h3 id="전문성-인정과-성과">전문성 인정과 성과</h3>
<h4 id="다수-기업으로부터의-러브콜">다수 기업으로부터의 러브콜</h4>
<p>2024년의 가장 큰 성과 중 하나는 3개 기업으로부터 동시에 오퍼를 받은 것입니다. 이는 제 기술력과 경험이 시장에서 인정받았다는 증거였으며, 개발자로서의 자신감을 크게 높여준 계기가 되었습니다.</p>
<blockquote>
<ol>
<li>신사업팀에서의 도전</li>
<li>새로운 도메인 설계와 구현 주도</li>
<li>팀 리더십 경험 축적</li>
<li>지식 공유와 성장의 선순환</li>
</ol>
</blockquote>
<h4 id="멘토링-활동의-의미">멘토링 활동의 의미</h4>
<p>무료 멘토링 활동은 제게 특별한 의미가 있었습니다. 주니어 개발자들과 지식을 나누면서, 오히려 제가 더 많이 배우고 성장할 수 있었습니다. 멘토링을 통해 얻은 주요 인사이트는 다음과 같습니다</p>
<blockquote>
<p><img src="https://velog.velcdn.com/images/korea-dollar/post/051d8f61-74f8-4450-bafd-51c617d31604/image.png" alt=""></p>
</blockquote>
<h3 id="기술적-성장의-기록">기술적 성장의 기록</h3>
<h4 id="새롭게-습득한-기술스택">새롭게 습득한 기술스택</h4>
<blockquote>
<ol>
<li>분산 시스템 설계</li>
<li>프로젝트 관리 능력 향상</li>
<li>애자일 방법론 실전 적용</li>
<li>팀 커뮤니케이션 스킬 향상</li>
<li>프로젝트 위험 관리 능력 배양</li>
</ol>
</blockquote>
<h3 id="3d-모델-최적화와-웹-성능-개선">3D 모델 최적화와 웹 성능 개선</h3>
<h4 id="threejs-성능-최적화">Three.js 성능 최적화</h4>
<p>2024년의 주요 성과 중 하나는 3D 모델의 최적화와 웹 성능 개선이었습니다. 200MB의 대용량 3D 모델을 품질 저하 없이 120MB로 압축하는데 성공했으며, 이는 웹 성능에 큰 영향을 미쳤습니다.
<img src="https://velog.velcdn.com/images/korea-dollar/post/ef4c3da3-dba6-47b0-9d33-4b2f9916c168/image.png" alt=""></p>
<h4 id="주요-최적화-전략">주요 최적화 전략</h4>
<blockquote>
<ol>
<li>3D 모델 텍스처 압축 및 최적화</li>
<li>메쉬 폴리곤 수 최적화</li>
<li>불필요한 디테일 제거</li>
<li>텍스처 해상도 조정</li>
<li>메모리 누수 방지 전략</li>
<li>이벤트 리스너 관리 및 컴포넌트 언마운트 시 이벤트 리스너 정리</li>
<li>WeakMap과 WeakSet을 활용한 참조 관리</li>
<li>메모리 모니터링 도구를 통한 주기적인 검사</li>
<li>리소스 최적화</li>
<li>동적 임포트를 통한 코드 스플리팅</li>
<li>캐싱 전략 구현</li>
<li>불필요한 리소스 지연 로딩</li>
<li>웹 성능 안정성 향상
LCP(Largest Contentful Paint) 최적화
FID(First Input Delay) 개선
CLS(Cumulative Layout Shift) 최소화</li>
</ol>
</blockquote>
<p>이러한 최적화 작업을 통해 사용자 경험을 크게 개선했으며, 특히 모바일 환경에서의 성능이 눈에 띄게 향상되었습니다. 이는 제가 2024년에 이룬 중요한 기술적 성과 중 하나입니다.</p>
<h3 id="2025년을-향한-구체적-목표">2025년을 향한 구체적 목표</h3>
<h4 id="기술적-목표">기술적 목표</h4>
<blockquote>
<p>신기술 학습 및 적용 (AI - RAG)
오픈소스 프로젝트 기여
컨퍼런스 발표자 참여 (꿈)
개인 성장 목표
체계적인 멘토링 프로그램 개발
개발자 커뮤니티 리더십 강화</p>
</blockquote>
<h4 id="마무리하며">마무리하며</h4>
<p>2024년은 제게 &#39;도전&#39;과 &#39;성장&#39;의 해였습니다. 지방에서 수도권으로의 이동, 3개 기업의 오퍼, 신사업팀에서의 리더십 경험, 그리고 멘토링 활동을 통한 지식 공유까지, 모든 경험이 제 개발자 커리어의 터닝포인트가 되었습니다.</p>
<p>2025년에는 이러한 경험을 바탕으로, 더 높은 목표를 향해 나아가고자 합니다. 단순한 기술적 성장을 넘어, 개발자 커뮤니티에 더 많은 기여를 하고, 후배 개발자들의 성장을 돕는 진정한 시니어 개발자로 성장하고자 합니다. 이 모든 경험이 제 개발자 인생에서 중요한 이정표가 되리라 확신합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[비전공자 출신 프론트엔드 개발자 이직 경험]]></title>
            <link>https://velog.io/@korea-dollar/%EB%B9%84%EC%A0%84%EA%B3%B5%EC%9E%90-%EC%B6%9C%EC%8B%A0-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EC%9D%B4%EC%A7%81-%EA%B2%BD%ED%97%98</link>
            <guid>https://velog.io/@korea-dollar/%EB%B9%84%EC%A0%84%EA%B3%B5%EC%9E%90-%EC%B6%9C%EC%8B%A0-%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90-%EC%9D%B4%EC%A7%81-%EA%B2%BD%ED%97%98</guid>
            <pubDate>Tue, 10 Sep 2024 14:56:13 GMT</pubDate>
            <description><![CDATA[<h3 id="비전공자의-프론트엔드-개발자-성공기-2년간의-여정">비전공자의 프론트엔드 개발자 성공기: 2년간의 여정</h3>
<p>안녕하세요, 비전공자 출신 프론트엔드 개발자입니다. 오늘은 제가 2년 동안 겪은 도전과 성장, 그리고 이직 성공 스토리를 여러분과 나누고자 합니다.
시작은 미약하였으나...
2년 전, 저는 개발과는 전혀 관련 없는 일을 하고 있었습니다. 하지만 IT 분야에 대한 열정과 호기심으로 새로운 도전을 결심했죠. 스파르타코딩클럽에서 처음 코딩의 재미를 알게 되었고, 이는 제 인생의 전환점이 되었습니다.</p>
<h3 id="끊임없는-노력의-일상">끊임없는 노력의 일상</h3>
<p>처음에는 최저시급을 받으며 시작했지만, 포기하지 않고 계속해서 공부했습니다. 매일 퇴근 후에는 2-3시간씩 개발 공부에 매진했습니다. 주말에도 쉬지 않고 코딩 연습과 프로젝트 작업을 했죠. 이런 노력이 쌓여 점점 실력이 향상되는 것을 느낄 수 있었습니다.</p>
<h3 id="개발자-컨퍼런스-지식의-보고">개발자 컨퍼런스: 지식의 보고</h3>
<p>기회가 될 때마다 개발자 컨퍼런스에 참석했습니다. 처음에는 낯설고 어려웠지만, 점점 더 많은 것을 이해하고 배울 수 있었습니다. 이를 통해 최신 기술 트렌드를 익히고, 제가 가진 잘못된 지식을 바로잡을 수 있었습니다. 특히 다른 개발자들의 경험담을 듣는 것이 큰 도움이 되었습니다.</p>
<h3 id="문제-해결력의-향상">문제 해결력의 향상</h3>
<p>기초를 튼튼히 다지면서 문제 해결력도 기르게 되었습니다. 단순히 개발에만 집중하는 것이 아니라, 넓은 범위에서 문제를 판단하고 해결하는 경험이 가장 좋았습니다. 다양한 프로젝트와 실무 경험을 통해 복잡한 문제를 분석하고 해결하는 방법을 배웠습니다. 이러한 경험은 개발자로서의 자신감을 키워주었고, 새로운 환경에서도 도전에 대한 두려움 없이 임할 수 있게 해주었습니다.</p>
<h3 id="프론트엔드-개발의-매력에-빠지다">프론트엔드 개발의 매력에 빠지다</h3>
<p>프론트엔드 개발은 사용자와 직접 맞닿아 있는 부분을 다루기 때문에 매우 흥미로웠습니다. 사용자 경험을 개선하고, 시각적으로 아름다운 인터페이스를 만드는 과정이 저에게는 큰 즐거움이었습니다. </p>
<h3 id="새로운-기회-그리고-도약">새로운 기회, 그리고 도약</h3>
<p>2년간의 노력 끝에 드디어 좋은 기회가 찾아왔습니다. 실력을 인정받아 연봉 상승과 함께 새로운 회사로 이직하게 되었죠. 특히 시니어 개발자들과 함께 일할 수 있는 환경으로 옮기게 되어 매우 기쁩니다. 이제는 더 큰 규모의 프로젝트에 참여하고, 복잡한 문제를 해결하는 과정에서 많은 것을 배우고 있습니다.</p>
<h3 id="추천-도서로-더-깊이-있는-학습">추천 도서로 더 깊이 있는 학습</h3>
<p>개발 실력 향상을 위해 꾸준히 책을 읽었습니다. 특히 추천하고 싶은 책은 &quot;<strong>우아한 타입스크립트</strong>&quot;와 &quot;<strong>Do it! 모던 자바스크립트</strong>&quot;입니다.</p>
<h4 id="우아한-타입스크립트">&quot;우아한 타입스크립트&quot;</h4>
<blockquote>
<p>이 책은 실무에서 타입스크립트를 어떻게 활용하는지 상세히 다루고 있어, 실제 프로젝트에 바로 적용할 수 있는 지식을 얻을 수 있었습니다.</p>
</blockquote>
<h4 id="do-it-모던-자바스크립트">&quot;Do it! 모던 자바스크립트&quot;</h4>
<blockquote>
<p>자바스크립트의 기초부터 최신 문법까지 체계적으로 배울 수 있어, 기본기를 다지는 데 큰 도움이 되었습니다.</p>
</blockquote>
<h3 id="비전공자를-위한-조언">비전공자를 위한 조언</h3>
<p><strong>포기하지 마세요</strong>: 처음에는 어렵고 힘들 수 있지만, 꾸준히 노력하면 반드시 결과가 따라옵니다.</p>
<p><strong>실무 프로젝트에 참여하세요</strong>: 이론만으로는 부족합니다. 실제 프로젝트를 통해 경험을 쌓는 것이 중요합니다.</p>
<p><strong>커뮤니티에 참여하세요</strong>: 다른 개발자들과 교류하며 새로운 정보와 인사이트를 얻을 수 있습니다.</p>
<p><strong>최신 트렌드</strong>: 기술의 변화가 빠른 만큼, 항상 새로운 것을 배우려는 자세가 필요합니다. 하지만 무지성으로 따라가지마세요. 프로젝트마다 필요한 개발 기술이 있고 왜 필요한지 항상 꼼꼼하게 따지고 최신 기술을 적용하셨으면 좋겠습니다. </p>
<p><strong>기초를 탄탄히 하세요</strong>: 프레임워크나 라이브러리도 중요하지만, 언어의 기본기를 잘 다지는 것이 장기적으로 더 중요합니다.
마치며
지금도 여전히 공부하고 있고, 새로운 것을 배우는 즐거움에 푹 빠져 있습니다. 이 글을 읽는 모든 비전공자 분들께 말씀드리고 싶습니다. </p>
<p>열심히 노력하면 반드시 좋은 기회가 찾아옵니다. 개발의 세계는 넓고 깊지만, 그만큼 보람차고 흥미진진합니다. 여러분의 도전을 응원합니다!</p>
<blockquote>
</blockquote>
<p>#스파르타코딩클럽 #비전공자 #프론트엔드 #개발자이직 #프론트엔드개발 #코딩부트캠프</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[항해 DEV LAB ]]></title>
            <link>https://velog.io/@korea-dollar/%ED%95%AD%ED%95%B4-DEV-LAB</link>
            <guid>https://velog.io/@korea-dollar/%ED%95%AD%ED%95%B4-DEV-LAB</guid>
            <pubDate>Fri, 06 Sep 2024 14:26:11 GMT</pubDate>
            <description><![CDATA[<p>최근에 항해에서 진행한 DEV LAB 행사에 참여했습니다. 
<img src="https://velog.velcdn.com/images/korea-dollar/post/e90eb544-2c0e-434a-a835-71f7805e1058/image.png" alt="">
행사는 스파르타 코딩클럽이 주최하며, 다양한 기술 세션과 커뮤니티 세션으로 구성되어 있었습니다. 총 5개의 기술 세션과 3개의 커뮤니티 세션이 진행되었고, 현직 개발자들과의 네트워킹 기회도 많았습니다.
지금도 좋은 인연이 되어 계속 많은 이야기와 개발자 경험을 하고 있습니다.
<img src="https://velog.velcdn.com/images/korea-dollar/post/85cfe006-a9f4-41f1-9f1d-2fa20882f523/image.png" alt=""></p>
<h4 id="기술-세션">기술 세션</h4>
<p>여러 주제의 발표가 있었으며, 특히 &#39;책임 분리 마법: 깔끔한 폴더 구조 만들기&#39;라는 세션이 인상 깊었습니다. 이 세션에서는 코드 관리의 중요성과 효율적인 폴더 구조에 대한 유용한 팁을 배울 수 있었습니다.</p>
<h4 id="네트워킹">네트워킹</h4>
<p>현직 개발자 200명과의 만남을 통해 다양한 경험과 인사이트를 공유할 수 있어서 좋은 경험이였습니다.</p>
<h3 id="ai와-자동화를-통한-개발자-성장">AI와 자동화를 통한 개발자 성장</h3>
<p>이동욱 CTO님의 세션에서는 개발자의 빠른 이직 주기에 대응하는 인프랩의 전략을 배웠습니다. 
<img src="https://velog.velcdn.com/images/korea-dollar/post/8863214c-528b-4985-b829-851fbf53b2f6/image.png" alt=""></p>
<h4 id="특히-주목할-만한-점">특히 주목할 만한 점</h4>
<p>개발자의 평균 이직 주기가 2~3년으로 짧아졌다는 것
회사 적응 기간을 1년에서 더 단축시키려는 노력
AI와 자동화를 활용해 주니어 개발자의 성장을 가속화하는 방법
이러한 접근 방식은 제가 미처 생각하지 못했던 부분으로, 회사의 인재 육성 전략에 대해 새로운 시각을 갖게 해주었습니다.</p>
<h3 id="테오님의-책임-분리의-마법-깔끔한-폴더-구조-만들기-세션">테오님의 &quot;책임 분리의 마법: 깔끔한 폴더 구조 만들기&quot; 세션</h3>
<p>단순한 기술적 팁을 넘어 코드 구조화의 철학을 전달해 주셨습니다. 
<img src="https://velog.velcdn.com/images/korea-dollar/post/060b6443-4f46-441c-804b-979eb6d41ad9/image.png" alt=""></p>
<h4 id="특히-인상-깊었던-점">특히 인상 깊었던 점</h4>
<p><strong>1. 컴포넌트 레이어의 도입</strong>
기존의 MVC 구조를 넘어, 컴포넌트 레이어를 추가함으로써 코드의 재사용성과 유지보수성을 크게 향상시킬 수 있다는 점을 배웠습니다.
<strong>2. 책임 분리의 중요성</strong>
각 폴더와 파일이 명확한 책임을 가져야 한다는 원칙은, 코드의 가독성과 협업 효율성을 높이는 데 큰 도움이 될 것 같습니다.
<strong>3. 실제 적용 사례</strong>
테오님께서 실제 프로젝트에서 이러한 구조를 적용하여 얻은 이점과 극복한 어려움을 공유해 주셔서, 이론과 실제의 간극을 이해하는 데 도움이 되었습니다.</p>
<p>테오님의 발표는 단순히 기술적인 내용을 전달하는 데 그치지 않고, 개발자로서의 철학과 고민을 함께 나누어 주셔서 깊은 감명을 받았습니다. 이를 통해 코드 구조화에 대한 새로운 관점을 갖게 되었고, 앞으로의 프로젝트에 적용해 볼 수 있는 구체적인 방법론을 얻을 수 있었습니다.</p>
<p>이번 DEV LAB 참여를 통해, 기술적 지식뿐만 아니라 개발 문화와 철학에 대해서도 많은 것을 배울 수 있었습니다. 특히 테오님의 세션은 제 개발 방식에 큰 변화를 줄 것 같습니다. 앞으로도 이러한 기회를 통해 지속적으로 성장하고 싶습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[스마트 팩토리 DX & SAP]]></title>
            <link>https://velog.io/@korea-dollar/%EC%8A%A4%EB%A7%88%ED%8A%B8-%ED%8C%A9%ED%86%A0%EB%A6%AC-DX-SAP</link>
            <guid>https://velog.io/@korea-dollar/%EC%8A%A4%EB%A7%88%ED%8A%B8-%ED%8C%A9%ED%86%A0%EB%A6%AC-DX-SAP</guid>
            <pubDate>Fri, 06 Sep 2024 01:41:23 GMT</pubDate>
            <description><![CDATA[<h2 id="dx--digital-transformation-">DX ( Digital Transformation )</h2>
<p><img src="https://velog.velcdn.com/images/korea-dollar/post/e065fd02-261d-4eb4-ac20-9befaa466577/image.png" alt=""></p>
<h4 id="정의">정의</h4>
<ol>
<li>기업의 모든 영역에 적용하여 근본적으로 비즈니스 성과를 향상시키는 전략으로 탄생</li>
<li>디지털 전환<h4 id="목적">목적</h4>
</li>
<li>생산 효율성 향상</li>
<li>새로운 고객 경험 제공</li>
<li>새로운 비즈니스 모델 발굴<h4 id="기술">기술</h4>
</li>
<li>IoT와 IIoT(산업용 사물인터넷)</li>
<li>5G 통신</li>
<li>클라우드 컴퓨팅</li>
<li>빅데이터 분석</li>
<li>인공지능(AI)<h3 id="스마트팩토리와의-관계">스마트팩토리와의 관계</h3>
제조업에서는 스마트팩토리 구축 과정을 디지털 전환의 일환으로 인식합니다.
스마트팩토리는 제조업에서의 DX 실현 방법 중 하나로 볼 수 있습니다. 
DX가 기업 전체의 디지털 혁신을 의미한다면, 스마트팩토리는 그 중 제조 영역에 특화된 개념이라고 할 수 있습니다.<h2 id="sap--systems-applications-and-products-in-data-processing-">SAP ( Systems, Applications, and Products in Data Processing )</h2>
<img src="https://velog.velcdn.com/images/korea-dollar/post/8b7cec2d-8904-42a9-a355-d8115865763d/image.png" alt=""></li>
</ol>
<h4 id="정의-1">정의</h4>
<p>기업용 소프트웨어를 개발하는 독일 기업의 이름이자 그 회사에서 개발한 전사적 자원관리(ERP) 시스템을 지칭합니다. 다시 말해 기업의 모든 업무 프로세스를 통합적으로 관리하는 소프트웨어 시스템입니다.</p>
<ul>
<li>ERP (Enterprise Resource Planning): 기업의 모든 자원을 통합적으로 관리하는 시스템 개념입니다. 그래서 기업 자원 관리를 위한 일반적인 개념입니다.</li>
<li>SAP: ERP 시스템을 제공하는 독일 기업의 이름이자 그 회사의 ERP 소프트웨어 제품명입니다. 그래서 ERP의 한 종류로, SAP SE 회사에서 개발한 특정 ERP 소프트웨어입니다.</li>
</ul>
<h4 id="특징">특징</h4>
<ol>
<li>실시간 데이터 처리: 모든 정보가 즉시 업데이트되어 공유됩니다.</li>
<li>모듈식 구조: 기업의 필요에 따라 필요한 모듈만 선택적으로 도입할 수 있습니다.</li>
<li>글로벌 표준: 전 세계적으로 사용되는 비즈니스 프로세스 표준을 반영합니다.<blockquote>
<p>FI (Finance): 재무회계
CO (Controlling): 관리회계
MM (Materials Management): 자재관리
SD (Sales and Distribution): 영업 및 유통
PP (Production Planning): 생산계획
HR (Human Resources): 인사관리</p>
</blockquote>
</li>
<li>업무 효율성 향상: 중복 업무 제거, 데이터 일관성 유지</li>
<li>의사결정 지원: 실시간 데이터 분석을 통한 신속한 의사결정</li>
<li>글로벌 비즈니스 지원: 다국어, 다통화 지원<h4 id="도입과정">도입과정</h4>
기업 분석 → 시스템 설계 → 구현 → 테스트 → 사용자 교육 → 실제 운영<h4 id="정리">정리</h4>
SAP는 기업의 디지털 전환(DX)을 위한 핵심 도구로 활용되며, 기업의 전반적인 운영 효율성을 높이고 경쟁력을 강화하는 데 중요한 역할을 합니다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[스마트 팩토리 무선 프로토콜]]></title>
            <link>https://velog.io/@korea-dollar/%EC%8A%A4%EB%A7%88%ED%8A%B8-%ED%8C%A9%ED%86%A0%EB%A6%AC-%EB%AC%B4%EC%84%A0-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C</link>
            <guid>https://velog.io/@korea-dollar/%EC%8A%A4%EB%A7%88%ED%8A%B8-%ED%8C%A9%ED%86%A0%EB%A6%AC-%EB%AC%B4%EC%84%A0-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C</guid>
            <pubDate>Fri, 06 Sep 2024 01:30:28 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/korea-dollar/post/0baf1c83-592e-467c-99ec-166e8225e05d/image.jpg" alt="">
<img src="https://velog.velcdn.com/images/korea-dollar/post/b7fdc11b-071b-4055-b81b-9dada1e9675d/image.png" alt=""></p>
<h2 id="무선-프로토콜">무선 프로토콜</h2>
<h3 id="종류">종류</h3>
<h4 id="1-mqtt--message-queuing-telemetry-transport-">1. MQTT ( Message Queuing Telemetry Transport )</h4>
<ul>
<li>특징<blockquote>
<ul>
<li>경량화된 발행-구독 메시징 프로토콜</li>
<li>IoT 장치 간 통신에 적합, 낮은 대역폭 환경에서도 효율적</li>
<li>TLS 암호화와 OAuth 등의 인증 프로토콜을 지원</li>
</ul>
</blockquote>
</li>
<li>원리
발행자(Publisher)가 특정 주제(Topic)로 메시지를 발행 &gt; 독자(Subscriber)가 관심 있는 주제를 구독 &gt; MQTT 브로커가 발행된 메시지를 해당 주제의 구독자들에게 전달</li>
</ul>
<h4 id="2-opc-ua--open-platform-communications-unified-architecture-">2. OPC UA ( Open Platform Communications Unified Architecture )</h4>
<p><img src="https://velog.velcdn.com/images/korea-dollar/post/a77800eb-14aa-4f0b-9cb6-cf7a7755bba0/image.png" alt=""></p>
<ul>
<li>특징<blockquote>
<ol>
<li>산업 자동화를 위한 머신 간 통신 프로토콜</li>
<li>플랫폼 독립적이며 보안 기능이 강화되어 있습니다.</li>
<li>기존 OPC(OPC Classic)의 후속 버전</li>
<li>데이터 모델링: 복잡한 시스템과 프로세스를 상세히 모델링</li>
<li>보안: 강력한 인증, 암호화, 데이터 무결성 검사를 제공</li>
<li>확장성: 단순한 장치부터 복잡한 시스템까지 다양한 규모의 애플리케이션에 적용 가능 및 SCADA시스템과의 통합을 용이하게 합니다.</li>
<li>서비스 지향 아키텍처: 다양한 서비스를 제공하여 유연한 시스템 구축이 가능</li>
<li>단순한 모델에서 복잡한 모델로 확장 가능한 구조</li>
<li>통합 아키텍처 : DA(Data Access), HDA(Historical Data Access), A&amp;E(Alarms &amp; Events) 등 기존 OPC의 여러 사양을 통합</li>
</ol>
</blockquote>
</li>
</ul>
<ul>
<li>방식 : 클라이언트-서버 모델을 기반, 서버는 데이터 모델과 서비스를 제공, 클라이언트는 서버에 연결하여 데이터를 읽거나 쓰고, 메소드를 호출<h4 id="3-mqtt와-opc-ua의-비교">3. MQTT와 OPC UA의 비교</h4>
</li>
<li>*- 통신 모델</li>
<li>*MQTT: 발행-구독 모델 vs OPC UA: 클라이언트-서버 모델 (발행-구독도 지원)</li>
</ul>
<p>*<em>- 데이터 모델
*</em>MQTT: 단순한 주제 기반 구조 vs OPC UA: 복잡한 객체 지향 데이터 모델</p>
<p>*<em>- 적합도
*</em>MQTT: 주로 경량 IoT 장치와 센서 네트워크 vs OPC UA: 복잡한 산업 자동화 시스템과 프로세스 제어</p>
<p>*<em>- 확장성
*</em>MQTT: 대규모 IoT 네트워크에 적합 vs OPC UA: 복잡한 산업 시스템에 더 적합</p>
<p>*<em>- 보안
*</em>MQTT: 기본적인 보안 기능 제공 vs OPC UA: 더 강력하고 포괄적인 보안 기능 제공</p>
<p>*<em>- 복잡성
*</em>MQTT: 상대적으로 단순하고 구현이 쉬움 vs OPC UA: 더 복잡하지만 기능이 풍부함</p>
<h4 id="4-정리">4. 정리</h4>
<p>OPC UA의 표준화된 통신 프로토콜과 데이터 모델을 통하여 SCADA 시스템의 장점인 다양한 산업 장비와 시스템으로부터 데이터를 쉽게 수집하고 제어할 수 있습니다. 
이는 공장 자동화, 에너지 관리, 빌딩 자동화 등 다양한 분야에서 SCADA 시스템의 효율성과 유연성을 크게 향상시킵니다.</p>
<h3 id="5-opc-ua와-akpache-kafka-함께하는-구조">5. OPC UA와 Akpache Kafka 함께하는 구조</h3>
<h4 id="apache-kafka이란">Apache Kafka이란?</h4>
<ul>
<li><p>여러 서버에 걸쳐 데이터를 분산 저장하고 처리</p>
</li>
<li><p>실시간 대량의 데이터를 실시간으로 수집, 저장, 처리</p>
</li>
<li><p>데이터 생산자(Producer)와 소비자(Consumer) 간의 중개 역할</p>
</li>
<li><p>디스크에 데이터를 저장하여 장기간 보존</p>
</li>
<li><p>하루에 수조 건의 메시지를 처리</p>
</li>
<li><p>다양한 데이터 소스와 목적지 간의 데이터 이동을 지원</p>
</li>
<li><p>데이터 손실 방지와 순서 보장</p>
</li>
<li><p>정리</p>
<blockquote>
<p>Apache Kafka는 대규모 데이터를 실시간으로 처리해야 하는 현대적인 데이터 아키텍처에서 중요한 역할을 하는 강력한 도구입니다.</p>
</blockquote>
</li>
</ul>
<h4 id="apache-kafka의-역할">Apache Kafka의 역할</h4>
<ul>
<li>Kafka는 OPC UA와 함께 사용되어 데이터 처리와 분배를 담당</li>
<li>데이터 수집: OPC UA를 통해 수집된 제조 설비의 데이터를 Kafka로 전송</li>
<li>실시간 스트리밍: 대용량의 센서 데이터와 생산 데이터를 실시간으로 처리</li>
<li>데이터 버퍼링: 네트워크 불안정이나 시스템 장애 시 데이터 손실 방지</li>
<li>데이터 분배: 수집된 데이터를 다양한 분석 시스템, 모니터링 도구, 저장소 등으로 분배</li>
<li>확장성 제공: 데이터 처리량 증가에 따른 수평적 확장 지원<h4 id="통합-아키텍처-절차">통합 아키텍처 절차</h4>
OPC UA 서버가 제조 설비로부터 데이터를 수집
OPC UA 클라이언트가 서버로부터 데이터를 읽어 Kafka 프로듀서로 전송
Kafka가 데이터를 토픽별로 저장하고 관리
다양한 Kafka 컨슈머가 필요한 데이터를 실시간으로 소비하여 처리</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[스마트 팩토리 LLM ]]></title>
            <link>https://velog.io/@korea-dollar/%EC%8A%A4%EB%A7%88%ED%8A%B8-%ED%8C%A9%ED%86%A0%EB%A6%AC-LLM</link>
            <guid>https://velog.io/@korea-dollar/%EC%8A%A4%EB%A7%88%ED%8A%B8-%ED%8C%A9%ED%86%A0%EB%A6%AC-LLM</guid>
            <pubDate>Fri, 06 Sep 2024 01:14:13 GMT</pubDate>
            <description><![CDATA[<h2 id="스마트-팩토리와-llm의-관계">스마트 팩토리와 LLM의 관계</h2>
<p><img src="https://velog.velcdn.com/images/korea-dollar/post/eaa16944-4974-449f-b048-aa941124171c/image.png" alt=""></p>
<h3 id="llm">LLM</h3>
<ul>
<li>Large Language Model : 대규모 언어 모델<h3 id="llm의-스마트팩토리-적용">LLM의 스마트팩토리 적용</h3>
<h4 id="1-데이터-통합-및-해석">1. 데이터 통합 및 해석</h4>
LLM은 다양한 형식의 데이터를 텍스트로 변환하고 해석할 수 있습니다. 센서 데이터, 생산 로그, 품질 보고서 등을 통합하여 의미 있는 인사이트를 추출합니다<h4 id="2-자연어-인터페이스">2. 자연어 인터페이스</h4>
복잡한 공장 시스템을 음성 명령으로 제어할 수 있게 합니다. 예를 들어, &quot;오후 2시 A설비 이상 떨림&quot;이라고 말하면 이상 신호가 기록되고, &quot;최근 발생한 이상 떨림과 조치법 알려줘&quot;라는 질문에 대해 관련 정보를 제공합니다.<h4 id="3-지식-기반-구축">3. 지식 기반 구축</h4>
공장 운영 매뉴얼, 과거 문제 해결 사례, 전문가 지식 등을 LLM에 학습시켜 종합적인 지식 기반을 구축합니다. 이를 통해 복잡한 문제에 대한 해결책을 제시할 수 있습니다.<h4 id="4-예측-분석-및-최적화">4. 예측 분석 및 최적화</h4>
LLM은 과거 데이터 패턴을 학습하여 미래 상황을 예측하고, 최적의 운영 방안을 제안할 수 있습니다. 이는 생산성 향상과 비용 절감으로 이어집니다.<h4 id="5-다중-모달-학습">5. 다중 모달 학습</h4>
최신 LLM은 텍스트뿐만 아니라 이미지, 음성 등 다양한 형태의 입력을 처리할 수 있습니다. 이를 통해 공장 환경의 복잡한 데이터를 종합적으로 분석할 수 있습니다.<h4 id="6-실시간-의사결정-지원">6. 실시간 의사결정 지원</h4>
LLM은 실시간으로 유입되는 데이터를 분석하여 즉각적인 의사결정을 지원합니다. 예를 들어, 생산라인의 병목현상이나 품질 이상을 실시간으로 감지하고 해결책을 제시할 수 있습니다.<h3 id="스마트팩토리와-llm의-관계">스마트팩토리와 LLM의 관계</h3>
</li>
<li>LLM은 방대한 양의 데이터를 분석하고 이해하여 공장 운영과 관련된 복잡한 문제들에 대한 해결책을 제시합니다.</li>
<li>작업 지시, 기계 간 통신, 이상 상태 감지 등을 자동으로 처리 한다. 이로 인해 공장의 자동화 수준을 한층 더 높이고 인간의 개입을 최소화합니다.</li>
<li>공정의 비효율성을 식별하고 개선점을 찾아낸다. 이를 통해 공장 운영에 효율성을 지속적으로 개선할 수 있습니다.</li>
<li>생산 공정을 신속하게 조정하고 다양한 제품에 대응할 수 있는 유연한 생산 시스템을 구축할 수 있다.</li>
<li>생성형 AI는 복잡한 시스템 구축 없이도 자연어 입력만으로 다양한 자동화 작업을 수행할수 있다. 그리고 이것은 RPA(Robotic Process Automation)를 넘어선 초 자동화를 가능하게 한다.</li>
<li>방대한 데이터를 분석하고 패턴을 파악하여 예측 유지보수, 품질관리, 수요예측등에 활용될 수 있다.</li>
</ul>
<blockquote>
<p>RPA(Robotic Process Automation)
소프트웨어 로봇을 사용하여 반복적이고 규칙 기반의 업무 프로세스를 자동화하는 기술
RPA는 미리 정의된 규칙에 따라 작동하는 반면, AI는 데이터 기반으로 학습하고 의사결정</p>
</blockquote>
<h3 id="llm과-ai">LLM과 AI</h3>
<ul>
<li>Large Language Model vs Artifical Intelligence </li>
<li>차이점</li>
</ul>
<ol>
<li><p>LLM은 AI의 한 분야인 자연어 처리에 특화된 모델
AI는 기계가 인간의 지능을 모방하는 광범위한 분야</p>
</li>
<li><p>LLM은 텍스트 이해와 생성에 초점을 맞춘 기능
AI는 주로 학습, 추론, 문제 해결 등 다양한 인지 기능을 포함</p>
</li>
<li><p>LLM은 텍스트에 대한 이해가 높기 때문에 주로 텍스트 기반 작업에 사용
AI는 컴퓨터 비전, 로봇공학, 음성인식 등 다양한 분야에 적용</p>
</li>
<li><p>LLM은 대규모의 텍스트 데이터를 필요
AI는 텍스트 이외 대규모 데이터를 필요</p>
</li>
<li><p>LLM은 주로 트랜스포머 아키텍처 기반
AI는 알고리즘과 아키텍처 기반
<img src="https://velog.velcdn.com/images/korea-dollar/post/452ca715-4d66-4b05-917f-42712d8dc465/image.png" alt=""></p>
<h4 id="transformer-아키텍처">Transformer 아키텍처</h4>
</li>
</ol>
<ul>
<li>정의 : 구글이 자연어 처리를 위해 발표한 딥러닝 모델</li>
<li>장점 : 병렬 처리 능력과 장거리 의존성 포착능력(시퀀스 내의 멀리 떨어진 요소들 사이의 관계를 효과적으로 파악)</li>
<li>구조</li>
<li><em>1. Encoder-Decoder*</em><ul>
<li>입력 문장을 이해하는 인코더</li>
<li>출력 문장을 이해하는 디코더
<img src="https://velog.velcdn.com/images/korea-dollar/post/57530724-5c49-437b-ba37-aea0a70b9aa4/image.png" alt=""></li>
</ul>
</li>
</ul>
<p><strong>2. Multi-Head attention</strong>
<img src="https://velog.velcdn.com/images/korea-dollar/post/6280bdb5-7418-45da-a259-a879be16375d/image.png" alt=""></p>
<ul>
<li>어텐션 연산을 병렬적으로 처리하여 효율성을 높임</li>
<li>어텐션 연산의 개념<ul>
<li>주어진 쿼리(query)에 대해 키(key)와 값(value)의 집합을 사용하여 출력을 계산하는 과정</li>
</ul>
</li>
</ul>
<p><strong>3. Positional attention</strong></p>
<ul>
<li>단어의 위치 정보를 모델에 제공</li>
</ul>
<p><strong>4. Feed-Forward attention</strong>
-각각의 attention층에 다음에 위치하여 추가적인 특징을 추출을 수행</p>
<p><strong>5. 레이어 정규화와 잔차 연결</strong></p>
<ul>
<li>모델의 안정성과 학습 효율성을 높입니다.</li>
<li>잔차 연결은 층의 입력을 그 층의 출력에 직접 더하는 기법입니다.</li>
</ul>
<h3 id="유전-알고리즘">유전 알고리즘</h3>
<p><img src="https://velog.velcdn.com/images/korea-dollar/post/f52c911a-42b2-4f49-a92f-158dc809258d/image.png" alt=""></p>
<ul>
<li>정의 : 자연계의 진화 체계를 모방한 메타휴리스틱 알고리즘</li>
<li>진화 원리 적용: 찰스 다윈의 &quot;적자생존&quot; 이론을 기반</li>
<li>최적화 도구: 복잡한 문제에 대한 최적의 해결책을 찾는 데 사용</li>
<li>순서도</li>
<li><em>초기 집단 생성*</em> (가능한 해결책들의 집단을 생성 ) &gt; <strong>적합도 평가</strong> (각 해결책의 품질을 평가) &gt; <strong>선택</strong> (더 나은 해결책을 선택) &gt; <strong>교차</strong> (선택된 해결책들을 조합하여 새로운 해결책을 만듦) &gt; <strong>돌연변이</strong> (일부 해결책에 무작위 변화를 준다.) &gt; <strong>반복</strong> (여러 세대에 걸쳐 반복)</li>
<li>복잡한 문제에 대한 최적의 해결책을 도출</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[ 스마트팩토리 아키텍처]]></title>
            <link>https://velog.io/@korea-dollar/%EC%8A%A4%EB%A7%88%ED%8A%B8%ED%8C%A9%ED%86%A0%EB%A6%AC-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98</link>
            <guid>https://velog.io/@korea-dollar/%EC%8A%A4%EB%A7%88%ED%8A%B8%ED%8C%A9%ED%86%A0%EB%A6%AC-%EC%95%84%ED%82%A4%ED%85%8D%EC%B2%98</guid>
            <pubDate>Fri, 06 Sep 2024 00:51:11 GMT</pubDate>
            <description><![CDATA[<h2 id="스마트팩토리-아키텍처">스마트팩토리 아키텍처</h2>
<p><img src="https://velog.velcdn.com/images/korea-dollar/post/4b9deb21-a144-47ba-a520-cd515ad5d9c9/image.png" alt=""></p>
<h3 id="핵심-구성-요소">핵심 구성 요소</h3>
<h4 id="1-cps--cyber-physical-system-">1. CPS ( Cyber Physical System )</h4>
<ul>
<li>정의 : 물리적 세계와 가상의 컴퓨팅 세계를 연결하는 시스템</li>
<li>원리 : 센서를 통해 물리적 환경에서 데이터 수집 &gt; 수집된 데이터를 사이버 공간에서 분석 및 처리 &gt; 분석 결과를 바탕으로 물리적 시스템을 제어</li>
<li>장점<blockquote>
<p>실시간 모니터링 및 제어 기능
예측 및 최적화를 통한 효율성 향상
자율적인 의사결정 및 조치 가능</p>
</blockquote>
</li>
</ul>
<h4 id="2빅데이터-및-데이터-관리">2.빅데이터 및 데이터 관리</h4>
<p>대량의 제조 데이터를 효율적으로 저장, 처리, 분석하기 위한 시스템</p>
<ul>
<li>주요 기술<blockquote>
<p>클러스터링: 유사한 데이터를 그룹화
복제: 데이터의 가용성과 견고성 향상
인덱싱: 데이터 검색 효율성 개선</p>
</blockquote>
</li>
</ul>
<h4 id="3-사물인터넷-iot">3. 사물인터넷 (IoT)</h4>
<p>공장 내 설비와 기계에 센서를 부착하여 데이터를 수집하고 네트워크로 연결합니다.</p>
<h4 id="4-클라우드-컴퓨팅">4. 클라우드 컴퓨팅</h4>
<p>수집된 데이터를 저장하고 처리하는 인프라를 제공합니다.</p>
<h4 id="5-인공지능-ai-및-머신러닝">5. 인공지능 (AI) 및 머신러닝</h4>
<p>수집된 데이터를 분석하여 예측 및 최적화를 수행합니다.</p>
<h3 id="구조">구조</h3>
<blockquote>
<ul>
<li>필드 레벨 : 센서, 액추에이터, 기계 등 물리적 장비</li>
</ul>
</blockquote>
<ul>
<li>제어 레벨: PLC, DCS, SCADA 등 제어 시스템</li>
<li>운영 레벨: MES 등 생산 관리 시스템</li>
<li>비즈니스 레벨: ERP, SCM 등 기업 자원 관리 시스템</li>
</ul>
<h4 id="1-plc--programming-logic-controller-">1. PLC ( Programming Logic Controller )</h4>
<ul>
<li><p>정의 : 산업용 제어 시스템</p>
</li>
<li><p>원리 : 입력장치로부터 신호 수신 &gt; 프로그래밍된 로직에 따라 신호처리 &gt; 출력 장치로 제어 신호 전송</p>
</li>
<li><p>장점 : 견고하고 신뢰성이 높은 하드웨어, 실시간 제어 기능</p>
<h4 id="2-dcs--distributed-control-system-">2. DCS ( Distributed Control System )</h4>
</li>
<li><p>정의 : 여러 제어 요소가 분산되어 있는 대규모 공정 제어 시스템</p>
</li>
<li><p>원리 : 각 제어 요소가 독립적으로 작동 &gt; 중앙 운영자 스테이션으로 전체 시스템 모니터링 및 조정 &gt; 네트워크를 통해 제어 요소 간 통신</p>
</li>
<li><p>장점 : 시스템 안정성 향상 (부분 적으로 고장이 전체에 영향을 미치지 않음), 유연한 확장성, 중앙 집중식 모니터링 및 제어 가능</p>
<h4 id="3-scada--supervisory-control-and-data-acquisition-">3. SCADA ( Supervisory Control and Data Acquisition )</h4>
</li>
<li><p>정의 : 산업 프로세스, 장비, 인프라를 원격으로 모니터링하고 제어하는 데 사용되는 컴퓨터 기반 시스템</p>
</li>
<li><p>역할 : 복잡한 산업 프로세스를 효율적으로 관리하고 제어
<img src="https://velog.velcdn.com/images/korea-dollar/post/1e4ed471-c314-481a-92a5-1cfa045260d7/image.png" alt=""></p>
</li>
<li><p>구성 요소</p>
<blockquote>
<p>센서와 액추에이터
원격 단말 장치(RTU) 또는 프로그래머블 로직 컨트롤러(PLC)
SCADA 중앙 컴퓨터 시스템
인간-기계 인터페이스(HMI)
통신 인프라</p>
</blockquote>
</li>
<li><p>기능</p>
<blockquote>
<p>데이터 수집 및 처리
원격 모니터링 및 제어
알람 및 이벤트 처리
데이터 저장 및 보고</p>
</blockquote>
</li>
<li><p>장점</p>
<blockquote>
<p>실시간 모니터링 및 제어
효율성 향상
비용 절감
안전성 개선</p>
</blockquote>
</li>
<li><p>SCADA 시스템은 다양한 산업 분야에서 중요한 역할을 하고 있습니다.</p>
</li>
<li><p>활용 사례</p>
<blockquote>
<ul>
<li>제조업 : 생산 라인 모니터링 및 제어, 품질 관리 데이터 수집 및 분석, 설비 효율성 모니터링 및 최적화</li>
<li>전력 산업 : 발전소 운영 모니터링, 전력 그리드 관리 및 부하 분산, 정전 감지 및 신속한 대응</li>
<li>석유 및 가스 산업 : 파이프라인 모니터링 및 제어, 저장 탱크 레벨 관리, 누출 감지 및 경보 시스템</li>
<li>수처리 시설 : 수질 모니터링, 펌프 및 밸브 제어, 정수 처리 공정 자동화</li>
<li>교통 시스템 : 신호등 제어 및 교통 흐름 최적화, 터널 및 교량 모니터링, 대중교통 운영 관리</li>
</ul>
</blockquote>
</li>
<li><p>정리</p>
</li>
<li><p><em>SCADA 시스템*</em>은 IoT 기술과 결합하여 더욱 효율적이고 유연한 산업 자동화를 가능하게 하고 있습니다. 클라우드 기반 SCADA 시스템의 도입으로 원격 모니터링 및 제어가 더욱 용이해졌으며, 빅데이터 분석과 결합하여 예측 유지보수 및 공정 최적화에 활용되고 있습니다.</p>
<h4 id="4-mes--manufacturing-execution-system-">4. MES ( Manufacturing Execution System )</h4>
</li>
<li><p>정의 : 생산 현장의 실시간 정보를 수집하고 관리하는 시스템</p>
</li>
<li><p>원리 : 생산 현장의 데이터 실시간 수집 &gt; 수집된 데이터 분석 및 가공 &gt; 생산 계획, 품질 관리, 재고 관리 등에 정보 제공</p>
</li>
<li><p>장점 : 생산 프로세스 최적화, 품질관리 향상</p>
<h4 id="5-erp--enterprise-resource-planning-">5. ERP ( Enterprise Resource Planning )</h4>
</li>
<li><p>정의 : 기업의 다양한 운영활동을 중앙 집중화하고 통합하는 시스템, 회계, 인사관리, 생산, 재무관리, 공급망 관리 등 기업의 핵심 프로세스를 하나의 시스템으로 통합</p>
</li>
<li><p>특징</p>
<blockquote>
<p>통합시스템 : 모든 비즈니스 프로세스를 하나의 시스템으로 통합
실시간 운영 : 데이터를 실시간으로 업데이트
공통 데이터베이스 : 모든 애플리케이션이 단일 데이터베이스를 공유
일관된 사용자 인터페이스 : 모든 모듈에서 동일한 인터페이스를 공유</p>
</blockquote>
</li>
<li><p>장점</p>
<blockquote>
<p>업무 효율성 향상
데이터 정확성 개선
의사결정 지원
비용 절감</p>
</blockquote>
</li>
<li><p>정리 : ERP 시스템은 기업의 규모와 산업에 관계없이 사용될 수 있으며, 클라우드 기반 또는 온프레미스 방식으로 구축될 수 있습니다. 현대적인 ERP 시스템은 인공지능(AI), 머신러닝, 사물인터넷(IoT) 등의 첨단 기술을 통합하여 더욱 지능적이고 효율적인 비즈니스 운영을 지원합니다.</p>
<h4 id="6-scm--supply-chain-management">6. SCM ( Supply Chain Management</h4>
</li>
<li><p>정의 : 공급망 전체를 관리하는 시스템</p>
</li>
<li><p>원리 : 공급망 전반의 데이터 수집 및 통합 &gt; 수집된 데이터 기반으로 수요 예측, 재고 관리, 물류 최적화 등 수행 &gt; 공급망 전체의 효율성 향상을 위한 의사결정 지원</p>
</li>
<li><p>장점 : 재고 최적화, 비용 절감, 공급망 가시성 확보</p>
<h4 id="7-etl--extract-transform-load-">7. ETL ( Extract, Transform, Load )</h4>
</li>
<li><p>정의 : 데이터를 처리하고 변환하며 적재하는 과정</p>
</li>
<li><p>단계</p>
<blockquote>
<p>추출(Extract) : 여러 소스에서 데이터를 가져온다.
변환(Transform) : 추출된 데이터를 정계, 통합, 구조화한다.
적재(Load) : 변환된 데이터를 시스템에 저장한다.</p>
</blockquote>
</li>
<li><p>목적</p>
<blockquote>
<p>데이터 통합 : 여러 소스의 데이터를 하나의 일관된 형식으로 통합
데이터 품질 향상 : 데이터를 정제하고 표준화하여 품질을 개선
분석지원 : 데이터 분석을 위한 기법</p>
</blockquote>
</li>
<li><p>장점</p>
<blockquote>
<p>시간 절약 : 데이터 준비 시간을 단축하여 분석에 더 많은 시간을 할애
데이터 품질 개선 : 일관된 프로세스를 통해 데이터의 정확성과 신뢰성을 높임</p>
</blockquote>
<h4 id="8-cnc--computer-numerical-control-">8. CNC ( Computer Numerical Control )</h4>
</li>
<li><p>정의 : 컴퓨터를 사용하여 제조 공정의 기계를 자동으로 제어</p>
</li>
<li><p>역할</p>
<blockquote>
<p>컴퓨터 프로그램을 통해 기계 도구의 움직임을 정밀하게 제어
G-코드와 M-코드라는 특수한 프로그래밍 언어를 사용하여 기계에 지시</p>
</blockquote>
</li>
<li><p>장점</p>
<blockquote>
<p>높은 정밀도와 일관성을 제공합니다.
복잡한 형상의 부품을 효율적으로 생산할 수 있습니다.
생산성을 크게 향상시킵니다.</p>
</blockquote>
<h4 id="9-cpps-cyber-physical-production-systems">9. CPPS (Cyber-Physical Production Systems)</h4>
</li>
<li><p>정의 : 물리적 생산 시스템과 디지털 기술을 통합한 첨단 제조 시스템</p>
</li>
<li><p>특징</p>
<blockquote>
<p>실제 물리적 생산 시스템과 가상의 디지털 모델을 연결합니다.
센서, 액추에이터, 통신 네트워크를 통해 실시간 데이터를 수집하고 처리합니다.
인공지능과 빅데이터 분석을 활용하여 생산 프로세스를 최적화합니다.\</p>
</blockquote>
</li>
<li><p>장점</p>
<blockquote>
<p>생산 과정의 실시간 모니터링과 제어가 가능합니다.
예측 유지보수를 통해 장비 가동 시간을 극대화할 수 있습니다.
생산 유연성과 효율성을 높일 수 있습니다.</p>
</blockquote>
<h4 id="10-cpps랑-cps-차이점">10. CPPS랑 CPS 차이점</h4>
</li>
<li><p>적용범위</p>
<ul>
<li>CPS: 더 광범위한 개념으로, 다양한 분야에 적용될 수 있습니다.</li>
<li>CPPS: 특별히 생산 및 제조 환경에 초점을 맞춘 CPS의 한 형태입니다.</li>
</ul>
</li>
<li><p>목적</p>
<ul>
<li>CPS: 물리적 프로세스와 계산의 통합을 통해 다양한 시스템을 모니터링하고 제어</li>
<li>CPPS: 생산 효율성을 극대화하기 위해 생산 과정 및 정보를 모니터링하고 최적화하는 데 중점</li>
</ul>
</li>
<li><p>구성요소</p>
<ul>
<li>CPS: 센서, 액추에이터, 제어기기 등이 네트워크로 연결된 복합 시스템을 구성
생산에 필요한 프로세스나 카테고리별로 개별 CPS를 구성하고, 이들을 통합하여 생산 시스템을 형성</li>
</ul>
</li>
<li><p>데이터 활용</p>
<ul>
<li>CPS: 물리적 세계의 정보를 수집, 분석하여 피드백 루프를 통해 제어</li>
<li>CPPS: 생산 관련 데이터를 수집하고 분석하여 생산 프로세스를 최적화</li>
</ul>
</li>
<li><p>정리</p>
<blockquote>
<p>CPS가 더 넓은 개념이라면, CPPS는 CPS의 원리를 생산 환경에 특화하여 적용한 것입니다. CPPS는 스마트팩토리 구현의 핵심 요소로, 제조업의 디지털 전환을 이끄는 중요한 기술입니다</p>
</blockquote>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[ 스마트팩토리 기본 개념]]></title>
            <link>https://velog.io/@korea-dollar/%EC%8A%A4%EB%A7%88%ED%8A%B8%ED%8C%A9%ED%86%A0%EB%A6%AC-%EA%B8%B0%EB%B3%B8-%EA%B0%9C%EB%85%90</link>
            <guid>https://velog.io/@korea-dollar/%EC%8A%A4%EB%A7%88%ED%8A%B8%ED%8C%A9%ED%86%A0%EB%A6%AC-%EA%B8%B0%EB%B3%B8-%EA%B0%9C%EB%85%90</guid>
            <pubDate>Fri, 06 Sep 2024 00:17:25 GMT</pubDate>
            <description><![CDATA[<h2 id="스마트팩토리">스마트팩토리</h2>
<p><img src="https://velog.velcdn.com/images/korea-dollar/post/50096b2f-72bb-4121-847c-84ee0c9bd8bb/image.png" alt="">
<img src="https://velog.velcdn.com/images/korea-dollar/post/f37dbf07-9db3-448c-b8b1-0e70ef49f83e/image.png" alt="">
출처 : <a href="https://surpriser.tistory.com/1559?pidx=2">https://surpriser.tistory.com/1559?pidx=2</a></p>
<h3 id="1-정의">1. 정의</h3>
<p>디지털 기술과 자동화를 통해 생산 프로세스를 최적화하는 지능형 공장 시스템을 의미합니다</p>
<h3 id="2-특징">2. 특징</h3>
<ul>
<li><p>상호 연결된 시스템과 기계를 사용하여 실시간 데이터 생성</p>
</li>
<li><p>인공지능과 빅데이터 분석을 통한 생산 프로세스 개선</p>
</li>
<li><p>센서 네트워크를 통한 자동화된 모니터링 및 제어</p>
</li>
<li><p>유연한 생산 시스템으로 다품종 소량생산 가능</p>
<h3 id="3-흐름">3. 흐름</h3>
</li>
<li><p>공장 내부 영역</p>
<blockquote>
<p>생산설비 자동화 및 디지털화
실시간 데이터 수집 및 분석
예측 유지보수 시스템 구축</p>
</blockquote>
</li>
<li><p>공장 외부 영역</p>
<blockquote>
<p>시장조사, 상품기획, 디자인과의 연계
물류 및 서비스와의 통합</p>
</blockquote>
<h3 id="4-데이터-흐름">4. 데이터 흐름</h3>
<blockquote>
<p>데이터 수집 &gt; 데이터 전송 &gt; 데이터 저장 &gt; 데이터 처리 및 분석 &gt; 시각화 및 모니터링 &gt; 제어 및 자동화 &gt; 피드백</p>
</blockquote>
</li>
</ul>
<h4 id="데이터-수집">데이터 수집</h4>
<p>센서, IoT기기, 생산 설비로 부터 실시간 데이터 수집 +  3D데이터 수집</p>
<h4 id="데이터-전송">데이터 전송</h4>
<p>산업용 네트워크를 통한 데이터 전송 (예: Industrial Ethernet, OPC UA)
엣지 컴퓨팅을 통한 데이터 전처리 및 필터링</p>
<h4 id="데이터-저장">데이터 저장</h4>
<p>클라우드 또는 온프레미스 데이터베이스에 저장
빅데이터 플랫폼을 활용한 대용량 데이터 관리</p>
<h4 id="데이터-처리-및-분석">데이터 처리 및 분석</h4>
<p>AI 및 머신러닝 알고리즘을 통한 데이터 분석
예측 분석 및 최적화 모델 적용
3D 모델링 및 시뮬레이션 수행</p>
<h4 id="시각화-및-모니터링">시각화 및 모니터링</h4>
<p>실시간 대시보드를 통한 생산 현황 모니터링
3D 디지털 트윈을 활용한 가상 공장 모델링 및 시각화</p>
<h4 id="제어-및-자동화">제어 및 자동화</h4>
<p>분석 결과를 바탕으로 한 자동 제어 명령 전송
AGV, 로봇 등 자동화 설비의 제어</p>
<h4 id="피드백-루프">피드백 루프</h4>
<p>분석 결과를 바탕으로 생산 프로세스 최적화
지속적인 데이터 수집 및 분석을 통한 개선</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next Auth]]></title>
            <link>https://velog.io/@korea-dollar/Next-Auth</link>
            <guid>https://velog.io/@korea-dollar/Next-Auth</guid>
            <pubDate>Fri, 12 Jul 2024 07:36:26 GMT</pubDate>
            <description><![CDATA[<h3 id="nextjs에서-쿠키-세션을-활용한-간편한-사용자-인증-구현">Next.js에서 쿠키 세션을 활용한 간편한 사용자 인증 구현</h3>
<p><a href="https://github.com/KoreaMoney/NextAuth">구현된 github</a>
<a href="https://next-auth-eta-seven.vercel.app/">TEST Site</a>
ID와 PW는 임시로 구성하였기 때문에 깃헙 Readed.md참고해주시길 바랍니다.</p>
<p>Next.js 애플리케이션에서 사용자 인증 및 세션 관리를 구현한 서버 사이드 코드입니다. 그리고 사용자 인증 및 세션 관리를 구현하는 예시하기 위해서 만들었습니다.</p>
<p>Next.js와 React를 사용하는 개발자들에게 이 코드는 안전하고 효율적인 인증 시스템을 구축하는 데 있어 훌륭한 시작점이 될 것입니다. 복잡한 인증 로직을 간소화하면서도 필요한 모든 핵심 기능을 포함하고 있어, 개발 시간을 단축하고 보안을 강화하는 데 도움이 될 것이라고 생각합니다.</p>
<p>코드에 대해 설명하고 싶지만 직접보는 부분이 더 좋다고 생각하여 자료를 만들면서 제가 iron-session을 사용한 이유와 주요 기능들에 대해 초점을 맞춰 설명드리겠습니다.</p>
<pre><code>export const getSession = async () =&gt; {
  const session = await getIronSession&lt;SessionData&gt;(cookies(), sessionOptions);

  if (!session.isLoggedIn) {
    session.isLoggedIn = defaultSession.isLoggedIn;
  }

  // CHECK THE USER IN THE DB
  session.isBlocked = isBlocked;
  session.isPro = isPro;

  return session;
};</code></pre><blockquote>
<p>session.isBlocked = isBlocked; 이 코드는 세션 객체에 사용자의 차단 상태를 설정하는 역할을 합니다. 이를 통해 애플리케이션은 사용자가 차단되었는지 여부를 세션을 통해 확인할 수 있습니다. 
이 설정은 사용자 인증 및 권한 관리에 중요한 역할을 합니다.</p>
</blockquote>
<p>iron-session을 사용하여 session을 관리하였습니다. 
iron-session을 사용한 이유는 다음과 같습니다. </p>
<h4 id="1-보안성-강화">1. 보안성 강화</h4>
<ul>
<li>JWT와 달리 암호화되어 사용자가 정보를 확인할 수 없습니다.
세션 데이터가 서명되고 암호화된 쿠키에 저장되어 안전합니다.<h4 id="2-서버리스-환경-적합">2. 서버리스 환경 적합</h4>
</li>
<li>세션 데이터를 쿠키에 저장하여 별도의 서버 측 저장소가 필요 없습니다.
세션을 위한 별도의 백엔드 구축이 불필요합니다.<h4 id="3-사용-편의성">3. 사용 편의성</h4>
</li>
<li>미들웨어 하나로 쉽게 세션 기능을 추가할 수 있어 러닝 커브가 낮습니다.</li>
<li>withIronSessionApiRoute와 같은 유용한 헬퍼 함수를 제공합니다.<h4 id="4-무상태stateless-방식">4. 무상태(Stateless) 방식</h4>
</li>
<li>서버 코드에서 네트워크가 필요 없는 상태 비저장 방식으로 디코딩됩니다.</li>
<li>세션 ID가 없어 서버 관점에서 &quot;무상태&quot;로 동작합니다.<h4 id="5-유연성">5. 유연성</h4>
</li>
<li>Next.js, Express 및 Node.js HTTP 서버에서 동작 가능합니다.<h4 id="6-민감한-데이터-저장">6. 민감한 데이터 저장</h4>
</li>
<li>데이터를 암호화하여 저장하므로 민감한 정보도 안전하게 저장할 수 있습니다.<h4 id="7-사용자-패스워드-불필요">7. 사용자 패스워드 불필요</h4>
</li>
<li>사용자 패스워드가 없어도 안전하게 암호화가 가능합니다</li>
</ul>
<pre><code>export const logout = async () =&gt; {
  const session = await getSession();
  session.destroy();
  redirect(&quot;/&quot;);
};

export const changePremium = async () =&gt; {
  const session = await getSession();

  isPro = !session.isPro;
  session.isPro = isPro;
  await session.save();
  revalidatePath(&quot;/profile&quot;); 
};</code></pre><h3 id="주요-기능">주요 기능</h3>
<h4 id="1-세션-관리">1. 세션 관리</h4>
<ul>
<li>getIronSession을 사용하여 안전한 세션 관리</li>
<li>사용자의 로그인 상태, 프리미엄 상태, 차단 상태 등을 세션에 저장<h4 id="2사용자-인증">2.사용자 인증</h4>
</li>
<li>login 함수를 통한 사용자 로그인 처리</li>
<li>사용자명과 비밀번호 검증 (실제 DB 연동은 주석 처리됨)<h4 id="3-로그아웃">3. 로그아웃</h4>
</li>
<li>logout 함수를 통한 세션 파괴 및 로그아웃 처리<h4 id="4-사용자-정보-업데이트">4. 사용자 정보 업데이트</h4>
</li>
<li>changePremium 함수로 사용자의 프리미엄 상태 변경</li>
<li>changeUsername 함수로 사용자명 변경<h4 id="5-iron-session">5. iron-session</h4>
</li>
<li>안전한 쿠키 기반 세션 관리를 위해 iron-session 라이브러리 사용<h4 id="6-revalidatepath">6. revalidatePath</h4>
</li>
<li>revalidatePath를 사용하여 특정 경로의 캐시 무효화</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[NextJS: dynamic import]]></title>
            <link>https://velog.io/@korea-dollar/NextJS-dynamic-import</link>
            <guid>https://velog.io/@korea-dollar/NextJS-dynamic-import</guid>
            <pubDate>Tue, 02 Jul 2024 04:48:30 GMT</pubDate>
            <description><![CDATA[<h3 id="nextjs의-dynamic-import-효율적인-코드-분할-기법">Next.js의 Dynamic Import: 효율적인 코드 분할 기법</h3>
<p>Next.js에서 제공하는 dynamic import는 애플리케이션의 성능을 크게 향상시킬 수 있는 강력한 기능입니다. 이 기술을 통해 대규모 애플리케이션의 코드를 효율적으로 관리하고, 초기 로딩 시간을 단축할 수 있습니다.</p>
<h3 id="코드-분할code-splitting이란">코드 분할(Code Splitting)이란?</h3>
<p>코드 분할은 대규모 애플리케이션의 JavaScript 코드를 더 작은 조각(chunk)으로 나누는 기술입니다. 이를 통해 애플리케이션의 초기 로딩 속도를 개선하고, 필요한 코드만 필요한 시점에 로드할 수 있습니다.</p>
<h3 id="nextjs의-dynamic-import-활용하기">Next.js의 Dynamic Import 활용하기</h3>
<p>Next.js는 next/dynamic을 통해 React 컴포넌트의 동적 로딩을 지원합니다. 이를 통해 컴포넌트나 라이브러리를 필요한 시점에 로드할 수 있어, 초기 JavaScript 번들 크기를 줄일 수 있습니다.</p>
<h4 id="기본사용법">기본사용법</h4>
<pre><code>import dynamic from &#39;next/dynamic&#39;;

const DynamicHeader = dynamic(() =&gt; import(&#39;../components/Header&#39;));

function HomePage() {
  return (
    &lt;div&gt;
      &lt;DynamicHeader /&gt;
      &lt;h1&gt;Welcome to my blog!&lt;/h1&gt;
    &lt;/div&gt;
  );
}</code></pre><p>예시에서 Header 컴포넌트는 페이지가 로드된 후에 동적으로 불러와집니다.</p>
<h3 id="dynamic-import의-주요-옵션">Dynamic Import의 주요 옵션</h3>
<h4 id="1-ssr-서버-사이드-렌더링">1. ssr (서버 사이드 렌더링)</h4>
<pre><code>const DynamicComponent = dynamic(() =&gt; 
import(&#39;../components/Heavy&#39;), { ssr: false });</code></pre><blockquote>
<p>ssr: false로 설정하면 해당 컴포넌트는 클라이언트 사이드에서만 렌더링됩니다.</p>
</blockquote>
<h4 id="2-loading-로딩-컴포넌트">2. loading (로딩 컴포넌트)</h4>
<pre><code>const DynamicComponentWithCustomLoading = dynamic(
  () =&gt; import(&#39;../components/Heavy&#39;),
  { loading: () =&gt; &lt;p&gt;Loading...&lt;/p&gt; }
);</code></pre><blockquote>
<p>컴포넌트가 로드되는 동안 표시될 로딩 컴포넌트를 지정할 수 있습니다.</p>
</blockquote>
<h4 id="3delay-지연-시간">3.delay (지연 시간)</h4>
<pre><code>const DynamicComponentWithDelay = dynamic(() =&gt; 
import(&#39;../components/Heavy&#39;), { delay: 200 });</code></pre><blockquote>
<p>컴포넌트 로딩을 시작하기 전 지정된 시간(밀리초) 동안 대기합니다.</p>
</blockquote>
<h3 id="실제-사용-예시-블로그-댓글-시스템">실제 사용 예시: 블로그 댓글 시스템</h3>
<p>블로그 포스트 페이지에 댓글 시스템을 동적으로 로드하는 예시를 살펴보겠습니다.</p>
<pre><code>import dynamic from &#39;next/dynamic&#39;;

const DynamicComments = dynamic(() =&gt; import(&#39;../components/Comments&#39;), {
  loading: () =&gt; &lt;p&gt;댓글을 불러오는 중...&lt;/p&gt;,
  ssr: false
});

function BlogPost({ content }) {
  return (
    &lt;article&gt;
      &lt;h1&gt;{content.title}&lt;/h1&gt;
      &lt;p&gt;{content.body}&lt;/p&gt;
      &lt;DynamicComments postId={content.id} /&gt;
    &lt;/article&gt;
  );
}</code></pre><blockquote>
<p> 예시에서 댓글 시스템은 필요할 때만 로드되며, 로딩 중에는 사용자에게 로딩 메시지를 표시합니다. 또한 ssr: false를 설정하여 서버 사이드 렌더링을 비활성화하고 클라이언트에서만 댓글을 로드합니다.</p>
</blockquote>
<h3 id="실제-사용-예시2-header-navigation">실제 사용 예시2: Header navigation</h3>
<pre><code>import dynamic from &quot;next/dynamic&quot;;
// import NavIcons from &quot;./NavIcons&quot;;
const NavIcons = dynamic(() =&gt; import(&quot;./NavIcons&quot;), { ssr: false });

const Navbar = () =&gt; {
  return (
    &lt;div className=&quot;h-20 px-4 md:px-8 lg:px-16 xl:px-32 2xl:px-64 relative&quot;&gt;
      &lt;div className=&quot;flex items-center justify-between h-full md:hidden&quot;&gt;
        {/* MOBILE */}
        &lt;Link href=&quot;/&quot;&gt;
          &lt;div className=&quot;text-2xl tracking-wide&quot;&gt;DWSH&lt;/div&gt;
        &lt;/Link&gt;
        &lt;Menu /&gt;
      &lt;/div&gt;
      {/* BIGGER SCREEN */}
      &lt;div className=&quot;hidden md:flex items-center justify-between h-full gap-8&quot;&gt;
        {/* LEFT */}
        &lt;div className=&quot;w-1/3 xl:w-1/2 flex items-center gap-12&quot;&gt;
          &lt;Link href=&quot;/&quot; className=&quot;flex items-center gap-3&quot;&gt;
            &lt;Image src=&quot;/logo3.png&quot; alt=&quot;logo&quot; width={50} height={50} /&gt;
            &lt;div className=&quot;text-2xl tracking-wide font-mono&quot;&gt;DWSH&lt;/div&gt;
          &lt;/Link&gt;
          &lt;div className=&quot;hidden xl:flex gap-4&quot;&gt;
            &lt;Link href=&quot;/&quot;&gt;Home&lt;/Link&gt;
            &lt;Link href=&quot;/&quot;&gt;Shop&lt;/Link&gt;
            &lt;Link href=&quot;/&quot;&gt;Deals&lt;/Link&gt;
            &lt;Link href=&quot;/&quot;&gt;About&lt;/Link&gt;
            &lt;Link href=&quot;/&quot;&gt;Contact&lt;/Link&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        {/* RIGHT */}
        &lt;div className=&quot;w-2/3 xl:w-1/2 flex justify-between items-center gap-8&quot;&gt;
          &lt;SearchBar /&gt;
          &lt;NavIcons /&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
};

export default Navbar;</code></pre><p>Next.js의 dynamic import는 대규모 애플리케이션의 성능을 <strong>최적화</strong>하는 강력한 도구입니다. 필요한 코드만 필요한 시점에 로드함으로써 초기 로딩 시간을 단축하고 사용자 경험을 개선할 수 있습니다. 적절히 활용한다면 더 빠르고 효율적인 웹 애플리케이션을 구축할 수 있을 것입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[클린 코드: 왜 필요한가?]]></title>
            <link>https://velog.io/@korea-dollar/%ED%81%B4%EB%A6%B0%EC%BD%94%EB%93%9C%EA%B0%80-%EC%99%9C-%ED%95%84%EC%9A%94%ED%95%9C%EA%B0%80</link>
            <guid>https://velog.io/@korea-dollar/%ED%81%B4%EB%A6%B0%EC%BD%94%EB%93%9C%EA%B0%80-%EC%99%9C-%ED%95%84%EC%9A%94%ED%95%9C%EA%B0%80</guid>
            <pubDate>Mon, 24 Jun 2024 06:48:21 GMT</pubDate>
            <description><![CDATA[<h3 id="가독성-좋은-코드란-무엇일까요">가독성 좋은 코드란 무엇일까요?</h3>
<p>코드 퀄리티가 낮으면 비즈니스적으로 많은 악영향을 미친다는 것을 알게 되었습니다. 협업하는 다른 개발자들과 함께 개발을 진행할 때, 문제가 없던 코드에 몇 가지 변경만 가했는데도 에러가 빈번하게 발생하는 경우가 있습니다. 이러한 에러들을 분석해보면, 결국 원인이 되는 코드에서 문제가 발생하는 것을 알게 됩니다.</p>
<p>하지만 그 문제점을 분석하는 과정에서 많은 시간이 소비되고, 이에 따른 대응이 필요합니다. 
최근 저는 회사의 디지털 트윈 플랫폼을 개발하면서 예상치 못한 부분에서 전혀 관련 없는 코드 한 줄이 문제가 되는 상황을 경험했습니다. 
문제점을 찾고 해결하는 과정에서 여러 단계가 겹치는 코드를 보면서, 가독성이 단순히 코드를 보기 좋게 만드는 것이 아니라 코드의 효율성을 높인다는 것을 깨달았습니다.</p>
<p>이전에는 단순히 보기 쉽고 클린 코드만 생각했지만, 이제는 협업 과정에서 효율적이고 쉽게 문제를 파악할 수 있는 가독성 좋은 코드를 작성해야겠다고 생각하고 실천하고 있습니다. 
현재 프로젝트뿐만 아니라, 다른 프로젝트에서도 재사용 가능한 컴포넌트를 구성하면 유연하게 적용할 수 있어 좋은 경험을 하게 되었습니다.</p>
<p>저희 팀은 시니어 개발자가 없는 상황에서 ChatGPT-4를 사용하여 코드 리뷰도 받아보고, 팀원들 간의 코드 리뷰를 통해 더 나은 코드와 효율적이고 재사용성이 뛰어난 코드를 작성하고자 노력하고 있습니다.</p>
<p><strong>클린 코드</strong>는 단순히 짧게 작성하고 컴포넌트를 분리하는 것에 그치지 않습니다. 클린 코드의 진정한 목적은 코드 로직을 신속하게 파악하고, 팀원들이 쉽게 이해할 수 있으며, 에러 발생 시 빠르게 대응하여 비즈니스 가치를 극대화하는 데 있습니다.</p>
<p>클린 코드를 작성하는 중요성을 이해하기 위해, 예시 이미지와 함께 살펴보겠습니다.</p>
<p><img src="https://velog.velcdn.com/images/korea-dollar/post/3c8904bb-a344-4a08-a676-e58dfd651d8b/image.png" alt=""></p>
<p>처음에는 단순하게 input만 존재하던 component에서, input의 입력값에 따라 추가된 코드들이 들어가면서 관련이 없는 코드들이 하나의 component에 묶이게 되었습니다. 
그 결과 하나의 함수에 여러 기능이 포함되는 복잡성이 생겼습니다. </p>
<blockquote>
<p>handleCheckMember 함수를 보면 setMember에 value를 설정하고, 다시 if문을 사용해서 setShowConsulting의 boolean 상태값을 조정하는 두 가지 기능이 추가되어 복잡해졌습니다.</p>
</blockquote>
<p>예시 사진을 보면, 초록색으로 구성된 부분은 멤버 여부 확인을 위한 구간이며, 멤버 확인을 마친 후의 구간은 보라색으로 표시되어 있습니다. 팝업을 보여줄지 여부에 따라 진행되는 노란색 구간에는 회원가입 로직이 포함되어 있어 정렬되지 않은 코드 구성을 볼 수 있습니다.</p>
<p>이러한 복잡성은 규모가 커질수록 유지보수가 어려워지고, 협업 과정에서 무해하다고 생각했던 함수들이 오히려 에러를 발생시키는 상황을 초래할 수 있습니다. 
따라서, 가독성이 좋은 코드를 구성하는 것이 매우 중요합니다.</p>
<p>이제 기능별로 구성하고, 가독성이 좋은 코드로 만들어 보겠습니다.</p>
<p>먼저, 가독성이 좋은 코드를 작성하려면 기능을 명확하게 정의하고 단순히 줄이는 것이 아니라 재사용 가능하게 구성하는 것이 중요합니다. </p>
<blockquote>
<p>Popup 컴포넌트는 event와 title을 커스텀할 수 있도록 설계하여 재사용성을 높였습니다. 또한, 기능적으로 많은 부분을 포함하지 않고 간단한 구조로 구성하여 이해하기 쉽도록 분리하였습니다.</p>
</blockquote>
<pre><code>const Popup = ({ title, children, onClose }) =&gt; (
  &lt;div className=&quot;popup&quot;&gt;
    &lt;h2&gt;{title}&lt;/h2&gt;
    {children}
    &lt;button onClick={onClose}&gt;닫기&lt;/button&gt;
  &lt;/div&gt;
);
</code></pre><blockquote>
<p>회원가입은 다른 기능과는 완전히 별개이기 때문에, 기능적인 부분을 명확히 구분하여 구성하였습니다. 이렇게 함으로써 코드의 가독성을 높이고 유지보수가 용이하도록 하였습니다.</p>
</blockquote>
<pre><code>const SignUpForm = ({ onClose }) =&gt; (
  &lt;Popup title=&quot;회원가입&quot; onClose={onClose}&gt;
    &lt;form&gt;
      &lt;input type=&quot;text&quot; placeholder=&quot;이름&quot; /&gt;
      &lt;input type=&quot;email&quot; placeholder=&quot;이메일&quot; /&gt;
      &lt;input type=&quot;password&quot; placeholder=&quot;비밀번호&quot; /&gt;
      &lt;button type=&quot;submit&quot;&gt;가입하기&lt;/button&gt;
    &lt;/form&gt;
  &lt;/Popup&gt;
);</code></pre><blockquote>
<p>ConsultantView 컴포넌트는 member로 인증된 회원에게 팝업을 보여줄지 판단하는 기능을 명확히 구분하였습니다. 이 과정에서 Popup 컴포넌트를 사용하여 재사용성을 잘 활용한 것을 확인할 수 있습니다.</p>
</blockquote>
<pre><code>const ConsultantView = ({ showPopup, onTogglePopup }) =&gt; (
  &lt;&gt;
    &lt;button onClick={onTogglePopup}&gt;상담사 보기&lt;/button&gt;
    {showPopup &amp;&amp; (
      &lt;Popup title=&quot;상담사 이미지&quot; onClose={onTogglePopup}&gt;
        &lt;img src=&quot;/path/to/consultant-image.jpg&quot; alt=&quot;상담사&quot; /&gt;
      &lt;/Popup&gt;
    )}
  &lt;/&gt;
);</code></pre><blockquote>
<p>InputCom은 input 부분을 따로 분리하여, 특정 기능에서만 사용하는 것이 아니라 다른 곳에서도 재사용할 수 있도록 구성되었습니다.</p>
</blockquote>
<pre><code>const InputCom = ({ value, onChange }) =&gt; (
  &lt;input 
    value={value} 
    onChange={onChange} 
    placeholder=&quot;입력하세요&quot; 
  /&gt;
);</code></pre><blockquote>
<p>종합적으로 코드를 구성한 부분을 import하여, 위에 보여준 사진과는 다르게 여기에서는 사용자 회원 여부를 확인하고 컨트롤하는 컴포넌트로 기능을 구현하였습니다. 이렇게 구성함으로써 추후 유지보수도 간단하게 할 수 있음을 확인할 수 있습니다.</p>
</blockquote>
<pre><code>const UserTypeButton = () =&gt; {
  const [member, setMember] = useState(&#39;&#39;);
  const [showPopup, setShowPopup] = useState(false);

  const isMember = member === &#39;ok&#39;;

  const handleMemberInput = (event) =&gt; {
    const value = event.target.value;
    setMember(value);
  };

  const togglePopup = () =&gt; {
    setShowPopup(!showPopup);
  };

  return (
    &lt;&gt;
      &lt;InputCom value={member} onChange={handleMemberInput} /&gt;
      {isMember ? (
        &lt;ConsultantView showPopup={showPopup} onTogglePopup={togglePopup} /&gt;
      ) : (
        &lt;SignUpForm onClose={togglePopup} /&gt;
      )}
    &lt;/&gt;
  );
};</code></pre><p>추천영상
<a href="https://www.youtube.com/watch?v=edWbHp_k_9Y">https://www.youtube.com/watch?v=edWbHp_k_9Y</a></p>
<h3 id="간략-내용정리">간략 내용정리</h3>
<ol>
<li><p><strong>가독성 향상</strong>: 명확하고 일관된 코드 스타일을 유지하면 다른 개발자들이 코드를 쉽게 읽고 이해할 수 있습니다.</p>
</li>
<li><p><strong>유지보수 용이</strong>: 잘 구조화된 코드는 수정과 업데이트가 쉽습니다. 이는 버그 수정이나 새로운 기능 추가 시 큰 도움이 됩니다.</p>
</li>
<li><p><strong>재사용성 증가</strong>: 모듈화된 코드와 재사용 가능한 컴포넌트는 개발 시간을 단축시키고 일관성을 유지하는 데 기여합니다.</p>
</li>
<li><p><strong>협업 효율성</strong>: 클린코드는 팀원 간의 협업을 원활하게 하여 프로젝트의 전반적인 생산성을 높입니다.</p>
</li>
<li><p><strong>디버깅 용이</strong>: 명확한 코드 구조는 오류를 찾고 해결하는 데 걸리는 시간을 줄여줍니다.</p>
</li>
<li><p><strong>비즈니스 가치 향상</strong>: 코드 품질이 높아지면 제품의 신뢰성과 안정성이 증가하여 비즈니스 가치를 높일 수 있습니다.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Nextjs14 Sever component rendering]]></title>
            <link>https://velog.io/@korea-dollar/Nextjs14-Sever-component-rendering</link>
            <guid>https://velog.io/@korea-dollar/Nextjs14-Sever-component-rendering</guid>
            <pubDate>Wed, 12 Jun 2024 13:50:32 GMT</pubDate>
            <description><![CDATA[<p><a href="https://nextjs.org/docs/app/building-your-application/rendering/server-components">참고문서 NEXTJS DOC</a></p>
<h3 id="react-server-componentrsc의-진행-방식">React Server Component(RSC)의 진행 방식</h3>
<ul>
<li><p>서버에서 요청이 들어오면 RSC Payload를 생성합니다.</p>
</li>
<li><p>RSC Payload와 클라이언트 컴포넌트의 자바스크립트 인스트럭션을 활용하여 실제 HTML을 생성합니다.</p>
</li>
<li><p>클라이언트에서 생성된 HTML을 응답받으면, 먼저 pre rendering이 진행됩니다.</p>
</li>
<li><p>이후 RSC Payload가 생성되면 그 정보를 바탕으로 클라이언트에서 reconcile 단계가 진행됩니다.</p>
</li>
<li><p>reconcile 단계가 클라이언트에서 진행되는 이유는 클라이언트가 가지는 트리 구조에 빈 공간(placeholder)이 있기 때문에 그 공간을 채우는 과정이기 때문입니다.</p>
</li>
<li><p>이후 서버 컴포넌트와 클라이언트 컴포넌트가 hydrate되고, HTML에 React를 끼얹어 상호작용이 가능해집니다.
<img src="https://velog.velcdn.com/images/korea-dollar/post/bc981957-79ab-4bd6-bb6b-b1e34eae2972/image.png" alt="">
자료출처 : <a href="https://www.smashingmagazine.com/2024/05/forensics-react-server-components/">https://www.smashingmagazine.com/2024/05/forensics-react-server-components/</a></p>
<h3 id="nextjs에서의-서버-컴포넌트-rendering-진행-순서">Next.js에서의 서버 컴포넌트 rendering 진행 순서</h3>
</li>
<li><p>Next.js는 서버에서 React의 API를 활용하여 렌더링을 진행합니다.
렌더링 작업은 개별 경로의 segment와 Suspense 경계에 따라 chunk로 분할됩니다.</p>
</li>
<li><p>React는 서버 컴포넌트를 RSC Payload라는 특수 데이터 형식으로 렌더링합니다.</p>
</li>
<li><p>RSC Payload</p>
<ul>
<li>서버 컴포넌트의 렌더링된 결과</li>
<li>클라이언트 컴포넌트가 렌더링되어야 할 위치의 자리 표시</li>
<li>해당 JavaScript 파일에 대한 참조</li>
<li>서버 컴포넌트에서 클라이언트 컴포넌트로 전달된 모든 props가 포함됩니다.</li>
</ul>
</li>
<li><p>Next.js는 RSC Payload와 클라이언트 컴포넌트 JavaScript 지침을 사용하여 서버에서 HTML을 렌더링합니다.</p>
</li>
<li><p>클라이언트에서 HTML은 초기 페이지 로드에만 사용되며, 빠르고 비대화형적인 경로 preview를 즉시 표시합니다.
<img src="https://velog.velcdn.com/images/korea-dollar/post/cb390bc9-0eb2-45bf-9134-165a7efb4383/image.png" alt=""></p>
</li>
<li><p>RSC Payload는 클라이언트와 서버 컴포넌트 트리를 조화시키고 DOM을 업데이트하는 데 사용됩니다.</p>
</li>
<li><p>JavaScript 지침은 클라이언트 컴포넌트를 수화하고 애플리케이션을 대화형으로 만드는 데 사용됩니다.
이상으로 React Server Component(RSC)와 Next.js에서의 서버 컴포넌트 렌더링 과정을 정리해 보았습니다. 
<img src="https://velog.velcdn.com/images/korea-dollar/post/445676a9-844b-4f70-b3b8-9591fe24f9f4/image.png" alt="">
<img src="https://velog.velcdn.com/images/korea-dollar/post/a26b467d-6a35-4bf5-bca6-4c062ab00754/image.png" alt=""></p>
</li>
</ul>
<p>자료출처 : <a href="https://saengmotmi.netlify.app/react/what-is-rsc/">https://saengmotmi.netlify.app/react/what-is-rsc/</a></p>
<h3 id="서버-컴포넌트">서버 컴포넌트</h3>
<pre><code>const ServerComponent = () =&gt; {
    // 이벤트 함수
    const handleClientEvent = () =&gt; {
    // client event발생
    console.log(&#39;서버에서 발생한 클라이언트 이벤트가 서버에서 처리가 되었습니다!&#39;);
   };
return (
    &lt;div onClick={() =&gt; handleClientEvent()}&gt;
        서버에서 클릭이벤트가 실행됩니다.
    &lt;/div&gt;
    );
};</code></pre><h4 id="코드-분석">코드 분석</h4>
<ul>
<li><p>ServerComponent는 서버 측에서 정의된 컴포넌트입니다.</p>
</li>
<li><p>handleClientEvent 함수는 클라이언트에서 발생한 이벤트를 서버에서 처리하는 역할을 합니다.</p>
</li>
<li><p>서버 컴포넌트는 onClick 이벤트 핸들러를 통해 클라이언트에서 발생한 이벤트를 받아 처리할 수 있습니다.</p>
<h3 id="서버-컴포넌트--클라이언트로-전달되는-rsc-payload">서버 컴포넌트 &gt; 클라이언트로 전달되는 RSC Payload</h3>
<p>서버 컴포넌트에서 클라이언트로 전달되는 RSC Payload는 서버 측에서 설정하는 합니다. 
그래서 일반적으로 React Server Components(RSC) 구현에서는 서버 측 코드에서 이 RSC Payload를 생성하여 클라이언트에 전달하게 됩니다.</p>
<pre><code>// Next.js 서버 측 코드 예시
export const getServerSideProps = () =&gt; {
return {
  props: {
    rscPayload: {
      type: &#39;RSC_PAYLOAD&#39;,
      data: {
        initialState: {
            // 클라이언트 컴포넌트의 초기 상태 설정
          counter: 0
        },
        eventHandlers: {
            // 클라이언트에서 발생한 이벤트에 대한 핸들러 설정
          onClick: &#39;handleServerEvent&#39;
        }
      }
    }
  }
};
};</code></pre><h4 id="코드-분석-1">코드 분석</h4>
</li>
<li><p>서버 컴포넌트에서 클라이언트로 전달되는 데이터 구조입니다.</p>
</li>
<li><p>initialState에는 클라이언트 컴포넌트의 초기 상태 정보가 포함되어 있습니다.</p>
</li>
<li><p>eventHandlers에는 클라이언트에서 발생한 이벤트에 대한 핸들러 정보가 포함되어 있습니다.</p>
</li>
<li><p>payload를 통해 클라이언트 컴포넌트는 서버에서 전달된 초기 상태와 이벤트 핸들러를 활용할 수 있습니다.</p>
<h3 id="클라이언트-컴포넌트">클라이언트 컴포넌트</h3>
<pre><code>const ClientComponent = ({ initialState, eventHandlers }) =&gt; {
// 클라이언트에서 이벤트 핸들러 정의
const handleClientEvent = () =&gt; {
  // 클라이언트에서 발생한 이벤트에 대한 처리
  console.log(&#39;클라이언트에서 발생한 이벤트가 클라이언트에서 처리가 되었습니다.&#39;);
};

// 클라이언트에서 이벤트 핸들러 등록됩니다.
const handleClick = () =&gt; {
  if (eventHandlers &amp;&amp; eventHandlers.onClick) {
    // 서버에서 전달된 이벤트 핸들러 실행합니다.
    eventHandlers.onClick();
  } else {
    // 서버에서 전달된 이벤트 핸들러가 없는 경우, 클라이언트에서 정의한 핸들러 실행합니다.
    handleClientEvent();
  }
};

return (
  &lt;div onClick={handleClick}&gt;
    클라이언트에서 클릭 이벤트가 실행됩니다.
    &lt;p&gt;Counter: {initialState.counter}&lt;/p&gt;
  &lt;/div&gt;
);
};</code></pre><h4 id="코드-분석-2">코드 분석</h4>
</li>
<li><p>ClientComponent는 클라이언트 측에서 정의된 컴포넌트입니다.</p>
</li>
<li><p>handleClientEvent 함수는 클라이언트에서 발생한 이벤트를 처리하는 역할을 합니다.</p>
</li>
<li><p>handleClick 함수는 클라이언트에서 발생한 이벤트를 처리하는데, 서버에서 전달된 이벤트 핸들러(eventHandlers.onClick)가 있는 경우 해당 핸들러를 실행합니다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[2년차 개발자의 팀 리빌딩의 시작]]></title>
            <link>https://velog.io/@korea-dollar/1.5%EB%85%84%EC%B0%A8-%EA%B0%9C%EB%B0%9C%EC%9E%90%EC%9D%98-%ED%8C%80-%EB%A6%AC%EB%B9%8C%EB%94%A9%EC%9D%98-%EC%8B%9C%EC%9E%91</link>
            <guid>https://velog.io/@korea-dollar/1.5%EB%85%84%EC%B0%A8-%EA%B0%9C%EB%B0%9C%EC%9E%90%EC%9D%98-%ED%8C%80-%EB%A6%AC%EB%B9%8C%EB%94%A9%EC%9D%98-%EC%8B%9C%EC%9E%91</guid>
            <pubDate>Tue, 04 Jun 2024 05:27:25 GMT</pubDate>
            <description><![CDATA[<p>저는 단지 2년차 개발자에 불과하지만 회사로부터 개발팀 리빌딩을 진행해달라는 요청을 받았습니다.
이러한 큰 책임을 맡기에는 제 경험이 턱없이 부족하다고 생각하여 처음에는 거절했습니다. 
그러나, &#39;언제 다시 이런 기회가 올까?&#39; 하는 생각에 다시 마음을 바꾸게 되었습니다. 
최근 우아한형제들의 송요창 개발자님의 강연을 듣고, 특히 팀 리빌딩에 대한 질문에 대한 답변에서 큰 영감을 받았습니다. 
송요창 개발자님은 팀 리빌딩을 언제 경험할 수 있느냐며, 이를 통해 얻을 수 있는 귀중한 경험을 강조하셨습니다.
또한, 우아한테크세미나에서 테크리더 세 분이 말하는 &#39;개발자 원칙&#39; 영상을 시청하며, 어떤 개발자가 되어야 좋은 팀 리빌딩을 할 수 있는지, 어떤 방식으로 개발자 문화를 구성해야 할지에 대해 많은 고민을 하게 되었습니다.
이러한 경험들을 통해, 저는 팀 리빌딩의 중요성과 그것을 성공적으로 이끌어나가기 위한 몇 가지 핵심 요소들에 대해 배울 수 있었습니다.
 첫째, 투명한 소통과 개방적인 문화의 중요성입니다. 팀원들 간의 솔직한 대화와 피드백은 팀의 단합과 생산성 향상에 필수적입니다.
 둘째, 팀원들의 장점을 인식하고 이를 최대한 활용하는 것입니다. 각자의 강점을 살려주면서 동시에 약점을 보완해 나가는 것이 중요합니다. 
마지막으로, 지속적인 학습과 성장을 장려하는 환경을 조성하는 것입니다. 기술은 끊임없이 발전하므로, 팀원들이 최신 기술 동향에 발맞추어 학습할 수 있는 환경을 제공하는 것이 중요하다고 생각합니다.</p>
<p>이러한 교훈들을 바탕으로, 저는 저희 팀을 더욱 강하고 유연한 팀으로 리빌딩하는 데 전념하고 있습니다.
이 과정에서 얻은 경험과 지식을 공유하고자 합니다. 팀 리빌딩은 단순히 구성원을 재배치하는 것 이상의 의미가 있다고 느끼게 되었습니다.
팀원분들의 각자의 잠재력을 최대한 발휘하고, 함께 성장해 나가는 과정이 중요하다는 것도 많이 느끼게 되었습니다.
저와 같은 상황에 처한 다른 개발자분들에게 이 글이 도움이 되길 바라며, 더 나은 팀 문화와 개발 환경을 만드는 데 기여할 수 있기를 희망합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Typescript 기초]]></title>
            <link>https://velog.io/@korea-dollar/Typescript-%EA%B8%B0%EC%B4%88</link>
            <guid>https://velog.io/@korea-dollar/Typescript-%EA%B8%B0%EC%B4%88</guid>
            <pubDate>Tue, 04 Jun 2024 01:20:51 GMT</pubDate>
            <description><![CDATA[<p>프론트엔드 개발자로서 사용자에게 안정적인 UX를 제공하는 것은 매우 중요합니다. 안정적인 사용자 경험을 통해 신뢰감을 주고 더 나은 웹사이트를 만들 수 있기 때문입니다. 그리고 높은 코드 품질로 웹사이트를 개발하면 사용자가 버그 없이 웹사이트를 경험할 수 있습니다. 이는 기업의 이미지에 긍정적인 영향을 줄 수 있습니다.
<a href="https://github.com/KoreaMoney/typescript-beginner">Typescript basic_github link</a></p>
<h3 id="typescript-등장-배경">TypeScript 등장 배경</h3>
<p>안정적인 개발과 코드 품질 향상을 위해 TypeScript를 사용하는 것이 좋습니다. TypeScript는 동적 타입 언어인 JavaScript를 보완하며 등장했습니다.</p>
<p>그렇다면 TypeScript는 새로운 언어일까요? 아닙니다. TypeScript는 JavaScript의 상위 집합으로, JavaScript 엔진을 사용하며 개발자가 원하는 변수의 타입을 정의할 수 있습니다. 그리고 이렇게 작성된 TypeScript 코드는 JavaScript로 컴파일되어 실행됩니다.</p>
<h3 id="typescript--javascript">TypeScript &amp; Javascript</h3>
<p>TypeScript와 JavaScript의 차이점을 간단히 살펴보겠습니다.</p>
<p><strong>1. 정적 타입 vs 동적 타입</strong></p>
<p>TypeScript는 &quot;<strong>정적 타입 언어</strong>&quot;이고, JavaScript는 &quot;<strong>동적 타입 언어</strong>&quot;입니다.
JavaScript는 변수의 타입이 실행 시간에 결정되는 동적 타입 지정 방식을 사용합니다. 이는 쉽게 배우고 유연하다는 장점이 있지만, 런타임 에러가 발생할 가능성이 있습니다. 특히 대규모 프로젝트에서는 모듈 간 오류 등을 찾아내기 어려울 수 있습니다.
반면 TypeScript는 컴파일 단계에서 타입을 체크하고, 타입 오류를 미리 알려줍니다. 이를 통해 개발 과정에서 빠르게 오류를 찾아내고 수정할 수 있어, 사전에 버그를 방지할 수 있습니다.
이처럼 TypeScript의 정적 타입 시스템은 JavaScript의 동적 타입 지정 방식이 가진 단점을 보완하고자 등장했습니다. 개발자는 TypeScript를 통해 보다 안전하고 생산적인 코드 작성이 가능합니다.</p>
<p><strong>2. 컴파일 언어 vs 인터프리터 언어</strong>
JavaScript와 TypeScript는 언어를 해석하는 과정에서 중요한 차이가 있습니다.
JavaScript는 &quot;<strong>인터프리터 언어</strong>&quot;입니다. 인터프리터 언어는 소스코드를 한 줄씩 읽어가며 즉시 실행합니다. 이로 인해 코드가 빨리 실행되는 장점이 있습니다.
반면 TypeScript는 &quot;<strong>컴파일 언어</strong>&quot;입니다. 컴파일 언어는 변수의 타입을 명시적으로 지정해야 합니다. 컴파일 단계에서 타입을 체크하기 때문에, 코드 작성 중에 타입 오류를 미리 알려줄 수 있습니다. 이를 &quot;타입 어노테이션&quot;이라고 합니다. 이를 통해 버그를 빨리 발견하고 방지할 수 있습니다.</p>
<p>이처럼 JavaScript와 TypeScript는 언어의 근본적인 특성이 다르기 때문에, 개발 과정과 결과물에서 차이가 있습니다. 개발자는 이러한 차이를 잘 이해하고 프로젝트의 특성에 맞는 언어를 선택해야 합니다.</p>
<h3 id="typescript-특징">TypeScript 특징</h3>
<ol>
<li>TypeScript의 강력한 타입 시스템은 사전에 버그를 예방할 수 있는 핵심 요소입니다.</li>
<li>TypeScript를 사용하면 가장 먼저 마주하게 되는 것이 바로 &quot;타입&quot;입니다. 타입은 변수의 &quot;자료형&quot;을 의미합니다. 문자형, 숫자형, 불리언, 객체, 배열 등 변수가 어떤 형태의 데이터를 가지고 있는지를 나타내는 추상적인 개념입니다.</li>
<li>TypeScript는 정적 타입 기반 언어입니다. 즉, 컴파일 과정에서 변수의 타입이 결정됩니다. 이를 통해 컴파일 단계에서 타입 오류를 미리 발견할 수 있습니다. 따라서 TypeScript를 사용하면 컴파일 에러를 사전에 예방할 수 있고, 디버깅 작업도 훨씬 수월해집니다.</li>
</ol>
<p>이처럼 TypeScript의 강력한 타입 시스템은 안정적인 코드 작성을 가능하게 해줍니다. 변수의 타입을 명확히 정의함으로써 예기치 못한 버그를 사전에 차단할 수 있는 것이 가장 큰 장점이라 할 수 있습니다. 이런 장점 이외에 Typescript만의 장점을 다른 것도 확인해보겠습니다.</p>
<h3 id="typescript-장점">TypeScript 장점</h3>
<ul>
<li><p>TypeScript는 높은 생산성을 제공합니다. JavaScript로 코드를 작성하면 객체의 필드나 함수의 매개변수로 들어오는 값이 어떤 것인지 파악하기 위해 여러 파일을 확인해야 하는 단점이 있습니다. 하지만 TypeScript를 사용하면 변수와 데이터의 자료형을 쉽게 파악할 수 있습니다.</p>
</li>
<li><p>TypeScript를 사용하면 개발자는 개발의 큰 구조를 구성하고 핵심 부분에 집중할 수 있습니다. 객체 내부의 값을 전부 기억할 필요가 없어지며, 자동으로 리스트업 해주기 때문에 생산성이 향상됩니다. 이러한 생산성 향상은 예기치 못한 동작을 사전에 방지할 수 있습니다.</p>
</li>
<li><p>TypeScript는 JavaScript의 상위 집합이기 때문에, 기존에 JavaScript로 구성된 프로젝트를 쉽게 마이그레이션할 수 있습니다. 대규모 코드 수정 없이도 TypeScript로의 전환이 가능합니다.</p>
</li>
<li><p>프로젝트 전체를 한 번에 TypeScript로 전환하는 것이 부담스럽다면, 일부 기능에만 한정하여 점진적으로 적용할 수 있습니다. 이렇게 단계적으로 전환을 진행하면 효율적으로 TypeScript를 도입할 수 있습니다. 추후 필요에 따라 점차 나머지 부분으로 TypeScript 적용 범위를 확장해 나갈 수 있습니다.</p>
</li>
</ul>
<p>TypeScript는 자료형 정보를 명시적으로 제공하여 개발 생산성을 높이고, 잠재적인 버그를 사전에 차단할 수 있습니다. 이를 통해 개발자는 핵심 로직에 더욱 집중할 수 있게 되는 것입니다.
이처럼 TypeScript는 기존 JavaScript 코드와의 호환성이 뛰어나, 프로젝트의 점진적인 마이그레이션을 가능하게 합니다. 이를 통해 개발팀은 큰 부담 없이 TypeScript의 장점을 활용할 수 있게 됩니다.</p>
<p>그렇다고 TypeScript에 단점이 없는 것은 아닙니다. TypeScript 역시 장단점이 존재합니다.</p>
<h3 id="typescript-단점">TypeScript 단점</h3>
<ul>
<li><p>학습에 어려움이 있고 생산성도 저하 될 수 있습니다. TypeScript를 처음 접하는 개발자의 경우, 타입 시스템 등 새로운 개념을 익히는 데 어려움을 겪을 수 있습니다. 이로 인해 초기 생산성이 저하될 수 있습니다. TypeScript의 사용이 익숙하지 않은 개발자들은 타입 관련 학습 시간이 필요하며, 이는 프로젝트 진행 속도에 영향을 미칠 수 있습니다.</p>
</li>
<li><p>타입 정의 및 지정의 어려움이 있습니다. 복잡한 프로젝트에서는 적절한 타입 정의가 쉽지 않을 수 있습니다. 개발자는 매번 타입을 지정해줘야 하는 번거로움을 겪을 수 있습니다. 또한 타입 어노테이션으로 인한 타입 에러 발생 등으로 실제 개발보다 타입을 지정하는 데 더 많은 시간을 소비할 수 있습니다.</p>
</li>
</ul>
<p>따라서 TypeScript 도입 시에는 이러한 학습 곡선과 타입 정의 및 지정의 어려움을 고려해야 합니다. 개발팀의 역량과 프로젝트의 복잡도에 따라 TypeScript의 장단점을 균형 있게 평가하고, 적절한 적용 방안을 모색해야 합니다.</p>
<h3 id="type지정">TYPE지정</h3>
<p>TypeScript 도입을 위해 기존 JavaScript와 React JSX 파일을 각각 .ts와 .tsx로 변경합니다. 이를 통해 변수와 함수의 타입을 명시하거나 자동으로 정의할 수 있어, 정적 타입 검사로 개발 생산성과 코드 품질을 높일 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/korea-dollar/post/58744217-fdc8-47f7-95a7-aa744e5334f7/image.png" alt=""></p>
<p>TypeScript는 정적 타입 시스템을 제공하여 변수 선언 시 명시한 타입과 다른 값을 대입하려 하면 컴파일 단계에서 오류를 발생시킵니다. 이를 통해 개발 과정에서 발생할 수 있는 타입 관련 문제를 사전에 방지할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/korea-dollar/post/6ef8df8b-6fad-40d9-a9a9-eb04fa1ec4d7/image.png" alt=""></p>
<h3 id="string">String</h3>
<pre><code>let variable = &quot;hello&quot;;
variable = 15; // fail
variable = &quot;world&quot;; // pass</code></pre><p>변수로 선언한 것은 문자열(string)입니다. 하지만 fail로 처리된 부분은 문자열이 아닌 숫자(number) 타입입니다. 이 경우, TypeScript는 &quot;number 형식은 string 형식에 할당할 수 없습니다&quot;라는 type에러를 발생시킵니다.</p>
<h3 id="number">Number</h3>
<pre><code>let age = 20;
age = &quot;20&quot;; // fail
age = 15; // pass</code></pre><h3 id="string--number-type정의">String &amp; Number Type정의</h3>
<pre><code>let testString: string;
    testString = 20; // fail
    testString = &quot;hello world&quot;; // pass

let ageWithType: number;
    ageWithType = &quot;hello world&quot;; // fail
    ageWithType = 20; // pass

let testBoolean: boolean;
    testBoolean = &quot;world&quot; // fail
    testBoolean = 2 // fail
    testBoolean = false; // pass</code></pre><p>변수 뒤의 &quot;:&quot;는 타입을 정의하는 것으로, 정의한 타입과 변수에 할당된 값이 다를 경우 타입 에러가 발생합니다.</p>
<h3 id="union-type">Union Type</h3>
<pre><code>let testStringOrNumber: string | number; 
    testStringOrNumber = 10; // pass
    testStringOrNumber = &quot;hello world&quot;; // pass
    testStringOrNumber = false; // fail</code></pre><p>유니온 타입은 자바스크립트의 OR(||) 연산자와 같이 &quot;A 아니면 B&quot;라는 의미를 가진 타입을 말합니다. &quot;|&quot; 연산자를 사용해 다양한 타입을 결합하는 이 방법을 유니온 타입 정의라고 합니다.
위의 예시는 string 또는 number인 경우는 type에서 pass하지만 이외 경우 타입이 일치하지 않기 때문에 오류를 발생합니다.</p>
<h3 id="array">Array</h3>
<pre><code>let names = [&quot;jenny&quot;, &quot;jane&quot;, &quot;tom&quot;];
    names.push(3); // fail
    names.push(&quot;john&quot;); // pass

let numbers = [10, 20, 30];
    numbers.push(&quot;john&quot;); // fail
    numbers.push(40); // pass</code></pre><p><img src="https://velog.velcdn.com/images/korea-dollar/post/89cb8123-be0d-4a98-83c5-5c8ee1ae9a55/image.png" alt=""></p>
<p>[string] 타입은 names에 추가되는 항목도 문자열이어야 함을 의미합니다. 위의 코드에서는 배열에 문자열 타입이 지정되어 있으며, 숫자를 배열에 추가하려고 하면 타입 에러가 발생하는 것을 확인할 수 있습니다.</p>
<h3 id="array-type정의">Array Type정의</h3>
<pre><code>let testStringArray: string[];
    testStringArray = [1, 2, 3]; // fail
    testStringArray = [&quot;jan&quot;, &quot;Feb&quot;, &quot;Mar&quot;]; // pass

let testNumberArray: number[];
    testNumberArray = [&quot;jan&quot;, false, 20]; // fail 
    testNumberArray = [1, 2, 3]; // pass

let testStringOrNumberArray: (string | number)[]; 
    testStringOrNumberArray = [1, 2, &quot;string&quot;]; // pass
    testStringOrNumberArray = [1, 2, &quot;string&quot;, true]; // fail</code></pre><p><img src="https://velog.velcdn.com/images/korea-dollar/post/fc22d111-a8da-4596-96ea-6ef404a050b8/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/korea-dollar/post/85b86a36-8c94-4bb0-bfff-58237a107c59/image.png" alt=""></p>
<p>number[]으로 type선언한 부분에서 fail을 보면 number을 제외한 문자열,불리언이 들어오면 타입에러가 발생하는 것을 볼 수 있습니다. 유니온 타입으로 선언한 값에서 fail이 발생한 이유는 string과 number이외에 boolean값이 들어갔기 때문입니다.</p>
<h3 id="object">Object</h3>
<pre><code>let user = {
  username: &quot;john&quot;,
  age: 222,
  isAdmin: false,
};

    user.username = &quot;admin&quot;; // pass
    user.age = &quot;20&quot;; // fail 
    user.age = 20; // pass
    user.isAdmin = true; // pass
    user.phone = &quot;+8110123445678&quot; // fail </code></pre><p><img src="https://velog.velcdn.com/images/korea-dollar/post/566f2a58-9df9-4504-b96e-55cf0b4a3f47/image.png" alt=""></p>
<p>에러가 발생한 이유는 user 객체 내에서 phone 항목에 대한 타입이 명시되지 않았기 때문입니다. user 객체에서 phone의 값으로 number가 선언되어 있으므로, 값을 변경하려면 같은 타입을 유지해야 합니다.</p>
<h3 id="object-type정의">Object Type정의</h3>
<pre><code>let userObj: {
  username: string;
  age: number;
  isAdmin: boolean;
};

    userObj = {
         username: &quot;john&quot;,
         age: 20,
          isAdmin: false,
   };</code></pre><p><img src="https://velog.velcdn.com/images/korea-dollar/post/3f182f1d-943f-422b-b571-59ac60b9df2d/image.png" alt=""></p>
<p>userObj에서 정의한 타입에 맞지 않으면 형식 오류가 발생합니다. 모든 속성이 올바르게 작성되어야만 통과됩니다.</p>
<h3 id="선택적-인자">선택적 인자</h3>
<pre><code>let userObj2: {
  username: string;
  age: number;
  isAdmin: boolean;
  phone?: string; // ?: 선택적 인자
};
    userObj2 = {
          username: &quot;hugh&quot;,
          age: 20,
          isAdmin: false,
    };</code></pre><p>선택적 인자는 &quot;<strong>?:</strong>&quot;로 타입 앞에 표기하며, 해당 항목이 있을 수도 있고 없을 수도 있는 상황에서 유연하게 대처하기 위해 사용됩니다. 이렇게 구성되면 함수는 유연성을 가지게 되어 더 나은 개발 효율성을 기대할 수 있습니다. 예를 들어, phone이 선택적 인자로 정의되어 있다면, phone이 있어도 되고 없어도 되며, 있을 경우 문자열을 가질 것임을 의미합니다.</p>
<h3 id="any">Any</h3>
<pre><code>let testAny;
    testAny = &quot;john&quot;; // pass
    testAny = 12; // pass
    testAny = true; // pass
    testAny = [&quot;john&quot;]; // pass
    testAny = [true, 20, &quot;John&quot;]; // pass
    testAny = {}; // pass

let testAnyArray: any[];
    testAnyArray = [20, true, &quot;coke&quot;, []]; // pass</code></pre><p><img src="https://velog.velcdn.com/images/korea-dollar/post/05d4f1c1-b344-4b64-ae38-29b7981fdb84/image.png" alt=""></p>
<p>any 타입은 어떤 타입도 지정할 수 있어, 일반 JavaScript와 다르지 않게 됩니다. 이렇게 되면 TypeScript를 사용하는 이유가 사라지기 때문에, any 타입을 무분별하게 사용하는 것은 추천하지 않습니다. 이는 TypeScript에서도 권장되지 않습니다.</p>
<h3 id="functions">Functions</h3>
<pre><code>let sayHi = () =&gt; {
  console.log(&quot;hello world!&quot;);
};
    sayHi = &quot;hello world!&quot;; // fail

let funReturnString = (): string =&gt; {
  console.log(&quot;hello world!&quot;);
  return &quot;world&quot;;
};

let multiple = (num: number) =&gt; {
  return num * 2;
};

let multiple2 = (num: number): number =&gt; {
  return num * 2;
};</code></pre><p><img src="https://velog.velcdn.com/images/korea-dollar/post/4971f58c-dd44-4954-a8ae-10f9dd18668b/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/korea-dollar/post/1a987383-dc1e-49f1-a166-dff4db19a3c9/image.png" alt=""></p>
<p>함수에서 반환 타입을 선언하지 않고 반환 값이 없다면, 해당 함수는 void로 선언됩니다. 다시 말해, 함수의 () 뒤에 <strong>:type</strong>을 선언하면 그 함수는 해당 타입으로 지정된다는 의미입니다. 또한, props가 존재한다면, 해당 props의 항목에 사용하는 부분에도 타입이 필요합니다.</p>
<h3 id="void">Void</h3>
<pre><code>let multiple3 = (num: number): void =&gt; {
  console.log(num)
};

let sum = (num1: number, num2: number, another?: number) =&gt; {
  return num1 + num2;
};
sum(2, 3);

let func = (user: { username: string; age: number; phone?: string }) =&gt; {
  console.log(&quot;user: &quot;, user.username);
};</code></pre><p>void는 함수에서 반환 값이 없을 경우 사용되는 반환 타입입니다. 이는 함수에 return 문이 없거나 명시적으로 값을 반환하지 않을 때 추론되는 타입을 의미합니다.</p>
<p>TypeScript에서 void를 반환 타입으로 지정하면, undefined 외에 다른 값을 반환할 수도 있습니다. 하지만, 일반적으로 void는 반환 값이 없다는 것을 나타내며, 실제로 반환 값을 사용하지 않음을 의미합니다. 따라서, void는 함수가 반환 값을 사용하지 않을 것이라는 것을 명시적으로 나타내기 위해 사용됩니다.</p>
<p>추가적으로, TypeScript에서는 void를 사용하여 반환 값을 명확히 하지 않는 함수를 정의함으로써 코드의 명료성을 높일 수 있습니다. 이는 함수가 부수 효과(side effect)만을 위해 호출된다는 것을 나타내는 좋은 방법입니다.</p>
<h3 id="type-aliases">Type Aliases</h3>
<pre><code>type UserType = {
  username: string;
  age: number;
  phone?: string;
};

let betterFunc = (user: UserType) =&gt; {
  console.log(user.username);
};

type myFunc = (a: number, b: string) =&gt; void;

let write: myFunc = (num, str) =&gt; {
  console.log(num + &quot;times&quot; + str);
};

type UserType2 = {
  username: string;
  age: number;
  phone?: string;
  theme: &quot;dark&quot; | &quot;light&quot;;
};

const userWithTheme: UserType2 = {
  username: &quot;hugh&quot;,
  age: 20,
  theme: &quot;dark&quot;,
};</code></pre><p>타입 별칭(Type Aliases)은 새로운 타입 값을 생성하는 것이 아니라, 이미 정의된 타입에 대하여 나중에 쉽게 참조할 수 있도록 이름을 지정하는 방법입니다. 타입 별칭과 인터페이스(Interface) 사이의 주요 차이점 중 하나는 타입의 확장 가능성 여부에 있습니다. 인터페이스는 확장할 수 있어서, 기존의 인터페이스에 새로운 속성이나 메서드를 추가하는 것이 가능하지만, 타입 별칭은 한 번 선언되면 그 형태를 변경할 수 없습니다.</p>
<p>따라서, 가능한 경우 인터페이스를 사용하여 타입을 선언하는 것이 좋습니다. 이는 코드의 유연성을 높이고, 나중에 타입을 확장하거나 수정할 필요가 있을 때 보다 쉽게 대응할 수 있게 해줍니다. TypeScript에서 타입 별칭은 특정한 경우에 유용하게 사용될 수 있지만, 일반적으로는 인터페이스를 통한 타입 선언을 권장합니다.</p>
<h3 id="interface">Interface</h3>
<pre><code>
interface IUser {
  username: string;
  email: string;
  age: number;
}

interface IEmployee extends IUser {
  employeeId: number;
}

const emp: IUser = {
  username: &quot;tom&quot;,
  email: &quot;tom@gmail.com&quot;,
  age: 20,
};

const emp2: IEmployee = {
  username: &quot;tom&quot;,
  email: &quot;tom@gmail.com&quot;,
  age: 20,
  employeeId: 10,
};</code></pre><p>TypeScript에서 인터페이스는 코드의 재사용성을 높이고, 명확한 계약을 정의하는 데 중요한 역할을 합니다. 특히, 인터페이스를 이용한 상속 기능은 여러 인터페이스의 특성을 결합하여 새로운 타입을 정의할 수 있는 강력한 방법을 제공합니다. 그리고 extends 키워드를 사용하는 인터페이스 상속은 다음과 같은 이점을 가지고 있습니다.</p>
<ul>
<li><strong>다중 상속 지원</strong> : 인터페이스는 다른 여러 인터페이스들의 속성을 상속받아, 복합적인 타입을 만들 수 있습니다. 예를 들어, interface A extends B, C라고 선언하면, 인터페이스 A는 B와 C의 모든 멤버를 상속받게 됩니다.</li>
<li><strong>코드 재사용성 증가</strong> : 기존 인터페이스의 속성을 재정의할 필요 없이, 상속을 통해 새로운 인터페이스를 쉽게 확장할 수 있습니다. 이는 코드의 중복을 줄이고, 유지 관리를 용이하게 합니다.
인터페이스 상속을 통해, 개발자는 더 명확하고 강력한 타입 계약을 정의할 수 있습니다. 이는 프로젝트의 안정성과 코드의 가독성을 향상시킵니다.</li>
</ul>
<p>결과적으로 TypeScript의 인터페이스는 개발자가 더욱 강력하고 유연한 코드를 작성할 수 있게 도와줍니다. 따라서 인터페이스의 확장 기능은 TypeScript를 사용하는 데 있어서 중요한 개념 중 하나입니다.</p>
<h3 id="generics">Generics</h3>
<pre><code>interface IAuthor {
  id: number;
  username: string;
}

interface ICategory {
  id: number;
  title: string;
}

interface IPost {
  id: number;
  titles: string;
  desc: string;
  extra: IAuthor[] | ICategory[];
}

interface IPostBetter&lt;T&gt; {
  id: number;
  title: string;
  desc: string;
  extra: T[];
}

const testMe: IPostBetter&lt;String&gt; = {
  id: 1,
  title: &quot;post title&quot;,
  desc: &quot;post description&quot;,
  extra: [&quot;str1&quot;, &quot;str2&quot;],
};

interface IPostEvenBetter&lt;T extends object&gt; {
  id: number;
  title: string;
  desc: string;
  extra: T[];
}

const testMe2: IPostEvenBetter&lt;{ id: number; username: string }&gt; = {
  id: 1,
  title: &quot;post title&quot;,
  desc: &quot;post description&quot;,
  extra: [
    {
      id: 1,
      username: &quot;tom&quot;,
    },
  ],
};

const testMe3: IPostEvenBetter&lt;IAuthor&gt; = {
  id: 1,
  title: &quot;post title&quot;,
  desc: &quot;post description&quot;,
  extra: [
    {
      id: 1,
      username: &quot;tom&quot;,
    },
  ],
};

const testMe4: IPostEvenBetter&lt;ICategory&gt; = {
  id: 1,
  title: &quot;post title&quot;,
  desc: &quot;post description&quot;,
  extra: [
    {
      id: 1,
      title: &quot;category title&quot;,
    },
  ],
};</code></pre><p>TypeScript의 제네릭은 타입을 고정된 값이 아닌, 변할 수 있는 &#39;변수&#39;처럼 다루어 코딩의 유연성을 극대화하는 기능입니다. 이를 통해 개발자는 더 일반화된 코드를 작성할 수 있으며, 이는 코드의 재사용성과 타입 안정성을 동시에 증가시킵니다.</p>
<p>제네릭을 사용하면, 꺾쇠(&lt;&gt;) 안에 변수명을 넣어 타입 변수를 선언할 수 있습니다. 이때, 자주 사용되는 변수명으로는 <strong>T</strong>가 있는데, 이는 Type의 약자로 볼 수 있습니다. 하지만, T 외에도 U, V 등 개발자가 원하는 어떤 이름도 사용할 수 있습니다.</p>
<p>예를 들어, 배열의 모든 요소를 포함하는 함수를 만들 때, 제네릭을 사용하면 다양한 타입의 배열에 대해 같은 함수를 사용할 수 있습니다. 이는 함수나 클래스 등을 다양한 타입에 대해 재사용 가능하게 만들어 줍니다.</p>
<p>위 코드에서 <strong>T</strong>는 사용자가 함수를 호출할 때 결정되는 타입으로, 이는 제네릭이 코드를 더 유연하게 만드는 방법 중 하나입니다.
제네릭을 사용함으로써, TypeScript 개발자는 타입 안정성을 유지하면서도 다양한 타입에 대해 동작하는 재사용 가능한 컴포넌트를 생성할 수 있습니다. 이는 크게 코드의 품질을 향상시키고, 개발 과정을 더욱 효율적으로 만듭니다.</p>
<h3 id="react">React</h3>
<h4 id="reactnode-type">ReactNode Type</h4>
<pre><code>const Parent = ({ children }: { children: React.ReactNode }) =&gt; {
  return (
    &lt;div&gt;
      &lt;h1&gt;This is the parent&lt;/h1&gt;
      {children}
    &lt;/div&gt;
  );
};

export default Parent;


const ChildrenPropExample = () =&gt; {
    return (
        &lt;div&gt;
            &lt;Parent&gt;
                &lt;Child /&gt;
                &lt;SecondChild /&gt;
            &lt;/Parent&gt;
        &lt;/div&gt;
    );
};

export default ChildrenPropExample;</code></pre><p>ReactNode 타입은 JSX 내에서 사용할 수 있는 모든 요소의 타입을 포괄합니다. 이는 ReactChild, ReactFragment, ReactPortal을 포함하며, 또한 boolean, null, undefined 값까지 다룹니다. 이로 인해 ReactNode는 매우 유연하며 다양한 형태의 자식 요소를 JSX 내에서 표현할 수 있게 해줍니다.</p>
<p>클래스 컴포넌트에서는 render 함수가 이 ReactNode 타입을 반환하는 것이 일반적입니다. 이는 클래스 컴포넌트가 화면에 렌더링할 내용을 정의할 때 ReactNode를 사용하여 다양한 형태의 출력을 지원한다는 것을 의미합니다.</p>
<p>반면에, 함수 컴포넌트는 ReactElement 인터페이스를 반환합니다. 이 차이는 ReactElement가 보다 구체적인 JSX 요소를 나타내는 반면, ReactNode는 더 넓은 범위의 타입, 즉 JSX에서 사용될 수 있는 거의 모든 것을 포괄한다는 점에서 비롯됩니다.</p>
<p>이러한 특성 덕분에, React 개발자들은 다양한 타입의 자식 요소들을 효과적으로 관리하고 조합할 수 있으며, 이는 React 애플리케이션의 유연성과 확장성을 크게 향상시킵니다.</p>
<p>parent안에 들어가는 children같은 경우 parent에서 React.ReactNode로 type을 정의했기 때문에 문제없이 props로 child가 들어가는 것을 확인 할 수 있습니다.</p>
<h4 id="event-type">Event Type</h4>
<pre><code>const EventExample = () =&gt; {
    const handleChange = (e: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; {
        console.log(e.target.value);
    };

    const handleClick = (e: React.MouseEvent&lt;HTMLButtonElement&gt;) =&gt; {
        e.preventDefault();
        console.log(&quot;Searched!&quot;);
    };

    const handleDelete = (e: React.MouseEvent&lt;HTMLButtonElement&gt;, id: number) =&gt; {
        e.preventDefault();
        console.log(`Post ${id} has been deleted!`);
    };

    return (
        &lt;div className=&quot;eventExample&quot;&gt;
            &lt;form&gt;
                &lt;input type=&quot;text&quot; placeholder=&quot;Search for anything...&quot; onChange={handleChange} /&gt;
                &lt;button onClick={handleClick}&gt;Search&lt;/button&gt;
            &lt;/form&gt;
            &lt;form className=&quot;post&quot;&gt;
                &lt;h1&gt;{&quot;타입스크립트의 이벤트 항목(1)&quot;}&lt;/h1&gt;
                &lt;p&gt;
                    Lorem ipsum dolor sit amet consectetur adipisicing elit.
                &lt;/p&gt;
                &lt;button onClick={(e) =&gt; handleDelete(e, 1)}&gt;Delete&lt;/button&gt;
            &lt;/form&gt;
            &lt;form className=&quot;post&quot;&gt;
                &lt;h1&gt;{&quot;타입스크립트의 이벤트 항목(2)&quot;}&lt;/h1&gt;
                &lt;p&gt;
                    Lorem ipsum dolor sit amet consectetur adipisicing elit.
                &lt;/p&gt;
                &lt;button onClick={(e) =&gt; handleDelete(e, 2)}&gt;Delete&lt;/button&gt;
            &lt;/form&gt;
        &lt;/div&gt;
    );
};

export default EventExample;</code></pre><p>React에서는 다양한 이벤트 핸들러를 제공하며, 대표적으로 onClick과 onChange 이벤트 핸들러를 사용할 수 있습니다.</p>
<p>onClick 이벤트의 경우, 주로 HTML의 button 태그 요소와 함께 사용되므로 HTMLButtonElement 타입이 필요합니다. 또한, 마우스 이벤트가 발생할 때는 React.MouseEvent 타입을 사용합니다. 따라서 onClick 이벤트의 타입은 &quot;React.MouseEvent&quot;에 <strong>HTMLButtonElement</strong>가 됩니다.</p>
<p>반면에, onChange 이벤트는 일반적으로 HTML의 input 태그 요소와 함께 사용되며, 이 경우 HTMLInputElement 타입이 필요합니다. 입력 이벤트가 발생할 때는 React.ChangeEvent 타입을 사용하므로, onChange 이벤트의 타입은 &quot;React.ChangeEvent&quot;의 <strong>HTMLInputElement</strong> 가 됩니다.</p>
<p>특정 액션(예: 삭제 또는 선택)을 구분해야 할 경우, 이벤트와 함께 <strong>ID</strong>를 전달할 수 있습니다. 이때 해당 ID의 타입도 명확히 정의해 주어야 합니다. 이를 통해 이벤트 핸들러는 더욱 명확하고 타입 안전성을 보장할 수 있습니다.</p>
<p>이러한 타입 정의를 통해 React 이벤트 핸들러는 보다 견고하고 유지보수하기 쉬운 코드 작성을 가능하게 합니다.</p>
<h4 id="useref-type">UseRef Type</h4>
<pre><code>const UseRefExample = () =&gt; {
  const inputRef = useRef&lt;HTMLInputElement&gt;(null);
  const usernameInputRef = useRef&lt;HTMLInputElement&gt;(null);

  useEffect(() =&gt; {
    inputRef.current?.focus();
  }, []);

  const handleClick = () =&gt; {
    console.log(&quot;username is: &quot; + usernameInputRef.current?.value);
  };

  return (
    &lt;div className=&quot;useRefExample&quot;&gt;
      &lt;input ref={inputRef} type=&quot;text&quot; placeholder=&quot;focus here&quot; /&gt;
      &lt;input ref={usernameInputRef} type=&quot;text&quot; placeholder=&quot;username&quot; /&gt;
      &lt;button onClick={handleClick}&gt;Send&lt;/button&gt;
    &lt;/div&gt;
  );
};

export default UseRefExample;</code></pre><p>useRef를 사용할 때는 참조하는 HTML 태그의 타입을 정확히 지정하는 것이 중요합니다. 예를 들어 input 태그를 참조한다면 HTMLInputElement 타입을 사용해야 하고, button 태그를 참조한다면 HTMLButtonElement 타입을 사용해야 합니다.</p>
<p>이렇게 적절한 타입을 지정하면 코드의 타입 안전성이 높아지고, 참조 객체의 속성과 메서드를 보다 안전하게 활용할 수 있습니다. 타입을 명확히 지정함으로써 컴파일 타임에 오류를 사전에 방지할 수 있고, 코드 자동 완성 기능을 통해 개발 효율성도 높일 수 있습니다.</p>
<p>따라서 개발 과정에서 이 점을 잘 기억하고 적용하면 보다 견고하고 유지보수하기 쉬운 React 애플리케이션을 만들 수 있습니다. 타입스크립트의 강력한 타입 시스템을 최대한 활용하는 것이 핵심입니다.</p>
<h4 id="usestate-type">UseState Type</h4>
<pre><code>interface UserType {
    sessionId: number;
    name: string;
}

const UseStateExample = () =&gt; {
    const [username, setUsername] = useState(&quot;&quot;);
    const [user, setUser] = useState&lt;UserType | null&gt;(null);
    // OR
    // const [user, setUser] = useState&lt;UserType&gt;();

    const handleChange = (e: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; {
        setUsername(e.target.value);
    };

    const handleClick = (e: React.MouseEvent&lt;HTMLButtonElement&gt;) =&gt; {
        e.preventDefault();
        setUser({
            name: username,
            sessionId: Math.random(),
        });
    };

    const handleClickLogout = (e: React.MouseEvent&lt;HTMLButtonElement&gt;) =&gt; {
        e.preventDefault();
        setUser(null);
    };

    return (
        &lt;div className=&quot;useStateExample&quot;&gt;
            {user ? (
                &lt;&gt;
                    &lt;b&gt;{user.name} logged in Typescript &lt;/b&gt;
                    &lt;button onClick={handleClickLogout}&gt;Logout&lt;/button&gt;
                &lt;/&gt;
            ) : (
                &lt;form&gt;
                    &lt;input type=&quot;text&quot; placeholder=&quot;Username&quot; onChange={handleChange} /&gt;
                    &lt;button onClick={handleClick}&gt;Login&lt;/button&gt;
                &lt;/form&gt;
            )}
        &lt;/div&gt;
    );
};

export default UseStateExample;</code></pre><p>useState 훅을 사용할 때, 상태 값의 타입을 명확히 정의하는 것은 매우 중요합니다. 예를 들어, 상태 값이 UserType이 될 수도 있고 null일 수도 있는 경우와, 상태 값이 항상 UserType이어야 하고 초기 값에 null을 주지 않는 경우 두 가지로 나눌 수 있습니다. 이 부분은 상황에 맞게 타입을 정의하면 됩니다.
위 코드를 기준으로 설명하도록 하겠습니다.</p>
<ul>
<li>UserType 또는 null을 허용하는 경우
상태 값이 UserType이거나 초기 상태로 null일 수 있음을 명시합니다. 예를 들어, 사용자가 로그인하기 전에는 null로 설정하고 로그인 후에는 UserType 객체로 설정할 수 있습니다.</li>
<li>항상 UserType만을 허용하는 경우
상태 값이 항상 UserType이어야 하며, 초기 값도 UserType 객체로 설정합니다. 예를 들어, 애플리케이션이 시작될 때 기본 사용자 정보를 로드하여 상태에 설정할 수 있습니다.<h4 id="usecontext--usereducer-type">UseContext &amp; UseReducer Type</h4>
<pre><code>interface StateType {
  theme: string;
  fontSize: number;
}
</code></pre></li>
</ul>
<p>interface ColorActionType {
    type: &quot;CHANGE_THEME&quot;;
}
type SizeActionType = {
    type: &quot;CHANGE_FONTSIZE&quot;;
    payload: number;
};</p>
<p>type ActionType = ColorActionType | SizeActionType;</p>
<p>export const ThemeContext = createContext&lt;{
    state: StateType;
    dispatch: React.Dispatch<ActionType>;
}&gt;({
    state: INITIAL_STATE,
    dispatch: () =&gt; {},
});</p>
<pre><code>useReducer를 사용할 때, state와 dispatch 모두에 대해 타입을 정의하는 것이 중요합니다. state는 상태 항목에 들어가는 부분의 타입을 정의하고, dispatch는 action을 실행하기 때문에 React.Dispatch를 사용하여 ActionType을 정의합니다.
- **상태와 액션 타입 정의** : 먼저 상태 타입과 액션 타입을 정의해야 합니다.</code></pre><p>interface StateType {
    theme: string;
    fontSize: number;
}</p>
<p>interface ColorActionType {
    type: &quot;CHANGE_THEME&quot;;
}
type SizeActionType = {
    type: &quot;CHANGE_FONTSIZE&quot;;
    payload: number;
};</p>
<p>type ActionType = ColorActionType | SizeActionType;</p>
<pre><code>- **리듀서 함수 정의** : 리듀서 함수는 상태와 액션을 받아 새로운 상태를 반환합니다.</code></pre><p>const reducer = (state: StateType, action: ActionType) =&gt; {
  switch (action.type) {
    case &quot;CHANGE_THEME&quot;:
      return {
        ...state,
        theme: state.theme === &quot;dark&quot; ? &quot;light&quot; : &quot;dark&quot;,
      };
    case &quot;CHANGE_FONTSIZE&quot;:
      return {
        ...state,
        fontSize: action.payload,
      };</p>
<pre><code>default:
  return state;</code></pre><p>  }
};</p>
<pre><code>- **useReducer 훅 사용** : useReducer 훅을 사용할 때 초기 상태와 리듀서 함수를 전달합니다. 이때 state와 dispatch의 타입이 자동으로 유추됩니다.</code></pre><p>const INITIAL_STATE = {
  theme: &quot;dark&quot;,
  fontSize: 20,
};</p>
<p>export const ThemeProvider = ({ children }: { children: React.ReactNode }) =&gt; {
  const [state, dispatch] = useReducer(reducer, INITIAL_STATE);</p>
<p>  return &lt;ThemeContext.Provider value={{ state, dispatch }}&gt;{children}&lt;/ThemeContext.Provider&gt;;
};</p>
<pre><code>- **컴포넌트에서 사용** : state와 dispatch를 컴포넌트 내에서 사용하여 상태를 관리하고 액션을 디스패치할 수 있습니다.</code></pre><p>const UseContextExample = () =&gt; {
    const { state, dispatch } = useContext(ThemeContext);
    console.log(state);</p>
<pre><code>return (
    &lt;div className=&quot;useContextExample&quot;&gt;
        &lt;button onClick={() =&gt; 
        dispatch({ type: &quot;CHANGE_THEME&quot; })}&gt;Change Theme&lt;/button&gt;
        &lt;button onClick={() =&gt; 
        dispatch({ type: &quot;CHANGE_FONTSIZE&quot;, payload: 20 })}&gt;Change Font Size&lt;/button&gt;
    &lt;/div&gt;
);</code></pre><p>};</p>
<p>export default UseContextExample;</p>
<pre><code>useReducer를 사용할 때 상태와 액션의 타입을 명확히 정의하면, 코드의 타입 안전성을 높이고, 유지보수성 및 가독성을 향상시킬 수 있습니다.
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[three.js glb & gltf 압축]]></title>
            <link>https://velog.io/@korea-dollar/three.js-glb-gltf-%EC%95%95%EC%B6%95</link>
            <guid>https://velog.io/@korea-dollar/three.js-glb-gltf-%EC%95%95%EC%B6%95</guid>
            <pubDate>Thu, 30 May 2024 02:22:56 GMT</pubDate>
            <description><![CDATA[<p>Three.js를 사용하여 glb 및 gltf 파일을 불러오는 과정에서 로딩 시간이 상당히 길어지는 문제에 직면했습니다. 이 문제를 해결하기 위해 DracoLoader를 도입했지만, 기대했던 만큼 로딩 시간이 단축되지 않았습니다. 그러나 gltf-pipeline를 사용한 결과, 원래 파일 크기 408,172,052에서 322,741,968로 약 <strong>85MB</strong> 가량 줄이는 데 성공했습니다.</p>
<h3 id="dracoloader">DracoLoader</h3>
<p><a href="https://threejs.org/docs/#examples/en/loaders/DRACOLoader">three.js doc dracoLoader</a></p>
<pre><code>import { DRACOLoader } from &#39;three/examples/jsm/loaders/DRACOLoader.js&#39;

const dracoLoader = new DRACOLoader()

dracoLoader.setDecoderPath(&#39;/draco/&#39;)
gltfLoader.setDRACOLoader(dracoLoader)</code></pre><p><strong>DracoLoader</strong>는 Three.js에서 제공하는 로더 중 하나로, Google의 Draco라는 기술을 활용해 3D 모델의 메쉬(Mesh)와 텍스처(Texture) 데이터를 압축하여 로딩 시간을 단축시키는 데에 목적이 있습니다. Draco는 특히 3D 그래픽 데이터의 크기를 상당히 줄일 수 있으며, 이로 인해 웹 환경에서 3D 콘텐츠를 더 빠르게 로드하고 렌더링할 수 있게 해줍니다. 하지만 무조건 장점만 존재하지 않습니다.</p>
<ul>
<li>장점<ul>
<li><strong>로딩 시간 단축</strong>: 큰 사이즈의 3D 모델과 텍스처 파일을 압축하여 웹 환경에서의 로딩 시간을 크게 줄일 수 있습니다.<ul>
<li><strong>네트워크 효율성</strong>: 데이터 전송량이 적어지므로 네트워크 사용량이 감소하며, 특히 데이터 사용이 중요한 모바일 환경에서 유리합니다.</li>
</ul>
</li>
<li><strong>사용자 경험 개선</strong>: 로딩 시간 감소로 인해 사용자의 대기 시간이 줄어들어, 전반적인 사용자 경험이 향상됩니다</li>
</ul>
</li>
<li>단점<ul>
<li><strong>처리 시간</strong>: 압축된 데이터를 원래대로 복구하는데 추가적인 처리 시간이 필요할 수 있습니다. 이는 클라이언트의 성능에 따라 달라질 수 있습니다.</li>
<li><strong>호환성 문제</strong>: 모든 3D 엔진이나 플랫폼에서 Draco 압축을 지원하는 것은 아니므로, 호환성을 고려해야 합니다.</li>
</ul>
</li>
</ul>
<p><strong>동작원리</strong></p>
<ul>
<li>DracoLoader의 동작 원리는 기본적으로 Draco 압축 알고리즘을 사용하여 3D 모델 데이터를 효율적으로 압축하고, 이를 다시 웹에서 사용할 수 있도록 해제하는 과정입니다.<ul>
<li><strong>압축 단계</strong>: 3D 모델의 메쉬와 텍스처 데이터는 Draco 압축 도구를 사용하여 압축됩니다. 이 과정에서 데이터 구조가 최적화되어 파일 크기가 줄어듭니다.</li>
<li><strong>전송 단계</strong>: 압축된 파일은 웹 서버를 통해 클라이언트에 전송됩니다.</li>
<li><strong>해제 단계</strong>: 클라이언트 측에서 DracoLoader를 사용하여 압축된 데이터를 해제하고, Three.js 엔진이 이해할 수 있는 형태로 변환하여 렌더링합니다.
이 과정을 통해, 원본 3D 모델 데이터보다 훨씬 작은 파일을 전송하고 처리할 수 있으므로, 로딩 시간을 단축시키고 사용자 경험을 개선할 수 있습니다.</li>
</ul>
</li>
</ul>
<h3 id="gltf-pipeline">glTF-Pipeline</h3>
<p><a href="https://www.npmjs.com/package/gltf-pipeline/v/0.1.0-alpha3">NPM Gltf-pipeline</a></p>
<p><strong>glTF-Pipeline</strong>은 glTF (.gltf/.glb) 모델을 최적화하고 변환하는 도구입니다. 이 도구를 사용하여 모델 파일의 크기를 줄이고 로딩 시간을 개선할 수 있습니다. 예를 들어, glTF 모델을 Draco 압축을 사용하여 최적화하거나, 이미지를 KTX2 형식으로 변환하여 텍스처의 크기를 줄일 수 있습니다. 그리고 3D 모델과 씬(Scene)을 최적화하고 변환하는 도구입니다. 이 도구는 glTF (GL Transmission Format) 형식의 3D 모델을 위한 공식적인 처리 파이프라인으로, 모델의 크기를 줄이고 로딩 시간을 단축시키며, 다양한 플랫폼과 장치에서의 호환성을 높이는데 중점을 둡니다. glTF는 &quot;JPEG of 3D&quot;로 불리며, 웹과 모바일 환경에서 3D 콘텐츠를 전송하기 위한 효율적인 포맷입니다.</p>
<ul>
<li>장점<ul>
<li><strong>성능 향상</strong>: glTF-Pipeline을 통해 3D 모델의 파일 크기를 줄이면서도 품질을 유지할 수 있어, 로딩 시간이 단축되고 전체적인 성능이 향상됩니다.<ul>
<li><strong>호환성</strong>: 다양한 플랫폼과 장치에서의 호환성이 높아집니다. glTF 형식은 널리 지원되므로, 변환된 모델은 다양한 환경에서 사용할 수 있습니다.</li>
</ul>
</li>
<li><strong>자동화</strong>:  glTF-Pipeline은 명령줄 도구나 Node.js API를 통해 쉽게 자동화할 수 있으며, 대규모 3D 콘텐츠의 배치 처리에 적합합니다.</li>
</ul>
</li>
<li>단점<ul>
<li><strong>처리 시간</strong>: 대규모 파일이나 복잡한 모델의 경우, 변환 과정에서 상당한 처리 시간이 소요될 수 있습니다.</li>
<li><strong>특정 기능의 제한</strong>: 모든 3D 모델링 기능이나 특성이 glTF 형식으로 완벽하게 변환되지 않을 수 있으므로, 일부 디테일이나 기능의 손실이 발생할 수 있습니다.</li>
</ul>
</li>
</ul>
<p><strong>작동원리</strong>
glTF-Pipeline의 작동 원리는 상당히 직접적입니다. 이 도구는 glTF 형식의 3D 모델을 입력으로 받아, 다양한 최적화 작업을 수행합니다. 이러한 작업에는 드라코(Draco) 메시 압축, 이미지 및 텍스처 최적화, 불필요한 데이터 제거, 그리고 파일 분할 등이 포함됩니다. 최적화 과정을 거친 후, 훨씬 작은 파일 크기로 변환된 glTF 파일이 출력됩니다. 이 과정을 통해, 원본 모델의 품질을 유지하면서도 전송 및 로딩 시간을 크게 줄일 수 있습니다.</p>
<p>설치</p>
<blockquote>
<p>npm install -g gltf-pipeline</p>
</blockquote>
<p>설치 후 glb파일 최적화 적용</p>
<blockquote>
<p>gltf-pipeline -i originalModel.glb -o optimizedModel.glb -d</p>
</blockquote>
<p>상대 경로를 사용하여 src 폴더 내부로 접근이 필요한 경우, gltf-pipeline을 활용하여 파일을 압축하였을 때 압축률이 개선되고 로딩 속도 역시 눈에 띄게 향상되는 것을 확인했습니다.</p>
<blockquote>
<p>gltf-pipeline -i src/assets/models/originalModel.glb -o src/assets/models/optimizedModel.glb -d</p>
</blockquote>
<p>gltf-pipeline option적용 예시</p>
<blockquote>
<p>gltf-pipeline -i src/assets/models/dymnt.glb -d  -o src/assets/models/draco.glb --draco.quantizePositionBits 14</p>
</blockquote>
<p>gltf-pipeline을 사용한 결과는 다음과 같습니다. 적용 전에는 DracoLoader만 사용할 경우, 3D 파일과 텍스처를 모두 불러오는 데 21.45초가 소요되었습니다. 그러나 gltf-pipeline을 적용한 후에는 13.45초로 약 <strong>38%</strong>가량 줄어 사용자 경험이 크게 향상되었습니다. 또한, 리소스 파일 크기도 기존 746MB에서 650MB로 약 <strong>12.87%</strong> 감소하여 최적화가 잘 이루어졌음을 확인할 수 있었습니다.</p>
<ul>
<li>로딩 시간 평가: 전체 화면 로딩 완료 시점<ul>
<li>이 시간은 사용자가 웹 페이지와 상호작용할 수 있는 시점까지의 총 로딩 시간을 의미합니다.</li>
</ul>
</li>
</ul>
<p><strong>GltfLoader만 적용</strong>
초기 측정 결과, 전체 화면 로딩 완료까지 소요된 시간은 평균 28.93초로 나타났습니다. 
<img src="https://velog.velcdn.com/images/korea-dollar/post/ce1b625f-a5e0-42de-872c-c3d6a0b8fde1/image.png" alt=""></p>
<p><strong>DracoLoader만 적용</strong>
초기 측정 결과, 전체 화면 로딩 완료까지 소요된 시간은 평균 21.45초로 나타났습니다. 
<img src="https://velog.velcdn.com/images/korea-dollar/post/b11b0e03-cbdc-4b62-9652-15b002d6eb74/image.png" alt=""></p>
<p><strong>DracoLoader + gltf-pipeline 적용</strong>
초기 측정 결과, 전체 화면 로딩 완료까지 소요된 시간은 평균 13.45초로 나타났습니다. 
<img src="https://velog.velcdn.com/images/korea-dollar/post/e458ca33-1e20-42bf-9fd8-b92cb0998013/image.png" alt=""></p>
<ul>
<li>무조건 압축은 좋은 부분은 아닙니다. 그만큼 화질이 깨져 단점도 존재하니 적절하게 사용하시는 걸 추천드립니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js14 App Router 2편]]></title>
            <link>https://velog.io/@korea-dollar/Next.js14-App-Router-2%ED%8E%B8</link>
            <guid>https://velog.io/@korea-dollar/Next.js14-App-Router-2%ED%8E%B8</guid>
            <pubDate>Sun, 26 May 2024 16:51:55 GMT</pubDate>
            <description><![CDATA[<h3 id="data-fetching">Data Fetching</h3>
<p>Next.js에서는 서버의 각 가져오기 요청에 대한 캐싱 및 재검증 동작을 구성할 수 있습니다.</p>
<ul>
<li><strong>데이터 캐싱</strong><pre><code>const getData = async () =&gt; {
const res = await fetch(&quot;https://jsonplaceholder.typicode.com/posts&quot;, { cache: &quot;force-cache&quot; });
if (!res.ok) {
  throw new Error(&quot;Something went wrong&quot;);
}
return res.json();
};</code></pre>fetch 내에 있는 cache 옵션 중 <strong>force-cache</strong>를 사용하면, 기본적으로 Next.js가 반환된 값을 서버의 데이터 캐시에 자동으로 저장합니다. 이는 빌드 시간이나 요청 시간에 데이터를 불러오고, 캐시하여, 각각의 데이터 요청마다 재사용 가능하다는 것을 의미합니다. 데이터 캐시는 설정된 시간 동안 웹 서버로 들어오는 모든 요청에 대해 활성화됩니다. 이러한 메커니즘 덕분에 1000명의 사용자가 접속한다 해도 실제로 API로는 단 한 번의 요청만이 이루어져서 큰 효율성을 자랑합니다. 또한, 캐시되지 않은 데이터(예: { cache: &#39;no-store&#39; })는 항상 데이터 소스에서 직접 가져와 저장됩니다.
<img src="https://velog.velcdn.com/images/korea-dollar/post/9017604e-4816-4850-8953-cecd954c856b/image.png" alt=""></li>
</ul>
<ul>
<li><strong>데이터 재검증</strong><pre><code>const getData = async () =&gt; {
const res = await fetch(&quot;https://jsonplaceholder.typicode.com/posts&quot;, { next: { revalidate: 1000 } });
if (!res.ok) {
  throw new Error(&quot;Something went wrong&quot;);
}
return res.json();
};</code></pre></li>
<li><em>데이터 재검증(Revalidating Data)*</em>은 데이터 캐시를 제거하고 최신 데이터를 다시 가져오는 과정입니다. 이는 데이터가 변경되어 최신 정보를 제공해야 할 때 유용합니다. 현재 next.revalidate를 1초로 설정해두었기 때문에, 1초 동안 1,000명의 사용자가 접속하더라도 실제 API 요청은 단 한 번만 전송됩니다.</li>
</ul>
<h3 id="seo">SEO</h3>
<p>SEO(Search Engine Optimization, 검색 엔진 최적화)는 구글과 같은 검색 엔진에 친화적인 사이트를 구축하여, 광고가 아닌 자연 검색 결과를 통해 트래픽의 양과 질을 극대화하는 작업을 의미합니다. 웹사이트의 기술적인 부분을 개선하여 검색 엔진이 웹사이트의 콘텐츠를 잘 이해하고 인덱싱할 수 있도록 하는 것도 최적화 작업의 중요한 부분입니다. 그러나 궁극적으로, SEO는 사용자들에게 유용하고 양질의 콘텐츠를 제공함으로써, 다양한 관련 키워드로 검색 결과 페이지에 노출되는 것을 목표로 하는 마케팅 전략입니다. 이를 통해 웹사이트의 온라인 가시성을 크게 개선할 수 있습니다.</p>
<pre><code>export const metadata = {
  title: &quot;FEDown | Introduction&quot;,
  description: &quot;Frontend developer&quot;,
};</code></pre><p>Next.js에서는 이러한 SEO를 간편하게 구성할 수 있습니다. 아래 코드는 정적 메타데이터를 설정하는 예입니다. SEO를 위해 페이지나 레이아웃에 메타데이터를 추가하고, 웹 페이지의 제목과 설명을 작성하면 됩니다.</p>
<p>metadata를 사용 시에는 server component로 구성된 공간에서만 사용이 가능합니다. 만약 client component가 되는 공간에는 아래와 같은 에러가 발생합니다.</p>
<blockquote>
<p>Error: 
  × You are attempting to export &quot;metadata&quot; from a component marked with &quot;use client&quot;, which is disallowed. Either remove the export, or the &quot;use client&quot; directive.</p>
</blockquote>
<p>아울러 app의 layout.js파일에 아래와 같은 코드로 작성 시 반복적으로 처리 된 내용을 하나로 묶어서 진행 할 수도 있습니다.</p>
<pre><code>export const metadata = {
  title: {
    default: &quot;FEDowon | home&quot;,
    template: &quot;%s | FEDowon&quot;,
  },
  description: &quot;Frontend developer&quot;,
};</code></pre><p>about page</p>
<pre><code>export const metadata = {
  title: &quot;About&quot;,
  description: &quot;About Description&quot;,
};</code></pre><p><strong>동적 metadata</strong></p>
<pre><code>export const generateMetadata = async ({ params }) =&gt; {
  const { slug } = params;
  const post = await getPost(slug);
  return {
    title: post.title,
    description: post.desc,
  };
};</code></pre><p>metadata를 동적으로 구성하기 위해서는 비동기적으로 데이터 처리를 진행하고 그 상태에서 title와 description을 작성하면 됩니다.</p>
<h3 id="server-action">Server action</h3>
<p>server action을 사용하기 위해서는 &quot;use server&quot;를 작성하여 진행합니다.</p>
<pre><code>const ServerTestPage = () =&gt; {
  const actionComponent = async () =&gt; {
    &quot;use server&quot;;
    console.log(&quot;it works back&quot;);
  };
  return (
    &lt;div&gt;
      &lt;form action={actionComponent}&gt;
        &lt;button&gt;Test me&lt;/button&gt;
      &lt;/form&gt;
    &lt;/div&gt;
  );
};
export default ServerTestPage;</code></pre><p>함께 server가 작성된 code입니다. lib안에 action.js를 만들고 form action에 actionComponent를 넣어도 동일하게 작동 됩니다.
일단 &quot;use server&quot;를 작성함으로서 server에서 동작할 수 있게 됩니다.
<img src="https://velog.velcdn.com/images/korea-dollar/post/b6f0746e-5fbe-4d28-8b2a-0376031cddfa/image.png" alt="">
<img src="https://velog.velcdn.com/images/korea-dollar/post/bbdb68b9-7ae3-4870-8cc5-6fe47effbf26/image.png" alt=""></p>
<p>다음 사진과 같이 &quot;Test me&quot; 버튼을 클릭하면, 서버에서 반응하여 터미널에 console.log 값이 출력되는 것을 확인할 수 있습니다. 또한, 네트워크 탭에서도 서버의 동작이 진행된 것을 확인할 수 있습니다.</p>
<h3 id="revalidatepath">revalidatePath</h3>
<pre><code>export const addPsot = async (formData) =&gt; {
  &quot;use server&quot;;
  const { title, desc, slug, userId } = Object.fromEntries(formData);
  try {
    connectToDb();
    const newPost = new Post({ title, desc, slug, userId });
    await newPost.save();
    revalidatePath(&quot;/blog&quot;);
  } catch (err) {
    console.log(err);
    return { err: &quot;Something went wrong&quot; };
  }
};
</code></pre><p>revalidatePath 함수는 특정 경로에 대해 필요에 따라 캐시된 데이터를 제거하고, 최신 데이터를 제공하기 위해 캐시된 데이터를 재검증하는 데 사용됩니다.</p>
<h3 id="api-route">API Route</h3>
<p><img src="https://velog.velcdn.com/images/korea-dollar/post/6a70a46b-6432-45e3-a936-7e83c9f03921/image.png" alt="">
URL에서 확인할 수 있듯이, &#39;api/blog/post1&#39; 같은 경로 구성이 가능합니다. Next.js에서는 앱 내부에 &#39;api&#39;라는 폴더를 만들어 이와 유사한 방식으로 진행할 수 있습니다.
<img src="https://velog.velcdn.com/images/korea-dollar/post/072173d7-2500-4f03-9b0c-f307d330cf74/image.png" alt="">
예시코드는 mongodb를 이용하여 만든 route.js입니다.</p>
<pre><code>import { Post } from &quot;@/lib/models&quot;;
import { connectToDb } from &quot;@/lib/utils&quot;;
import { NextResponse } from &quot;next/server&quot;;

export const GET = async (req) =&gt; {
  try {
    connectToDb();
    const posts = await Post.find();
    return NextResponse.json(posts);
  } catch (err) {
    console.error(&quot;Failed to fetch posts&quot;);
  }
};</code></pre><p>작성된 코드를 보면 NextResponse이 있습니다. NextResponse는 더 많은 편의 기능을 제공하는 웹 응답 API를 확장합니다. </p>
<h4 id="nextresponse-option">NextResponse option</h4>
<ul>
<li>cookies : 응답의 Set-Cookie 헤더를 읽거나 수정할 수 있습니다.</li>
<li>set(name, value) : 주어진 이름에 대한 값을 사용하여 응답에 쿠키를 설정합니다.<pre><code>let response = NextResponse.next()
response.cookies.set(&#39;show-banner&#39;, &#39;false&#39;)
return response
// Response will have a `Set-Cookie:show-banner=false;path=/home` header</code></pre></li>
<li>get(name) : 쿠키 이름을 제공하면 해당 쿠키의 값을 반환합니다. 쿠키를 찾을 수 없는 경우 undefined가 반환됩니다. 여러 개의 쿠키가 발견되면 첫 번째 쿠키가 반환됩니다.<pre><code>let response = NextResponse.next()
// { name: &#39;show-banner&#39;, value: &#39;false&#39;, Path: &#39;/home&#39; }
response.cookies.get(&#39;show-banner&#39;)</code></pre></li>
<li>getAll() : 쿠키 이름을 제공하면 해당 쿠키의 값들을 반환합니다. 이름이 제공되지 않은 경우 응답에 있는 모든 쿠키를 반환합니다.<pre><code>let response = NextResponse.next()
// [
//   { name: &#39;experiments&#39;, value: &#39;new-pricing-page&#39;, Path: &#39;/home&#39; },
//   { name: &#39;experiments&#39;, value: &#39;winter-launch&#39;, Path: &#39;/home&#39; },
// ]
response.cookies.getAll(&#39;experiments&#39;)
// Alternatively, get all cookies for the response
response.cookies.getAll()</code></pre></li>
<li>delete(name) : 쿠키 이름이 주어진 경우, 해당 쿠키를 응답에서 삭제합니다.<pre><code>let response = NextResponse.next()
// Returns true for deleted, false is nothing is deleted
response.cookies.delete(&#39;experiments&#39;)</code></pre></li>
<li>json() : 주어진 JSON 데이터를 포함한 응답을 생성합니다.<pre><code>import { NextResponse } from &#39;next/server&#39;
</code></pre></li>
</ul>
<p>export async function GET(request: Request) {
  return NextResponse.json(
    { error: &#39;Internal Server Error&#39; }, { status: 500 }
  )
}</p>
<pre><code>- redirect() : URL을 생성하여 수정한 후 NextResponse.redirect() 메서드에서 사용할 수 있습니다. 예를 들어, request.nextUrl 속성을 사용하여 현재 URL을 가져와서 다른 URL로 리다이렉션할 수 있습니다.</code></pre><p>import { NextResponse } from &#39;next/server&#39;</p>
<p>return NextResponse.redirect(new URL(&#39;/new&#39;, request.url))</p>
<pre><code>- rewrite() : 제공된 URL을 유지하면서 다시 작성(프록시)하는 응답을 생성합니다.</code></pre><p>import { NextResponse } from &#39;next/server&#39;</p>
<p>// Incoming request: /about, browser shows /about
// Rewritten request: /proxy, browser shows /about
return NextResponse.rewrite(new URL(&#39;/proxy&#39;, request.url))</p>
<pre><code>- next() : 메서드를 사용하면 일찍 반환할 수 있고 라우팅을 계속할 수 있습니다. 미들웨어에 유용합니다.</code></pre><p>import { NextResponse } from &#39;next/server&#39;</p>
<p>return NextResponse.next()</p>
<pre><code>### Auth.js
[Auth.js API Reference](https://authjs.dev/reference/overview)
auth.js는 Next.js를 포함한 다양한 웹 프레임워크를 지원하며, 인증 관련 개발을 더욱 쉽고 다양하게 진행할 수 있게 도와줍니다. 예를 들어, 카카오, 네이버, 구글, 깃헙 등의 로그인을 손쉽게 구현할 수 있습니다.
![](https://velog.velcdn.com/images/korea-dollar/post/4a8015a9-f481-4bc4-960b-ac4f53efca75/image.png)
사진보다 더 많은 provider을 지원하여 쉽게 auth를 개발할 수 있습니다.
예시) 깃헙일 경우</code></pre><p>import NextAuth from &quot;next-auth&quot;;
import Github from &quot;next-auth/providers/github&quot;;
export const {
  handlers: { GET, POST },
  auth,
  signIn,
  signOut,
} = NextAuth({
  providers: [Github({ clientId: process.env.GITHUB_ID,
  clientSecret: process.env.GITHUB_SECRET })],
});</p>
<pre><code>login page</code></pre><p>import { signIn } from &quot;@/lib/auth&quot;;
import React from &quot;react&quot;;</p>
<p>const LoginPage = () =&gt; {
  const handleGithubLogin = async () =&gt; {
    &quot;use server&quot;;
    await signIn(&quot;github&quot;);
  };
  return (
    <div>
      <form action={handleGithubLogin}>
        <button>Login with Github</button>
      </form>
    </div>
  );
};</p>
<p>export default LoginPage;</p>
<pre><code>위에 코드로 구성하면 이제 우리가 깃헙으로 로그인하던 모습이 나타납니다.
![](https://velog.velcdn.com/images/korea-dollar/post/52a8f982-478e-4fb3-8cf0-067421777e65/image.png)

개발하실 때 주의사항은 async, await같은 경우 client가 아닌 server component에서 진행하는 것이 좋습니다.</code></pre><p>const Navbar = async () =&gt; {
  const session = await auth();</p>
<p>  return (
    <div className={styles.container}>
      <Link href="/" className={styles.logo}>
        GOGUMA
      </Link>
      <div>
        <Links session={session} />
      </div>
    </div>
  );
};</p>
<pre><code>
### Middleware
[Middleware](https://nextjs.org/docs/app/building-your-application/routing/middleware)
미들웨어를 사용하면 요청이 완료되기 전에 코드를 실행하여 다양한 작업을 수행할 수 있습니다. 이는 들어오는 요청에 따라 요청이나 응답 헤더를 재작성하고, 리디렉션을 수행하며, 요청을 수정하거나 직접 응답을 제공하여 응답을 조정할 수 있습니다. 구체적으로 다음과 같은 기능을 제공합니다:

- 인증 및 권한 부여: 특정 페이지나 API 경로에 접근하기 전에 사용자의 신원을 확인하고 세션 쿠키를 검사하여 적절한 권한을 부여합니다.
- 서버 측 리디렉션: 특정 조건에 따라 서버에서 사용자를 다른 경로로 리디렉션합니다.
- 경로 재작성: 요청 속성을 기반으로 API 경로나 페이지에 대한 경로를 동적으로 재작성하여 A/B 테스트, 기능 출시, 레거시 경로 지원 등을 구현할 수 있습니다.
- 로깅 및 분석: 요청을 페이지나 API에서 처리하기 전에 데이터를 캡처하고 분석하여 유용한 통찰을 얻습니다.
- 기능 플래그 지정: 기능을 동적으로 활성화하거나 비활성화하여 기능 출시나 테스트를 원활하게 수행합니다.

이러한 기능을 통해 미들웨어는 웹 애플리케이션의 유연성과 관리성을 크게 향상시킵니다.
![](https://velog.velcdn.com/images/korea-dollar/post/260c1524-a1a4-46e8-ae68-249c1d620f83/image.png)
middleware.js파일은 src 디렉토리 경로에 있어야 합니다.</code></pre><p>import NextAuth from &quot;next-auth&quot;;
import { authConfig } from &quot;./lib/auth.config&quot;;</p>
<p>export default NextAuth(authConfig).auth;</p>
<p>export const config = {
  matcher: [&quot;/((?!api|static|.<em>\..</em>|_next).*)&quot;],
};</p>
<pre><code>### useFormState
useFormState는 React Hook의 일환으로, 폼 관련 데이터 및 상태 관리에 주로 활용되며, 입력 필드의 값 관리나 유효성 검사에 있어 매우 유용하게 쓰입니다. 이를 통해 React 양식에서의 데이터 처리가 한층 더 간결하고 효율적으로 이루어집니다.

- **상태 관리의 간소화**: React Hook을 통해 폼 상태를 손쉽게 관리할 수 있어, 코드의 복잡성을 줄이고 개발 과정을 더욱 신속하게 진행할 수 있습니다.
- **강력한 유효성 검사 및 오류 처리 기능**: React Hook Form과 같은 라이브러리를 함께 사용함으로써, 정교한 유효성 검사와 오류 처리가 가능해져, 사용자 경험을 크게 향상시킬 수 있습니다.
- **성능 최적화의 이점**: React Hook을 활용함으로써, 필요한 경우에만 컴포넌트가 리렌더링되도록 하여 불필요한 리렌더링을 방지할 수 있으며, 이는 애플리케이션의 전반적인 성능 최적화에 기여합니다.

이러한 특징들 덕분에 useFormState는 React 기반의 웹 애플리케이션 개발 시 폼 관리를 위한 강력한 도구로 자리매김하고 있습니다.</code></pre><p>&quot;use client&quot;;</p>
<p>import { addPost } from &quot;@/lib/action&quot;;
import styles from &quot;./adminPostForm.module.css&quot;;
import { useFormState } from &quot;react-dom&quot;;</p>
<p>const AdminPostForm = ({ userId }) =&gt; {
  const [state, formAction] = useFormState(addPost, undefined);</p>
<p>  return (
    <form action={formAction} className={styles.container}>
      <h1>Add New Post</h1>
      <input type="hidden" name="userId" value={userId} />
      <input type="text" name="title" placeholder="Title" />
      <input type="text" name="slug" placeholder="slug" />
      <input type="text" name="img" placeholder="img" />
      <textarea type="text" name="desc" placeholder="desc" rows={10} />
      <button>Add</button>
      {state?.error}
    </form>
  );
};</p>
<p>export default AdminPostForm;</p>
<p>```
Next.js 14버전의 기본적인 사항을 학습하셨으니, 이제 GitHub에서 다양한 코드 예제를 살펴보며 자신만의 포트폴리오를 만들어 보세요. Next.js를 적용해 복습하고 실습하면서 더욱 깊이 있게 익혀보시기 바랍니다.
<a href="https://github.com/KoreaMoney/Nextjs-Beginners">Nextjs14버전 project github</a>
<a href="https://portfolio-next14-beginner.vercel.app/">next14로 제작된 portfolio project</a></p>
<blockquote>
<p>Error: <code>&#39;</code> can be escaped with <code>&amp;apos;</code>, <code>&amp;lsquo;</code>, <code>&amp;#39;</code>, <code>&amp;rsquo;</code>. react/no-unescaped-entities 에러</p>
</blockquote>
<p>next js 를 vercel에 빌드하려다 생긴 에러가 발생했습니다. 이런 이유를 error메세지를 확인 시 &#39;를 그대로 넣어서 발생하였다고 했습니다. 그래서 콤마보다는 html entities를 사용하여 에러를 해결하였습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[주니어 4명이 만든 성장과정]]></title>
            <link>https://velog.io/@korea-dollar/%EC%A3%BC%EB%8B%88%EC%96%B4-4%EB%AA%85%EC%9D%B4-%EB%A7%8C%EB%93%A0-%EC%84%B1%EC%9E%A5%EA%B3%BC%EC%A0%95</link>
            <guid>https://velog.io/@korea-dollar/%EC%A3%BC%EB%8B%88%EC%96%B4-4%EB%AA%85%EC%9D%B4-%EB%A7%8C%EB%93%A0-%EC%84%B1%EC%9E%A5%EA%B3%BC%EC%A0%95</guid>
            <pubDate>Fri, 24 May 2024 13:35:10 GMT</pubDate>
            <description><![CDATA[<p>송요창 개발자님이 추천해주신 “어느날 시니어가 사라졌다”라는 영상을 본 후 일주일 동안 깊은 깨달음을 얻었습니다. 프론트엔드 개발자들만으로 이루어진 팀에서 문화를 형성하며, 서로의 이야기를 나누고, 일과 후엔 스터디를 겸한 회고 시간을 디스코드에서 가졌습니다. 또한, 함께 코드 관련 규칙을 설정했습니다.</p>
<p>항상 &#39;시니어가 있는 회사에 취업하라&#39;는 말을 많이 들었습니다. 시니어 개발자가 계시면 그들만의 장점이 있고, 없다면 서로 지식을 공유하며 어려움을 함께 이겨내는 과정에서 성장할 수 있는 장점이 있다고 느꼈습니다.</p>
<p>코드 문제를 찾고 해결하는 과정이 단순한 문제해결력인지 의문을 가졌던 적이 있습니다. 하지만 프로젝트 미팅에 주니어로서 참여하며 문제를 정의하고 프로젝트의 의도를 파악하는 과정, 그리고 각자의 개발 환경을 구조화하는 작업 역시 문제해결력의 일환임을 깨달았습니다.</p>
<p>그리고 다른 팀에서 어떤 개발자가 어떤 개발을 하고 있는지 소통을 통해 매일 구성원들이 활동적으로 하고 있다라는 것을 보여주기도 하였습니다. </p>
<p>이러한 성장 과정을 통해 저는 더 나은 개발자로 성장하고 있음을 느끼게 되었습니다.
시니어 개발자가 없는 개발자분들께서 꼭 보셨으면 좋은 영상인것 같습니다!
<a href="https://youtu.be/1M2uCsfcIso?si=RiqbNhnlTNwHvFmi">https://youtu.be/1M2uCsfcIso?si=RiqbNhnlTNwHvFmi</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Next.js14 App Router 1편]]></title>
            <link>https://velog.io/@korea-dollar/Next.js14-App-Router</link>
            <guid>https://velog.io/@korea-dollar/Next.js14-App-Router</guid>
            <pubDate>Sat, 18 May 2024 15:53:13 GMT</pubDate>
            <description><![CDATA[<p><a href="https://github.com/KoreaMoney/Nextjs-Beginners">Github</a>
Next.js를 선택하는 것은 단순히 인기가 있기 때문만은 아닙니다. 프로젝트의 목표와 요구 사항에 맞춰 가장 적합한 기술을 선정하는 것이 중요합니다. Next.js, Vite, 혹은 다른 프레임워크를 사용할지 결정할 때, 프로젝트의 방향성과 필요성을 고려해야 합니다.</p>
<p>Next.js는 서버 사이드 렌더링(SSR)을 통해 초기 페이지 로딩 속도를 개선하고, 검색 엔진 최적화(SEO)에 유리한 점이 특징입니다. 또한, 자동 코드 분할, 최적화된 이미지 로딩, 정적 사이트 생성(Static Site Generation, SSG)과 같은 고급 기능을 제공합니다. 이러한 기능들은 웹 애플리케이션의 성능을 향상시키고, 개발자 경험을 개선할 수 있습니다.</p>
<p>반면, Vite는 빠른 콜드 스타트와 모듈 재구성 시간을 제공하는 현대적인 개발 서버로, HMR(Hot Module Replacement)을 통한 빠른 개발 경험을 제공합니다. 프로젝트가 큰 규모의 애플리케이션이 아니거나, SSR보다는 빠른 개발과 테스트를 중시하는 경우 Vite가 더 적합할 수 있습니다.</p>
<p>따라서, 프로젝트의 필요성에 따라 Next.js의 서버 사이드 렌더링과 SEO 친화적인 특성이 필요한지, 아니면 Vite의 빠른 개발 환경이 더 큰 장점으로 작용하는지 고려해야 합니다. 이 외에도 다른 프레임워크가 프로젝트의 요구 사항을 더 잘 충족시킬 수 있는지도 검토해야 합니다. 결국, 선택하는 기술은 프로젝트의 성공을 위해 가장 적합한 도구여야 합니다.</p>
<p><a href="https://nextjs.org/showcase">Next.js homepage</a>
Next.js홈페이지의 강조하는 문장</p>
<blockquote>
<p>Peerless performance, efficiency and developer experience. Next.js is trusted by some of the biggest names of the web.
뛰어난 성능, 효율성, 그리고 개발자 경험. Next.js는 웹의 가장 큰 이름들에 의해 신뢰받고 있습니다.</p>
</blockquote>
<p>Next.js를 설명하면 항상 나오는 단어가 있습니다. 바로 SSR입니다.
SSR(Server Side Rendering)이 어떤 장점이 있길래 다들 좋아하는 걸까? </p>
<blockquote>
<p>A powerful framework for building high-performance, server rendered web applications
고성능 서버 렌더링 웹 애플리케이션을 구축하기 위한 강력한 프레임워크입니다.</p>
</blockquote>
<p>위에서 본것과 같이 이전에는 Next.js는 Full-stack web applications를 강조했지만, 이제는 더 나아가 성능과 SSR이 뛰어나지 못해 강력하다는 것을 장점으로 내세우는 것을 볼 수 있습니다.
<img src="https://velog.velcdn.com/images/korea-dollar/post/0b6a5757-2691-40bf-9adc-5169a2b541a6/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/korea-dollar/post/7b7295af-ae5c-4513-b0e4-1d60da02fd3e/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/korea-dollar/post/6e9991a4-6699-47d3-93c7-b1a98f2d7c4e/image.png" alt="">
자료 출처 : <a href="https://www.smashingmagazine.com/2024/05/forensics-react-server-components/">https://www.smashingmagazine.com/2024/05/forensics-react-server-components/</a></p>
<h3 id="ssr">SSR</h3>
<p><strong>SSR</strong>은 client(browser)가 server에 매번 data를 요청하여 서버에서 처리하는 방식입니다. 클라이언트에서 요청이 들어올 때마다 매번 서버에서 새로운 화면을 만들어 제공합니다. 다시말해, server가 화면을 그리는 주체가 되는 것 입니다.</p>
<ul>
<li>SSR
<img src="https://velog.velcdn.com/images/korea-dollar/post/65146306-444b-40a5-885c-c3e0af8a9ba8/image.png" alt=""></li>
<li>CSR
<img src="https://velog.velcdn.com/images/korea-dollar/post/d90afa3e-513a-41b6-a0b9-3a9cd4e25ee6/image.png" alt="">
SSR(Server Side Rendering)은 웹 애플리케이션에서 중요한 역할을 하는 기술로, 여러 가지 장점 때문에 많은 개발자들이 선호합니다. 아래는 SSR의 주요 장점들입니다:</li>
</ul>
<ol>
<li><p><strong>향상된 초기 로딩 속도</strong>: SSR을 사용하면 서버에서 미리 페이지를 렌더링하여 클라이언트로 전송합니다. 이로 인해 사용자는 데이터를 기다릴 필요 없이 거의 즉시 페이지를 볼 수 있습니다. 이는 특히 초기 페이지 로딩 시간이 중요한 웹 애플리케이션에 있어 큰 이점으로 작용합니다.</p>
</li>
<li><p><strong>검색 엔진 최적화(SEO) 개선</strong>: 서버 사이드 렌더링을 통해 생성된 페이지는 검색 엔진이 더 쉽게 크롤링하고 인덱싱할 수 있습니다. 이는 웹사이트의 검색 엔진 결과 페이지(SERP) 순위를 높일 수 있으며, 특히 동적인 데이터를 많이 사용하는 웹 애플리케이션에 있어서 중요합니다.</p>
</li>
<li><p><strong>소셜 미디어 최적화</strong>: SSR을 사용하면 소셜 미디어 플랫폼이 웹 페이지의 메타 데이터(예: 제목, 설명, 이미지 등)를 더 잘 읽을 수 있어, 공유될 때 보다 매력적인 미리보기를 생성할 수 있습니다. 이는 사용자 참여를 증가시키고 웹사이트 트래픽을 늘리는 데 도움이 됩니다.</p>
</li>
<li><p><strong>향상된 사용자 경험</strong>: SSR을 통해 빠른 페이지 로딩을 제공함으로써 사용자 경험이 향상됩니다. 사용자는 빠른 상호작용을 경험하게 되며, 이는 특히 모바일 사용자에게 중요합니다. 또한, SSR은 네트워크 연결이 불안정한 환경에서도 더 나은 성능을 제공할 수 있습니다.</p>
</li>
</ol>
<p>Next.js는 이러한 SSR의 장점들을 쉽게 활용할 수 있게 해주는 프레임워크입니다. 서버 사이드 렌더링 외에도, Next.js는 정적 사이트 생성(Static Site Generation, SSG)과 클라이언트 사이드 렌더링(Client Side Rendering, CSR)을 지원하여, 개발자가 애플리케이션의 요구사항에 맞춰 최적의 렌더링 전략을 선택할 수 있도록 합니다. 이러한 유연성과 SSR의 장점을 결합한 것이 Next.js를 매우 인기 있는 선택으로 만들고 있습니다.</p>
<p>서버가 화면을 그리는 구조는 몇 가지 중요한 장점을 제공합니다. 첫째로, 첫 페이지 로딩 속도가 클라이언트 측 렌더링(CSR)에 비해 상당히 빠릅니다. 이는 CSR에서는 첫 페이지에 해당하는 문서만 브라우저로 전송되고, 브라우저가 렌더링을 담당하기 때문에 초기 로딩이 느린 반면, 서버 측 렌더링(SSR)에서는 서버가 화면을 미리 그려 전달하기 때문에 사용자가 보다 신속히 화면을 볼 수 있습니다. 둘째로, 검색 엔진 최적화(SEO) 측면에서 더 우수합니다. 이는 검색 엔진이 콘텐츠를 더 잘 이해하고 인덱싱할 수 있게 해줍니다.</p>
<p>하지만 SSR이 가진 장점만큼 단점도 존재합니다. 서버에서 화면을 그리고 전달하는 구조는 초기 로딩 이후 페이지 이동 시 속도가 다소 느릴 수 있습니다. CSR에서는 이미 클라이언트에 필요한 데이터를 렌더링해 둔 상태에서 페이지 이동이 발생할 경우, 새로운 데이터만 갈아끼우는 방식이지만, SSR에서는 서버로부터 응답을 받고 그 내용을 렌더링하는 과정이 필요하기 때문에 시간이 더 소요됩니다.</p>
<p>이러한 SSR의 단점을 극복하기 위해 Next.js는 &#39;Hydration&#39;이라는 개념을 도입했습니다. 간단히 말해, SSR과 CSR의 장점을 결합하여 사용자에게 더 나은 경험을 제공하는 것입니다. 이를 통해 SSR로 빠른 첫 페이지 로딩을 제공한 이후, 페이지 내에서의 이동은 CSR 방식으로 처리하여 사용자 인터페이스의 반응성을 높입니다.</p>
<p>Next.js를 학습하는 이유를 간략히 설명드렸습니다. 또한, Next.js 14버전의 앱 라우터 방식을 쉽게 이해할 수 있도록 도식화한 이미지도 함께 첨부했으니 참고하시길 바랍니다.</p>
<h3 id="folder-structure">Folder structure</h3>
<p><img src="https://velog.velcdn.com/images/korea-dollar/post/df3f8887-cfe5-44de-9f54-157f7860ed6f/image.png" alt="">
위 사진을 보며 하나씩 보겠습니다.
src에 있는 App아래에 모든 page들이 구성되어 있습니다. page로 구성하고 싶은 것들은 모두 Folder을 생성하고 그 안에 page.js를 생성한다라는 것을 볼 수 있습니다.</p>
<p><strong>app router</strong>은 page router와 다르게 folder를 기준으로 합니다. 그렇기 때문에 page로 구성하고 싶은 것들은 folder을 page이름으로 정하고 그 안에 page.js라는 입력합니다. 
그리고 page &gt; children page을 구현하고 싶다면 main page의 folder안에 다시 folder을 생성하고 children page인 page.js를 넣습니다.
<img src="https://velog.velcdn.com/images/korea-dollar/post/1f49f609-7e37-496b-8bda-c042e0489ab6/image.png" alt=""></p>
<p>blog page의 children을 보면 다른 folder와 다르게 [ ] 대괄호을 표시한 것을 볼 수 있습니다.
<img src="https://velog.velcdn.com/images/korea-dollar/post/2454f019-d268-48be-869e-505bf5ea6beb/image.png" alt="">
Next.js에서 동적 라우팅을 구현할 때, 대괄호([ ])를 사용하는 것은 동적 페이지 경로를 정의하기 위함입니다. 예를 들어, 블로그에서 [slug]로 지정된 폴더에는 다양한 포스트가 있을 수 있고, <a href="http://localhost:3000/blog/post1">http://localhost:3000/blog/post1</a> 같은 URL을 통해 접근할 때 [slug]에 해당하는 post1이라는 값을 가진 페이지로 라우팅됩니다.</p>
<p>또한, Next.js에서는 소괄호(( ))를 사용하는 것에 대해서도 알게 되었습니다. 소괄호는 특정 폴더로의 직접적인 라우팅을 방지하는 용도로 사용됩니다. 소괄호로 묶인 폴더는 그 자체로는 라우팅 대상이 되지 않지만, 그 내부의 하위 폴더나 파일에는 접근할 수 있으므로, 그룹화를 위한 용도로 적합합니다. 이 구조를 사용하면, 소괄호로 묶인 폴더의 이름을 pathname으로 직접 추가하려고 할 때 404 에러가 발생하게 됩니다. 이러한 방식으로, 더 세밀한 라우팅 제어와 구조화된 폴더 관리를 할 수 있게 됩니다.
<img src="https://velog.velcdn.com/images/korea-dollar/post/f616ee5c-6d6c-4e9e-8884-726c61071131/image.png" alt="">
<img src="https://velog.velcdn.com/images/korea-dollar/post/183db745-bc7a-4a0b-be7d-d8a4de4c8b26/image.png" alt=""></p>
<h3 id="layout">layout</h3>
<p>예시에서 언급한 것처럼, layout.js 파일의 기능을 통해 어떤 페이지는 &quot;This is the Main Layout&quot;을 보여주고, 다른 페이지는 &quot;This is the Blog Layout&quot;과 같이 다른 내용을 보여주는 것을 확인할 수 있습니다. 이는 layout.js가 앱의 메인 레이아웃을 정의하고, 그 안에 children 프로퍼티를 통해 각 페이지의 컨텐츠를 동적으로 렌더링하기 때문입니다. 따라서 모든 페이지가 메인 레이아웃을 공유하면서도, 특정 페이지에서는 추가적으로 다른 레이아웃을 보여줄 수 있게 됩니다.</p>
<p>이렇게 메인 레이아웃을 설정함으로써, 페이지 전체에 걸쳐 일관된 디자인과 구조를 유지할 수 있으며, 특정 페이지나 섹션에 대해 다른 레이아웃을 적용하고 싶을 때 유연하게 대응할 수 있습니다. 예를 들어, 블로그 페이지에서만 특별한 사이드바나 추가적인 요소를 포함하는 블로그 레이아웃을 적용할 수 있습니다.</p>
<pre><code>export default function RootLayout({ children }) {
  return (
    &lt;html lang=&quot;en&quot;&gt;
      &lt;body className={inter.className}&gt;
        &lt;h1&gt;This is the Main Layout&lt;/h1&gt;
        {children}
      &lt;/body&gt;
    &lt;/html&gt;
  );
}</code></pre><p><img src="https://velog.velcdn.com/images/korea-dollar/post/79ea670d-90f6-4e38-9053-b36357124d59/image.png" alt="">
경우에 따라 해당 page에서 children에게 보여줘야할 layout이 존재 할 수 있습니다. 그럴 경우에는 해당 folder안에 layout.js를 작성하여 해주고 children을 작성해주면 해당 folder의 children은 위 사진과 같이 &quot;This is the Blog Layout&quot;을 볼 수 있습니다.</p>
<pre><code>const BlogLayout = ({ children }) =&gt; {
  return (
    &lt;div&gt;
      &lt;h2&gt;This is the Blog Layout&lt;/h2&gt;
      {children}
    &lt;/div&gt;
  );
};
export default BlogLayout;</code></pre><p>비슷한 기능을 하지만 re-rendering(또는 re-mounting)이 필요한 경우에는 template.js를 사용하는 것이 좋습니다. 기본적으로 layout.js는 re-rendering을 하지 않습니다. 그러나 template.js를 사용하면 리마운팅을 할 수 있습니다. 레이아웃 기능을 유지하면서 페이지를 이동할 때마다 리마운팅이 필요할 경우 유용합니다. 예를 들어, 페이지 이동 시 구글 애널리틱스와 같은 기록이 필요한 경우에 사용됩니다.
<img src="https://velog.velcdn.com/images/korea-dollar/post/4234feb3-12d9-4931-be4a-ba7e3f933538/image.png" alt="">
개발을 진행할 때, 컴포넌트와 라이브러리는 app 폴더가 아닌 src 폴더에 넣는 것을 추천합니다. app 폴더 안에는 오직 페이지와 스타일만을 구성하고, 그 외의 모든 것들은 src에서 관리하는 것을 권장하고 있기 때문입니다. 이렇게 하면 프로젝트 구조가 더 깔끔해지고, 관리하기도 쉬워집니다.
<a href="https://nextjs.org/learn/dashboard-app">Next.js learn</a></p>
<h3 id="error-component">error component</h3>
<p><img src="https://velog.velcdn.com/images/korea-dollar/post/aff21732-25a4-4919-a0fe-409a9bdfbcc7/image.png" alt="">
React Router DOM에서 자주 사용되던 ErrorComponent와 유사한 기능이 Next.js에서는 더욱 단순화되어 제공됩니다. Next.js에서는 앱 폴더 내에 error.js 파일을 만들어주기만 하면, 앱의 메인 페이지에서 오류가 발생할 경우 자동으로 해당 에러 컴포넌트로 연결하여 오류를 표시해 줍니다. error.js 파일을 사용할 때에는 &quot;use client&quot; 지시어를 반드시 포함시켜주어야 합니다. 이렇게 하면 클라이언트 측에서 오류 처리를 효율적으로 관리할 수 있습니다.
<img src="https://velog.velcdn.com/images/korea-dollar/post/0fb2b7f4-c013-4e14-b147-e27f2947cd10/image.png" alt=""></p>
<pre><code>&quot;use client&quot;;

const Error = () =&gt; {
  return &lt;div&gt;⚠️Error⚠️&lt;/div&gt;;
};
export default Error;</code></pre><p><img src="https://velog.velcdn.com/images/korea-dollar/post/75b56fc9-c514-485c-9f47-ee87d5337c6b/image.png" alt="">
에러 컴포넌트가 에러를 확인하고 layout.js를 구성한 후 페이지를 호출하는 것이 아니라, 에러 컴포넌트 자체를 호출하는 과정을 확인할 수 있습니다.</p>
<h3 id="use-client">use client</h3>
<p>에러 컴포넌트에서 등장하는 &quot;use client&quot;에 대해 알아보겠습니다.
<img src="https://velog.velcdn.com/images/korea-dollar/post/1e4a7dc2-39ae-4922-ade9-593e6400558f/image.png" alt=""></p>
<blockquote>
<p>Using Client Components in Next.js
To use Client Components, you can add the React &quot;use client&quot; directive at the top of a file, above your imports.
&quot;use client&quot; is used to declare a boundary between a Server and Client Component modules. This means that by defining a &quot;use client&quot; in a file, all other modules imported into it, including child components, are considered part of the client bundle. - Next.js Doc <a href="https://nextjs.org/docs/app/building-your-application/rendering/client-components">Client rendering</a></p>
</blockquote>
<p>&quot;use client&quot;는 서버와 클라이언트 컴포넌트 모듈 간의 경계를 선언하는 데 사용됩니다. 이는 &quot;use client&quot;를 파일에 정의함으로써, 그 파일로 가져오는 모든 다른 모듈들, 자식 컴포넌트들을 포함하여, 모두 클라이언트 번들의 일부로 간주된다는 의미입니다.</p>
<p>Next.js의 공식 문서를 살펴보면, 클라이언트 렌더링의 장점을 활용한다는 것을 알 수 있습니다. React 훅을 사용하거나 이벤트와 같은 React의 문법을 사용하기 위해 &quot;use client&quot;를 작성하여 서버와 클라이언트 컴포넌트를 명확히 구분하고 있다는 점이 확인됩니다.</p>
<p>&quot;<strong>Use client</strong>&quot;는 클라이언트 사이드 렌더링(CSR) 또는 하이드레이션을 의미하는 용어일 수 있습니다. 이는 서버 사이드에서 렌더링된 페이지가 클라이언트(브라우저)로 전송된 후, 페이지의 일부 또는 전체가 클라이언트 사이드에서 다시 렌더링되거나 업데이트되는 과정을 가리킵니다. 특히, 에러 처리 시나리오에서 &quot;use client&quot; 접근 방식을 사용하면, 서버 사이드에서 발생한 에러를 클라이언트 사이드에서 적절히 처리하고 사용자에게 보다 친절한 피드백을 제공할 수 있습니다.</p>
<p>예를 들어, 에러 컴포넌트를 사용하여 서버에서 발생한 에러를 감지한 후, 이를 클라이언트 사이드에서 처리하여 사용자에게 에러 메시지를 보여주거나, 사용자가 다시 시도할 수 있는 옵션을 제공하는 등의 방식으로 활용할 수 있습니다. 이렇게 함으로써, 사용자 경험을 향상시키고 애플리케이션의 안정성을 높일 수 있습니다.</p>
<p>결론적으로, &quot;use client&quot;는 에러 상황에서 클라이언트 사이드의 처리를 강조하는 접근 방식을 의미하며, 이를 통해 보다 유연하고 사용자 친화적인 에러 처리가 가능해집니다.</p>
<h3 id="not-found">not-found</h3>
<p>URL 경로에 존재하지 않는 페이지로 이동할 경우, NotFound 페이지를 보여주는 것은 사용자 경험을 향상시키는 중요한 방법 중 하나입니다. Next.js는 이러한 NotFound 페이지를 보다 간편하게 구현할 수 있도록 지원합니다.</p>
<p>app경로 내에 not-found.js 파일을 생성하여 설정하면, Next.js는 자동으로 해당 파일을 애플리케이션의 기본 NotFound 페이지로 인식하고 사용합니다
<img src="https://velog.velcdn.com/images/korea-dollar/post/87ca2480-0404-4065-bf70-a0dc867fe07c/image.png" alt="">
<img src="https://velog.velcdn.com/images/korea-dollar/post/edbb9770-420e-4c33-9ef8-f0429c306f0b/image.png" alt=""></p>
<h3 id="loading">loading</h3>
<p>이와 마찬가지로 위 사진을 보면 app경로안에 loading.jsx가 있습니다. Next.js에서는 앱의 로딩 경험을 개선하기 위해 매우 간단하고 효과적인 방법을 제공합니다. 특히, app 경로 내에 loading.jsx 파일을 추가함으로써, 개발자들은 사용자에게 보다 매끄러운 페이지 전환 시의 로딩 경험을 제공할 수 있습니다. Next.js는 이러한 접근 방식을 통해 개발자가 로딩 페이지를 쉽게 구성하고 관리할 수 있도록 지원합니다.</p>
<blockquote>
<p>Error: 
  × You&#39;re importing a component that needs usePathname. It only works in a Client Component but none of its parents are marked with &quot;<strong>use client</strong>&quot;, so they&#39;re Server Components by default.</p>
</blockquote>
<p>추가적으로 개발 중에 위와 같은 <strong>에러</strong>를 발견하시면, 이는 &#39;use client&#39;를 의미합니다. 즉, 서버 컴포넌트가 아닌 클라이언트 컴포넌트를 변경해야 사용할 수 있다는 것을 알려줍니다.</p>
<h3 id="routes-type">Routes Type</h3>
<p><img src="https://velog.velcdn.com/images/korea-dollar/post/2a084335-06d9-45bc-bc7d-eddfd956fadb/image.png" alt=""></p>
<blockquote>
<p><strong>패러렐 라우팅</strong>은 두 개의 페이지를 동시에 표시하고자 할 때 활용됩니다. 이 기법을 통해 모달 같은 UI 요소도 구현할 수 있습니다.
예를 들어, A 페이지와 B 페이지를 동시에 보여주고 싶다면, A 페이지의 layout.tsx 파일에 두 번째 속성(첫 번째 속성은 children)을 추가하여 원하는 위치에 배치해야 합니다. 그리고 B 페이지의 폴더 이름은 @로 시작해야 합니다. 중요한 점은, A 페이지와 B 페이지의 폴더가 같은 위치에 있어야 한다는 것입니다.</p>
</blockquote>
<p>패러렐 라우팅을 활용할 때, &#39;@&#39; 폴더 내에 기본적으로 표시할 내용이 없는 경우, &#39;page.tsx&#39; 대신 &#39;default.tsx&#39;를 사용할 수 있습니다. &#39;page.tsx&#39;를 사용하는 것도 가능하지만, 특별히 표시할 내용이 없을 경우 &#39;default.tsx&#39;에서 null을 반환하도록 설정하는 것이 좋습니다.</p>
<blockquote>
<p><strong>인터셉팅 라우트</strong>는 폴더 이름 앞에 소괄호(), 마침표., 그리고 마침표 두 개..를 사용합니다. 이는 실제 폴더 구조와는 관계없이, 브라우저의 주소를 기준으로 합니다(라우팅 그룹()이나 병렬 라우팅@ 등은 고려하지 않음). 현재 폴더 또는 상위 폴더 내에서 같은 이름의 폴더를 찾아 대체하는 방식으로 작동합니다.</p>
</blockquote>
<h3 id="nextimage">next/image</h3>
<p>Next.js에서 사용할 파일들은 public폴더에 넣어주고 시작하면 됩니다.</p>
<blockquote>
<p>The Next.js Image component extends the HTML &quot;img&quot;element with features for automatic image optimization.
Size Optimization: Automatically serve correctly sized images for each device, using modern image formats like WebP and AVIF.
Visual Stability: Prevent layout shift automatically when images are loading.
Faster Page Loads: Images are only loaded when they enter the viewport using native browser lazy loading, with optional blur-up placeholders.
Asset Flexibility: On-demand image resizing, even for images stored on remote servers</p>
</blockquote>
<p>Next.js의 Image 컴포넌트는 자동 이미지 최적화 기능을 포함하여 HTML img 요소를 확장합니다:</p>
<ul>
<li><strong>크기 최적화</strong>: 현대적인 이미지 형식인 WebP와 AVIF를 사용하여 각 장치에 맞는 크기의 이미지를 자동으로 제공합니다.</li>
<li><strong>시각적 안정성</strong>: 이미지가 로딩될 때 레이아웃 이동을 자동으로 방지합니다.</li>
<li><strong>더 빠른 페이지 로딩</strong>: 네이티브 브라우저의 게으른 로딩을 사용하여 이미지가 뷰포트에 들어올 때만 이미지를 로드하며, 선택적으로 흐릿한 플레이스홀더를 사용할 수 있습니다.</li>
<li><strong>자산 유연성</strong>: 원격 서버에 저장된 이미지까지도, 요청 시 이미지 크기를 조정할 수 있습니다.</li>
</ul>
<p>Next.js에서는 next/image 컴포넌트를 통해 웹상에서 사용되는 이미지들을 최적화하고 안정성을 제공합니다. 반면, 기본 HTML img 태그를 사용할 경우, Lighthouse 검사 결과에서 볼 수 있듯이 Largest Contentful Paint(LCP)에 부정적인 영향을 미치며, 이는 곧 웹사이트의 퍼포먼스 문제로 이어질 수 있습니다.
<img src="https://velog.velcdn.com/images/korea-dollar/post/85fb3b08-a196-40ce-89c6-10d02a313b56/image.png" alt="">
Next.js의 next/image 컴포넌트를 사용할 때 &quot;serve images in next-gen formats&quot; 경고가 나타나지 않는 이유는, 이 기능이 차세대 이미지 형식을 지원하기 때문입니다. 차세대 이미지 형식이란 JPEG나 PNG와 같은 전통적인 이미지 형식보다 압축 효율이 뛰어나고 품질을 더 잘 유지하면서 웹 페이지의 로딩 속도를 향상시키는 현대적인 이미지 형식을 의미합니다. next/image는 바로 이러한 최신 이미지 형식으로의 최적화를 자동으로 처리해주기 때문에 해당 경고가 발생하지 않는 것입니다.</p>
<h2 id="navigation">Navigation</h2>
<h3 id="nextlink">next/link</h3>
<pre><code>import Link from &quot;next/link&quot;;

const Links = () =&gt; {
  const links = [];
  return (
    &lt;div&gt;
      {links.map((link) =&gt; (
        &lt;Link key={link.title} href={link.path} prefetch={false}&gt;
          {link.title}
        &lt;/Link&gt;
      ))}
    &lt;/div&gt;
  );
};
export default Links;</code></pre><p><a href="https://nextjs.org/learn/dashboard-app/navigating-between-pages">Next.js learn Linkpart</a>, <a href="https://nextjs.org/docs/app/api-reference/components/link">Next.js Doc</a>
Next.js에서는 우리가 사용하던 react-router-dom에서의 Link비슷한 기능을 하는 <strong>next/link</strong>가 있습니다. </p>
<blockquote>
<p>Save your changes and check to see if it works in your localhost. You should now be able to navigate between the pages without seeing a full refresh.
변경 사항을 저장하고 로컬호스트에서 작동하는지 확인하세요. 이제 전체 새로 고침 없이 페이지 간 이동이 가능할 것입니다. - Next.js learn</p>
</blockquote>
<p>Next.js의 next/link를 활용하면 별도의 라이브러리 없이도 페이지 라우팅을 손쉽게 할 수 있습니다. 이는 페이지를 새로 고침하지 않고도 이동이 가능하게 하여 사용자 경험을 한층 더 향상시킵니다.</p>
<p>next/link는 다양한 옵션을 제공하는데, 그 중 prefetch옵션이 있습니다. prefetch는 데이터를 사전에 백그라운드에서 불러와 로딩할 수 있게 해줍니다. 따라서, 이를 true로 설정하면 정적 및 동적 경로에 대한 전체 경로를 사전에 가져와, 페이지에 방문할 때 보다 빠르게 접근할 수 있습니다.</p>
<p>또 다른 옵션으로는 replace가 있습니다. 이는 새로운 URL을 라우터 히스토리 스택에 추가하지 않고, 현재 페이지의 경로를 새로운 URL로 대체합니다.</p>
<p>예를 들어, 홈에서 로그인 페이지를 거쳐 아이템 페이지로 이동한 후, router.replace를 사용하여 &#39;마이페이지&#39;로 이동한다면, 라우터 히스토리 스택에서 현재 페이지인 아이템이 마이페이지로 대체됩니다. 결과적으로, 히스토리 스택은 홈 &gt; 로그인 &gt; 마이페이지로 기록됩니다. 이 경우 마지막 페이지에서 뒤로 가기를 누르면 로그인 페이지로 돌아갑니다.</p>
<p>이러한 기능들을 통해 Next.js는 사용자와 개발자 모두에게 효율적이고 쾌적한 웹 경험을 제공합니다.</p>
<h3 id="userouter">useRouter</h3>
<pre><code>&#39;use client&#39;

import { useRouter } from &#39;next/navigation&#39;

export default function Page() {
  const router = useRouter()
  return (
    &lt;button type=&quot;button&quot; onClick={() =&gt; router.push(&#39;/dashboard&#39;)}&gt;
      Dashboard
    &lt;/button&gt;
  )
}</code></pre><p><strong>useRouter</strong>은 경로를 지정하고 이를 관리하는 데 유용한 기능을 제공합니다. 이 훅을 통해 다양한 탐색 및 라우팅 작업을 수행할 수 있습니다.
<strong>router.push(href: string)</strong>: 제공된 경로로 클라이언트 측 탐색을 수행하며, 브라우저 기록에 새 항목을 추가합니다.
<strong>router.replace(href: string)</strong>: 브라우저의 기록 스택에 새 항목을 추가하지 않고, 제공된 경로로 클라이언트 측 탐색을 수행합니다.
<strong>router.refresh()</strong>: 현재 경로를 새로 고쳐 서버에 새 요청을 보내고, 데이터를 다시 가져오며, 서버 구성 요소를 다시 렌더링합니다. 이 과정에서 클라이언트 측 React 상태(예: useState)나 브라우저 상태(예: 스크롤 위치)는 유지되며, 업데이트된 React 서버 구성 요소 페이로드만 병합됩니다.
<strong>router.prefetch(href: string)</strong>: 제공된 경로를 미리 가져와 더 빠른 클라이언트 측 전환을 가능하게 합니다.
<strong>router.back()</strong>: 브라우저의 기록 스택에서 이전 경로로 이동합니다.
<strong>router.forward()</strong>: 브라우저 기록 스택의 다음 페이지로 이동합니다.
useRouter 훅을 통해 Next.js는 보다 유연하고 강력한 라우팅 기능을 제공하여, 개발자와 사용자가 모두 만족할 수 있는 웹 애플리케이션을 구축할 수 있습니다.</p>
<h3 id="useparams">useParams</h3>
<pre><code>&#39;use client&#39;

import { useParams } from &#39;next/navigation&#39;

export default function ExampleClientComponent() {
  const params = useParams()
  return &lt;&gt;&lt;/&gt;
}</code></pre><p><strong>useParams</strong>는 현재 경로의 동적 매개변수들을 포함하는 객체를 반환하는 훅입니다. 이를 통해, 경로에 포함된 변수 값을 쉽게 추출하고 활용할 수 있습니다. 예를 들어, /app/shop/[tag]/[item]이라는 경로가 있고 실제 URL이 /shop/1/2라고 가정할 때, useParams를 사용하면 { tag: &#39;1&#39;, item: &#39;2&#39; }라는 객체를 얻을 수 있습니다. 이를 통해, 경로에서 설정한 id 값이나 [slug]와 같은 동적 매개변수들을 효율적으로 가져와 사용할 수 있습니다.</p>
<p>이런 방식으로 useParams를 활용하면, 웹 애플리케이션에서 동적 경로를 통해 다양한 데이터를 표현하고 관리하는 것이 한층 더 용이해집니다.</p>
<h3 id="usepathname">usePathname</h3>
<pre><code>&#39;use client&#39;

import { usePathname } from &#39;next/navigation&#39;

export default function ExampleClientComponent() {
  const pathname = usePathname()
  return &lt;p&gt;Current pathname: {pathname}&lt;/p&gt;
}</code></pre><p><strong>usePathname</strong>은 현재 URL의 경로명만을 반환하는 훅입니다. 이는 useParams와 달리 동적 매개변수나 [slug] 값을 포함하지 않습니다. 예를 들어, 만약 현재 URL이 /dashboard?page=2라면, usePathname을 통해 얻을 수 있는 값은 /dashboard가 됩니다.</p>
<p>이 훅을 사용함으로써, 쿼리 파라미터나 해시 값 등의 추가적인 URL 구성 요소 없이, 순수하게 경로명만을 추출해낼 수 있습니다.</p>
<h3 id="usesearchparams">useSearchParams</h3>
<pre><code>&#39;use client&#39;

import { useSearchParams } from &#39;next/navigation&#39;

export default function SearchBar() {
  const searchParams = useSearchParams()

  const search = searchParams.get(&#39;search&#39;)
  return &lt;&gt;Search: {search}&lt;/&gt;
}</code></pre><p><strong>useSearchParams</strong>는 현재 URL의 쿼리 스트링(&quot;search&quot; 부분)에서 원하는 값을 쉽게 추출할 수 있는 훅입니다. 예를 들어 URL이 &quot;/dashboard?search=my-project&quot;일 경우, 이 훅을 사용하여 &#39;search&#39;의 값을 &quot;my-project&quot;로 쉽게 얻을 수 있습니다. 이를 통해 웹 애플리케이션에서 사용자의 검색 요청과 같은 쿼리 스트링 기반의 데이터를 효율적으로 관리하고 활용할 수 있습니다.</p>
<h3 id="page-params">page params</h3>
<pre><code>const SinglePostPage = ({ params }) =&gt; {
  console.log(&quot;params를 찾습니다.&quot;, params);
  return &lt;&gt;&lt;/&gt;
}</code></pre><p><img src="https://velog.velcdn.com/images/korea-dollar/post/dfe96b25-fd86-403f-b075-a37a0a06c64e/image.png" alt="">
[slug]를 포함하는 페이지에서도 현재 경로의 동적 매개변수를 파악할 수 있습니다. 예를 들어, URL 경로가 /articles/[slug]와 같이 설정되어 있고, 실제 방문한 페이지의 URL이 /articles/react-hooks-introduction이라면, { slug: &#39;react-hooks-introduction&#39; }와 같이 현재 경로의 동적 매개변수 값을 얻을 수 있습니다. 이렇게 하면 페이지 내에서 동적으로 변하는 경로 값을 효과적으로 활용할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React.createElement & JSX]]></title>
            <link>https://velog.io/@korea-dollar/React.createElement</link>
            <guid>https://velog.io/@korea-dollar/React.createElement</guid>
            <pubDate>Wed, 15 May 2024 10:06:25 GMT</pubDate>
            <description><![CDATA[<h3 id="우리가-자주보는-indexjs에서-존재하는-reactcreateelement는-무엇일까">우리가 자주보는 index.js에서 존재하는 React.createElement()는 무엇일까?</h3>
<p>createElement를 사용하면 React 엘리먼트를 생성할 수 있다.
즉, 리액트 컴포넌트는 React.createElement를 통해 element에 대한 정보를 가지는 Object를 생성하고 이를 In-Memory에 저장하고 ReactDOM.render 함수를 통해 Web API(document.createElement)를 이용해서 실제 웹 브라우저에 그려주는 방식으로 동작한다.</p>
<p>JSX -&gt; React element -&gt; fiber(VDOM에 올라가기 위해 필요한 정보를 포함하는 노드같은 존재)
babel을 통해 JSX -&gt; React element
createElement(type, config, child1, child2, .... childN)</p>
<h4 id="type는-3가지가-있다">type는 3가지가 있다.</h4>
<ul>
<li>host(browser) componet : HTML element이름</li>
<li>custom componet : 새로 만들어 작성한 함수</li>
<li>static component : 미리 정의된 Symbol 또는 memo, lazy와 같이 함수 호출로 return한 React element</li>
</ul>
<p>config에는 props가 있고 props는 ref, key etc...
children : 중심 component의 자식 component들</p>
<h4 id="react-element만드는-과정createelement함수-들여다보기">React element만드는 과정(createElement함수 들여다보기)</h4>
<p>React element에는 key와 ref라는 예약된 props가 있다. 
이를 제외한 나머지를 props객체에 저장한다.
여러 자식이 오면 배열에 저장한다.
default props가 존재하면 props객체에 적용된다.
이런 과정을 거쳐 React element객체가 생성된다.
<img src="https://velog.velcdn.com/images/korea-dollar/post/a9cb5f72-a09e-43b0-8449-9e0bd63a1bcc/image.png" alt=""></p>
<p>JSX를 사용하지 않고 순수하게 react element만 사용할 경우의 code는 다음과 같다.</p>
<pre><code>import { createElement } from &#39;react&#39;;

function Greeting({ name }) {
  return createElement(
    &#39;h1&#39;,
    { className: &#39;greeting&#39; },
    &#39;Hello &#39;,
    createElement(&#39;i&#39;, null, name),
    &#39;. Welcome!&#39;
  );
}

export default function App() {
  return createElement(
    Greeting,
    { name: &#39;DOWON&#39; }
  );
}
</code></pre><p>결과는 Hello Taylor. Welcome! 다음과 같다.
그럼 여기에서 궁금한 점은 JSX처럼 사용할 경우 Code는 어떻게 변경되는가?</p>
<pre><code>function Greeting({ name }) {
  return (
    &lt;h1 className=&quot;greeting&quot;&gt;
      Hello &lt;i&gt;{name}&lt;/i&gt;. Welcome!
    &lt;/h1&gt;
  );
}

export default function App() {
  return &lt;Greeting name=&quot;DOWON&quot; /&gt;;
}
</code></pre><p>이렇게 된다. Code가 짧아지고 보기가 더 편해진다. 그래서 우리는 평소 개발할때 JSX를 사용하여 진행하게 된다.</p>
<h4 id="여기에서-jsx은-무엇일까">여기에서 JSX은 무엇일까?</h4>
<ul>
<li>JSX(Javascript Syntax eXtension)는 Javascript 확장한 문법이다.</li>
<li>JSX는 리액트로 프로젝트를 개발할 때 사용되므로 공식적인 자바스크립트 문법은 아니기 때문에 브라우저에서 실행하기 전에 바벨을 사용하여 일반 자바스크립트 형태의 코드로 변환된다.</li>
<li>JSX를 html이 아니다. </li>
<li>대문자로 시작하는 JSX 태그: 사용자 정의 컴포넌트 </li>
<li>소문자로 시작하는 JSX 태그: 내장 컴포넌트</li>
<li>JSX를 사용하면 UI 구조를 더 직관적으로 설계할 수 있고, JavaScript 표현식을 HTML 코드 안에 포함시킬 수 있어 코드를 간결하게 만들 수 있다.</li>
<li>결론적으로 우리는 JSX를 사용함으로서 가독성과 컴파일 시 오류 검출을 빠르게하여 쉽게 코드를 작성할 수 있게 된다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[React useState분석 (Linked list)]]></title>
            <link>https://velog.io/@korea-dollar/React-useState%EB%B6%84%EC%84%9D-Linked-list</link>
            <guid>https://velog.io/@korea-dollar/React-useState%EB%B6%84%EC%84%9D-Linked-list</guid>
            <pubDate>Mon, 13 May 2024 13:31:13 GMT</pubDate>
            <description><![CDATA[<h2 id="시작에-앞서-linked-list란-무엇일까">시작에 앞서 linked list란 무엇일까?</h2>
<p>여러개의 node가 서로 연결되어 있다.
하나의 node에는 node value와 pointer to the next node가 있고 next node는 다음 node을 가리키게 된다.
<img src="https://velog.velcdn.com/images/korea-dollar/post/08acaacd-9405-401e-8b13-8961a81629f4/image.png" alt="">
<img src="https://velog.velcdn.com/images/korea-dollar/post/02ce4a43-7710-4fe4-88de-f81f671073ea/image.png" alt="">
<img src="https://velog.velcdn.com/images/korea-dollar/post/62bf6eae-2fb8-4b61-8673-3871e072fb21/image.png" alt=""></p>
<h3 id="mountworkinprogresshook">mountWorkInProgressHook</h3>
<h4 id="hook객체">hook객체</h4>
<ul>
<li><p>hook.memoizedState 마지막에 얻은 state값</p>
</li>
<li><p>hook.next다음 hook을 가리키는 pointer(hook은 linked list에 저장)</p>
</li>
<li><p>hook.queue hook을 호출할 때마다 update객체를 linked list로 구현한 queue에 저장</p>
</li>
<li><p>hoook은 배열로 설명할 수 있지만, 실제코드에서는 linked list로 구현된다.</p>
<h4 id="workinprogresshook">workInProgressHook</h4>
<p>작업중인 hook이 null일 경우 첫번째 hook아니면 그 다음 hook으로 추가한다.
fiber.memoizedState에 firstWorkInProgressHook할당 -&gt; 컴포넌트와 hook(linked list)연결
workInProgressHookdms tail poiner </p>
<h4 id="mountstate">mountState</h4>
<p>initialState가 함수면 초기값을 할당
hook.memoizedState에 initialState할당
<img src="https://velog.velcdn.com/images/korea-dollar/post/26d1b613-825f-4db3-9a50-9ad25515b54e/image.png" alt=""></p>
<h3 id="setstate의-state-update과정">setState의 state update과정</h3>
<p>dispatchAction함수</p>
</li>
<li><p>조건문은 render phase update OR idle update구분</p>
<ul>
<li>update객체 생성</li>
<li>expiration Time</li>
<li>action(setState()인지)</li>
<li>next : null</li>
<li>eagerReducer : null</li>
<li>eagerState : null
update를 queue에 저장( circular linked list )
<img src="https://velog.velcdn.com/images/korea-dollar/post/34eba4fc-8503-4d95-8df6-7aefd0ecb0f6/image.png" alt=""></li>
</ul>
</li>
<li><p>불필요한 렌더링이 발생하지 않도록 최적화</p>
<ul>
<li>Work스케줄링 X(현재 컴포넌트의 업데이트로 인해)</li>
<li>action의 결과값 === 현재 상태값
두가지 조건 모두 만족할 경우 함수 return(실행중지)
update를 적용하기 위해 Work를 scheduler에 예약(scheduling)<h4 id="setstate를-호출하는-2가지-경우">setState를 호출하는 2가지 경우</h4>
</li>
</ul>
</li>
</ul>
<ol>
<li>idle</li>
<li>render phase<h4 id="currentlyrenderingfiber">currentlyRenderingFiber</h4>
currentlyRenderingFiber는 workInProgress의 또 다른 이름(workInProgressHook에서 구분하기 위해 다른 이름으로 변수 추가 생성) 타입은 null아니면 Fiber
renderWithHooks()에서 workInProgress를 할당
(renderWithHooks는 render phase에서 호출)
다시 말해, currentlyRenderingFiber가 fiber와 동일하다(null X)라는 의미는 renderWithHooks()가 호출되었다는 의미이다.<h4 id="fiber와-alternatecurrent와-workinprogress">fiber와 alternate(current와 workInProgress)</h4>
fiber는 current와 workInProgress둘다를 가리킨다.
alternate는 fiber.alternate
여기에는 current와 workInProgress가 서로를 참조하는 주소값을 할당한다.
하지만, VDOM과 React lifeCycle에서 배운것과 같이 workInProgress(fiber)는 commit phase를 지나면서 current(fiber)로 바뀌고 current(fiber)를 참조복사해서 새로운 workInProgress(alternate)가 만들어진다.<h3 id="render-phase에서-setstate">render phase에서 setState</h3>
이미 idle에서 work를 scheduler에 등록했기 때문에 다시 WORK를 등록할 필요가 없고, 최적화할 필요도 없다.
render phase update가 더이상 발생하지 않을 때 까지 컴포넌트를 재호출하고 action(setState)을 소비하게 된다.<h3 id="render-phase에서-update의-저장">render phase에서 update의 저장</h3>
</li>
</ol>
<p><strong>didScheduleRenderPhaseUpdate</strong>
기존에 진행 중이던 update를 잠깐 담아둘 임시 저장소가 필요하다. 그리고 renderPhaseUpdates(Map)은 객체와 비슷하게 key, value형태로 값을 저장한다.
이때 key의 type으로 string뿐만 아니라 객체도 가능하다.
linked list형태로 renderPhaseUpdates를 저장한다.</p>
<h3 id="render-phase에서-update의-소비">render phase에서 update의 소비</h3>
<p>renderWithHooks()에서 renderPhaseUpdates에 저장한 update소비한다.
didSchduleRenderPhaseUpdate로 발생여부를 판단한다.
numberOfReRenders
hook업데이트 구현체에서 render phase update를 소비하기 위해 필요한 변수들의 값을 할당
nextCurrentHook
hook 업데이트를 구현테를 dispatcher에 주입한다.
ReactCurrentDispatcher.current = HooksDispatcherOnUpdate</p>
<h3 id="update진행소비중에-다시-update발생">update진행(소비)중에 다시 update발생</h3>
<p>순서
component 재 호출 &gt; 다시 update발생할 경우 didSchduleRenderPhaseUpdate값은 true &gt; numberOfReRenders가 +1되고 25번까지 반복한다.
<img src="https://velog.velcdn.com/images/korea-dollar/post/6ff3b1ae-f316-4bf8-9569-aa64a130375a/image.png" alt=""></p>
<ul>
<li>useState는 얼마나 많은 re-rendering을 진행할까?
위에서 설명한 것과 같이 rendering을 최대 25번을 진행한다. 그럼 이후에는 어떤 결과가 생길까?
우리가 한번 씩 코드를 잘못작성하거나 useEffect의 의존성 배열을 잘못넣을 경우 만나는 error가 있다.<h4 id="to-many-re-renders-react-limits-the-number-of-renders-to-prevent-and-infinite-loop">To many re-renders, React limits the number of renders to prevent and infinite loop</h4>
</li>
</ul>
<p>이런 error를 만나는 경우 useState의 state값이 rendering을 25번 진행하였고, 너무 많은 rendering을 진행하기 때문에 발생하는 것으로 파악할 수 있다.
<img src="https://velog.velcdn.com/images/korea-dollar/post/3dba2006-7a8e-4424-bd73-a3e8ce5cdefe/image.png" alt=""></p>
]]></description>
        </item>
    </channel>
</rss>