<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Soobin Bak - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/korean/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Soobin Bak - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/korean/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Wed, 24 Jun 2026 09:44:06 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/korean/news/author/soobin/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ React 서버 컴포넌트를 사용해야 하는 이유와 방법 ]]>
                </title>
                <description>
                    <![CDATA[ 2020년 말, React 팀은 "제로-번들-사이즈 React 서버 컴포넌트" 개념을 도입했습니다. 그 이후로 React 개발자 커뮤니티는 이 미래 지향적인 접근 방식을 실험하고 적용하는 방법을 학습해 왔습니다. React는 UI를 구축하는 방식에 대한 우리의 생각을 바꾸었습니다. 그리고 React 서버 컴포넌트를 사용하는 새로운 모델은 훨씬 더 구조화되고 편리하며, 유지 관리하기 쉽고 더 나은 사용자 ]]>
                </description>
                <link>https://www.freecodecamp.org/korean/news/how-to-use-react-server-components/</link>
                <guid isPermaLink="false">6598f5974759f103f7f97680</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Soobin Bak ]]>
                </dc:creator>
                <pubDate>Mon, 08 Jan 2024 08:53:44 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/korean/news/content/images/2024/01/React-Server-Components-2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>기사 원문:</strong> <a href="https://www.freecodecamp.org/news/how-to-use-react-server-components/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">React Server Components – How and Why You Should Use Them in Your Code</a>
      </p><p>2020년 말, React 팀은 "제로-번들-사이즈 React 서버 컴포넌트" 개념을 도입했습니다. 그 이후로 React 개발자 커뮤니티는 이 미래 지향적인 접근 방식을 실험하고 적용하는 방법을 학습해 왔습니다.</p><p>React는 UI를 구축하는 방식에 대한 우리의 생각을 바꾸었습니다. 그리고 React 서버 컴포넌트를 사용하는 새로운 모델은 훨씬 더 구조화되고 편리하며, 유지 관리하기 쉽고 더 나은 사용자 경험을 제공합니다.</p><p><code>Next.js</code>의 최신 릴리즈는 “서버 컴포넌트로 생각하기” 방향으로 나아갔습니다. 그리고 React 개발자로서 우리는 애플리케이션을 구축하는데 이 기술을 최대한 활용하기 위하여 새로운 사고 모델에 적응해야 합니다.</p><p>이 튜토리얼에서는 RSC(React Server Component)에 대해 배울 것입니다. React 서버 컴포넌트가 무엇인지, 어떻게 작동하는지, 그리고 더 중요하게는 이것이 어떤 문제를 해결하는지 중점적으로 알아볼 것입니다.</p><p>또한 왜 RSC가 필요한지 이해할 수 있도록 많은 예시를 보여줄 것입니다. 마지막으로 <code>React 서버 컴포넌트</code>와 비슷해 보이지만 다른 기능인 <code>서버 사이드 렌더링(SSR)</code> 간의 차이점을 배울 것입니다.</p><p>React를 처음 접하는 경우, React 서버 컴포넌트에 대해 학습하기 전에, 컴포넌트 아키텍처, 상태(state), 속성(props)을 이용한 데이터 전달, 가상 돔(Virtual DOM) 트리에 대한 기본 지식이 필요합니다.</p><p>또한 이 글을 읽은 다음 freeCodeCamp에서 <a href="https://www.freecodecamp.org/news/react-fundamentals-for-beginners/">전체 로드맵을 참고</a>하여 React 기초를 확고히 다질 수도 있습니다.</p><p>준비가 되었나요? 시작해봅시다.</p><p>만약 비디오 콘텐츠를 통해 학습하고 싶다면, 이 글을 비디오 튜토리얼로도 볼 수 있습니다. 🙂</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/5DZvdoMogys?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="React Server Components Made Easy(With Examples and Demo)" name="fitvid0"></iframe>
          </div>
        </div>
      </figure><h2 id="-ui-react">클라이언트 사이드 UI 라이브러리로서의 React</h2><p>React는 처음부터 클라이언트 사이드 UI 라이브러리였습니다. 웹 및 모바일 개발자가 컴포넌트 기반 아키텍처를 활용하여 애플리케이션을 개발하는 데 도움이 되는 JavaScript 기반의 오픈 소스 라이브러리입니다.<br>React 철학은 우리가 디자인 전체를 더 작고 독립적인 부분인 <code>컴포넌트</code>라고 불리는 작은 조각으로 나누는 것을 제안합니다.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/07/image-169.png" class="kg-image" alt="image-169" width="600" height="400" loading="lazy"></figure><p>하나의 컴포넌트가 여러 개의 하위 컴포넌트로 분해되는 것을 보여주는 이미지입니다.</p><p>컴포넌트는 <code>state</code>라고 불리는 자체 비공개 데이터와 서로 다른 컴포넌트 간에 데이터를 전달하는 방법인 &nbsp;<code>props</code>를 가질 수 있습니다. 컴포넌트들을 컴포넌트 계층 구조로 나누고, 상태를 정의하고, 상태를 변경하여 발생되는 효과(effect)를 관리하고, 데이터 흐름(flow)을 결정합니다.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/07/image-170.png" class="kg-image" alt="image-170" width="600" height="400" loading="lazy"></figure><p><em>state와 props의 작동 방식을 보여주는 이미지</em></p><p>전통적으로 이러한 모든 컴포넌트들은 자바스크립트의 함수입니다(여기서는 함수형 컴포넌트에 대해서만 이야기하고, 과거에 사용했던 클래스형 컴포넌트는 따로 이야기 하지 않겠습니다). 앱이 브라우저에서 로드될 때, 컴포넌트 코드를 다운로드하고 이를 사용하여 앱이 작동하도록 만듭니다.</p><p>여전히 ‘컴포넌트’라는 용어를 사용할 것입니다. 하지만 이 문서는 React 서버 컴포넌트의 개념을 소개하므로, 이러한 전통적인 컴포넌트를 <code>클라이언트 컴포넌트</code> 라고 부르겠습니다(클라이언트/브라우저에서 다운로드되고 React가 마법을 부려 렌더링하는 컴포넌트).</p><h2 id="react-">React 앱의 일반적인 문제</h2><p>React 클라이언트 컴포넌트는 훌륭하며 특정 사례를 해결하는 데 효과적입니다. 하지만 React 앱을 구축할 때, 패턴을 조금 다르게 고려해 볼 필요가 있습니다. 이는 다음과 같은 사항을 고려해야 하기 때문입니다.</p><ul><li><code>사용자 경험(User Experience)</code>: 우리는 사용자와 고객을 위한 소프트웨어 제품을 만듭니다. 앱이 성공하길 원한다면, 애플리케이션의 사용자 경험이 중요합니다.</li><li><code>유지 보수(Maintainability)</code>: 프로젝트 코드는 여러 개발팀을 거쳐 수년간 원활하게 유지 보수 되어야 합니다.</li><li><code>성능 비용(Performance Cost)</code>: 애플리케이션이 느려져서는 안 되며, 우리의 디자인(설계) 접근 방식이 느리게 만들어서도 안됩니다.</li></ul><p>이제 일상적으로 마주할 수 있는 몇 가지 예를 살펴보겠습니다. 또한 React를 사용하여 일상적인 웹 개발에서 각 핵심 사항을 어떻게 구현하고 설계할 수 있는지 이해할 수 있을 것입니다.</p><h3 id="-">레이아웃 이동 문제</h3><p>매우 흔한 UX 문제 중 하나는 컴포넌트가 렌더링될 때 레이아웃이 갑자기 이동되는 현상입니다. 아래의 코드 스니펫을 살펴봅시다.</p><pre><code class="language-jsx">&lt;CourseWraper&gt;
  &lt;CourseList /&gt;
  &lt;Testimonials /&gt;
&lt;/CourseWraper&gt;
</code></pre><p>다음은 익숙한 JSX 코드로, <code>CourseWrapper</code> 컴포넌트와 <code>CourseList</code> 및 <code>Testimonials</code> 두 개의 하위 컴포넌트가 있습니다. <code>CourseList</code> 와 <code>Testimonials</code> 두 컴포넌트 모두 데이터를 가져오기 위해 네트워크 호출(API 호출)을 수행한다고 가정해 봅시다.</p><p>다음은 <code>CourseList</code> 컴포넌트 입니다.</p><pre><code class="language-jsx">function CourseList() {

    // 실제 네트워크 호출을 가정하면,
    // useEffect를 사용하여 처리할 것입니다.
    const info = fetchCourseList();

    return(
      &lt;&gt; &lt;/&gt;)
}
</code></pre><p>그리고 <code>Testimonial</code> 컴포넌트 입니다.</p><pre><code class="language-jsx">function Testimonials() {

    // 실제 네트워크 호출을 가정하면,
    // useEffect를 사용하여 처리할 것입니다.
    const info = fetchTestimonials();

    return(
      &lt;&gt; &lt;/&gt;
    )
}
</code></pre><p>이러한 컴포넌트들이 네트워크 호출을 수행하는 경우, 응답이 돌아오는 순서에 대한 보장이 없습니다. 이는 네트워크 속도, 지연 시간 및 여러 다른 요인에 따라 달라집니다.<br><code>Testimonials</code> 컴포넌트의 네트워크 호출이 <code>CourseList</code> 컴포넌트보다 먼저 완료되는 상황에서, <code>Testimonials</code> 컴포넌트가 먼저 렌더링되고 그 다음에 <code>CourseList</code> 컴포넌트가 렌더링됩니다. 이로 인해 <code>Testimonials</code> 컴포넌트가 적합한 위치로 이동됩니다. 아래에서 제가 하는 말이 무엇인지 확인할 수 있습니다.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/07/layoutshift-1.gif" class="kg-image" alt="layoutshift-1" width="600" height="400" loading="lazy"></figure><p><em>레이아웃 이동의 UX 문제를 보여주는 슬로우 모션</em></p><p>로딩 인디케이터나 깜빡임 효과를 통해서 사용자에게 잠시 후를 기대하도록 알려주어 UX를 좀 더 향상시킬 수 있습니다(그러나 언제가 될지는 확신하지 못합니다).</p><h3 id="-waterfall-">네트워크 워터폴(waterfall) 문제</h3><p>또 다른 전형적인 사용자 경험 문제에 대해 이야기해 봅시다. 지난 예제와 유사한 React 컴포넌트를 상상해 보세요.</p><pre><code class="language-jsx">function Course() {
  return (
    &lt;CourseWraper&gt;
      &lt;CourseList /&gt;
      &lt;Testimonials /&gt;   
    &lt;/CourseWraper&gt;
  )
}
</code></pre><p><em>두 개의 하위 컴포넌트를 가진 CourseWrapper 컴포넌트</em></p><p>여기서 조금 수정을 해보겠습니다. <code>CourseList</code> 과 <code>Testimonials</code> 컴포넌트와 함께 이제 <code>CourseWrapper</code>도 네트워크 호출을 수행합니다.</p><pre><code class="language-jsx">function CourseWrapper() {

    // 실제 네트워크 호출을 가정하면,
    // useEffect를 사용하여 처리할 것입니다.
    const info = fetchWrapperInfo();
    
    return(
      &lt;&gt; &lt;/&gt;
    )
}
</code></pre><p><em>CourseWrapper 컴포넌트 - 네트워크 호출 수행</em></p><p>따라서 부모 컴포넌트는 데이터를 가져오기 위해 네트워크 호출을 수행하고, 그 하위 컴포넌트들 또한 네트워크 호출을 수행합니다.</p><p>흥미로운 점은, 부모 컴포넌트는 네트워크 호출이 완료될 때까지 렌더링되지 않는다는 것입니다. 따라서 자식 컴포넌트들의 렌더링도 홀딩 합니다.</p><p>현재 작업을 시작하기 위해 이전 것의 응답이 완료되기를 기다리는 현상은 <code>워터폴(Waterfall)</code>라고 알려져 있습니다. 이 경우에는 네트워크 워터폴 및 컴포넌트 렌더링 워터폴 문제 모두 발생합니다.</p><p>이제 여러분은 각 컴포넌트에서의 모든 네트워크 호출을 제거하고 각각의 컴포넌트가 응답을 기다리지 않도록 부모 컴포넌트에서 단일 호출 하도록 네트워크 호출 로직을 끌어 올릴 수 있다고 생각할 수 있습니다. 이것은 현명한 생각이지만 유지 보수 측면에서 문제가 발생할 수 있습니다. 다음 섹션에서 이에 대해 더 자세히 알아보겠습니다.</p><h3 id="--1">유지 보수 관련 문제</h3><p>서버 측 상호 작용과 관련된 몇 가지 사용자 경험 문제를 살펴보았으므로, 이제 유지 보수 관련 문제를 고려해 봅시다.</p><p>모든 컴포넌트가 네트워크 호출을 수행하지 않는다고 가정해 봅시다. 단일 API 호출인 <code>fetchAllDetails()</code>를 사용하여 (부모 컴포넌트를 포함하여) 모든 컴포넌트의 세부 정보를 한 번에 가져옵니다.</p><p>그런 다음 필요한 정보를 각 컴포넌트에 props로 전달합니다. 이것은 위에서 본 "워터폴" 문제보다 더 나은 접근 방법이겠지요?</p><pre><code class="language-jsx">function Course() {
	
    // 실제 네트워크 호출을 가정하면,
    // useEffect를 사용하여 처리할 것입니다. 
    const info = fetchAllDetails();
    
    return(
    	&lt;CourseWrapper
        	ino={info.wrapperInfo} &gt;
            &lt;CourseList
        		ino={info.listInfo} /&gt;
            &lt;Testimonials
        		ino={info.testimonials} /&gt;
        &lt;/CourseWrapper&gt;     
    )
 }
</code></pre><p><em>Course 컴포넌트 - 최상위 API 호출 수행</em></p><p>그러나 이것은 일부 유지 보수 문제를 야기할 수 있습니다.</p><p>어느 화창한 날, 제품이 Testimonials 기능을 삭제하기로 결정했다고 가정해 봅시다. 우리는 위의 코드에서 Testimonials 컴포넌트를 간단히 삭제할 수 있습니다. 그런데, <code>fetchAllDetails()</code> 호출을 통해 가져온 데이터를 정리하는 것을 잊을 수 있습니다. 사용되지 않고 불필요한 상태로 남아 있을 수 있습니다.</p><p>이러한 문제를 완화하기 위해, 가능한 사용자 경험 문제를 설명하면서 이전 섹션에서 이미 논의한 방식으로 코드를 변경할 수 있을 것입니다. 따라서 우리는 더 나은 해결책을 찾아야 합니다. 하지만 그에 앞서, <code>성능 비용</code>이라는 또 하나의 고려 사항에 대해 먼저 이야기해 보겠습니다.</p><h3 id="--2">성능 비용</h3><p>우리가 논의할 마지막 문제 영역은 성능 비용입니다.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/07/image-171.png" class="kg-image" alt="image-171" width="600" height="400" loading="lazy"></figure><p><em>인터넷에서 발견한 재미있는 밈 - 자바스크립트가 클라이언트에게 주는 무거움을 묘사</em></p><p>전통적으로, React 컴포넌트는 클라이언트 사이드 자바스크립트 함수입니다. 이는 React 애플리케이션의 구성 요소입니다. 클라이언트에서 애플리케이션을 로드할 때, 컴포넌트가 클라이언트에 다운로드되고 React가 그것들을 렌더링하는데 필요한 작업을 수행합니다.</p><p>그러나 이로 인해 두 가지 중요한 문제가 발생합니다.</p><p>먼저, 사용자가 요청을 보낼 때, 앱은 HTML과 연결된 JavaScript, CSS 및 이미지와 같은 다른 에셋을 다운로드합니다.</p><p>클라이언트 사이드(브라우저에서)에서 React는 마법을 부리기 시작하고 HTML 구조를 하이드레이트(hydrate) 시킵니다. 이것은 HTML을 구문 분석하고, 이벤트 리스너를 DOM에 연결하며 스토어에서 데이터를 가져옵니다. 따라서 사이트는 완전히 작동하는 React 앱이 됩니다.</p><p>그러나 중요한 점은 클라이언트에서 많은 일이 일어나고 있다는 것입니다. 결국 이 코드를 모두 클라이언트에서 다운로드하게 됩니다.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/07/image-182.png" class="kg-image" alt="image-182" width="600" height="400" loading="lazy"></figure><p><em>브라우저에 다운로드된 스크립트의 양</em></p><p>대부분의 경우, 프로젝트에 종속성이 있는 외부 라이브러리(Node 모듈)가 필요합니다. 이러한 모든 종속성은 클라이언트 사이드에서 다운로드되어 더욱 무거워집니다.</p><p>이제 문제점을 이해했으므로, <code>React 서버 컴포넌트</code>가 제공하는 기능과 이러한 문제를 해결하는 방법에 대해서 확실히 이해할 수 있을 것입니다.</p><p>그러나 이에 대해 이야기하기 전에, 클라이언트와 서버에 대해 조금 더 알아보겠습니다.</p><h2 id="--3">클라이언트-서버 모델</h2><p>이 글에서 클라이언트와 서버 라는 용어를 여러 번 사용했습니다. 이제 이들에 대한 공식적인 정의를 내리고 높은 수준에서 그들의 관계를 설명해보겠습니다.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/size/w1600/2023/07/image-175.png" class="kg-image" alt="image-175" width="600" height="400" loading="lazy"></figure><p><em>클라이언트와 서버의 관계를 보여주는 다이어그램</em></p><ul><li><code>클라이언트</code>: 애플리케이션의 클라이언트는 최종 사용자 측에서 작업을 실행하는 시스템입니다. 클라이언트의 예로는 PC, 랩탑, 모바일, 브라우저 등이 있습니다.</li><li><code>서버</code>: 이름에서 알 수 있듯이, 서버는 클라이언트에 서비스를 제공합니다. 빠른 데이터 액세스를 위해 데이터 저장소나 데이터베이스와 공존할 수 있습니다.</li><li><code>요청</code>: 요청은 클라이언트가 서버로부터 서비스를 요청하기 위해 사용하는 통신 모드입니다.</li><li><code>응답</code>: 응답은 또한 서버가 서비스(데이터/정보)를 클라이언트에게 다시 보내기 위해 사용하는 통신 모드입니다.</li></ul><h2 id="react--1">React 클라이언트 컴포넌트</h2><p>위에서 언급한대로, 전통적으로 React 컴포넌트는 클라이언트 사이드에서 실행됩니다. 서버와 상호 작용할 때, 요청을 보내고 응답이 돌아올 때까지 기다립니다. 응답을 받으면 클라이언트는 다음 작업을 트리거합니다.</p><p>요청한 서비스가 성공적으로 완료되면 클라이언트 컴포넌트는 UI에 맞게 작동하고 성공 메시지를 표시합니다. 오류가 발생한 경우 클라이언트 컴포넌트는 사용자에게 오류를 보고합니다.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/size/w1600/2023/07/image-176.png" class="kg-image" alt="image-176" width="600" height="400" loading="lazy"></figure><p><em>클라이언트 서버 모델에서의 React 클라이언트 컴포넌트</em></p><p>네트워크 워터폴를 발생시킬 때 클라이언트 컴포넌트의 응답이 지연되어 사용자 경험이 저하됩니다. 그렇다면 이를 어떻게 완화할 수 있을까요?</p><h2 id="react-rscs-">React 서버 컴포넌트(RSCs)는 어떻게 도움을 줄까요?</h2><p>React 컴포넌트를 서버로 옮겨보는 것은 어떨까요? 그리고 아마도 데이터 저장소와 동일한 곳에 위치시키고... 그런데 이것이 실제로 가능한 일일까요?<br>네! 이제 <code>React Server Components</code>에 대해 알아보겠습니다. 이러한 새로운 컴포넌트는 서버에 있으므로 데이터를 더 빨리 가져올 수 있습니다. 네트워크를 통해 왕복하지 않고도 파일 시스템 및 데이터 저장소와 같은 서버 인프라에 액세스할 수 있습니다.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/size/w1600/2023/07/image-177.png" class="kg-image" alt="image-177" width="600" height="400" loading="lazy"></figure><p><em>클라이언트 서버 모델에서의 React 서버 컴포넌트</em></p><p>이제 서버 컴포넌트 측면에서 생각해야 하기 때문에, React 개발자에게는 완전한 패러다임 전환입니다.</p><p>RSC를 사용하면, 데이터 가져오는 로직을 서버로 이동하여(네트워크 호출 없이 데이터를 가져오도록) 서버 자체에서 준비할 수 있습니다. 클라이언트로 돌아오는 데이터는 모든 데이터와 함게 잘 구성된 컴포넌트 입니다. 얼마나 놀라운 일인가요?</p><p>이는 React 서버 컴포넌트를 사용하면 다음과 같은 코드를 작성할 수 있음을 의미합니다.</p><pre><code class="language-jsx">import { dbConnect } from '@/services/mongo'

import { addCourseToDB } from './actions/add-course'

import CourseList from './components/CourseList'

export default async function Home() {

  // MongoDB 연결
  await dbConnect();
  
  // db의 모델을 이용하여 모든 course를 얻는다.
  const allCourses = await courses.find();
  
  // 서버 쪽에서 콘솔이 찍힌다.
  console.log({allCourses})

  return (
    &lt;main&gt;
      &lt;div&gt;
        &lt;CourseList allCourses={allCourses} /&gt;  
      &lt;/div&gt;
    &lt;/main&gt;
  )
}
</code></pre><p><em>React 서버 컴포넌트의 예</em></p><p>저것 보세요! 몇 가지 변경 사항을 즉시 알아챌 수 있습니다.</p><ul><li>이 컴포넌트는 비동기 호출을 처리하므로 <code>async</code> 타입 입니다.</li><li>우리는 컴포넌트 자체에서 데이터베이스(MongoDB)에 연결합니다. 와우! 보통 이러한 코드는 <code>Node.js</code> 또는 <code>Express</code>에서 볼 수 있습니다, 맞나요?</li><li>그런 다음 데이터베이스를 쿼리하고 렌더링을 위해 JSX에 전달할 데이터를 가져옵니다.</li></ul><p>콘솔 로그는 브라우저 콘솔이 아닌 서버 콘솔에서 찍히는 것에 주목하세요.</p><p>또한 상태 관리 (useState)와 이펙트 관리 (useEffect)를 완전히 제거했습니다. 깔끔하고 간단합니다.</p><p>React 서버 컴포넌트를 사용하면, useEffect를 사용할 필요가 없을 수도 있습니다(영원히!).</p><h3 id="react--2">React 서버 컴포넌트의 한계</h3><p>이러한 이점도 갖고 있지만, 기억해야 할 RSC의 제한 사항도 있습니다.</p><ul><li>RSC는 서버에 남아 있고 서버에서 렌더링됩니다. 클라이언트 사이드과 관련된 것이 없습니다. 이것은 서버 컴포넌트에 사용자 인터렉션을 추가할 수 없음을 의미합니다. 예를 들어, 이벤트 핸들러나 useState, useReducer, useEffect와 같은 React 훅을 서버 컴포넌트에서 사용할 수 없습니다.</li><li>서버 컴포넌트에서 localstorage, bluetooth, web USB와 같은 브라우저 웹 API를 사용할 수 없습니다.</li><li>클라이언트 상호 작용과 관련된 모든 것에 대해서는, 계속 클라이언트 컴포넌트를 사용해야 합니다.</li></ul><p>이해가 되시나요? 그렇다면 어떻게 애플리케이션에 맞게 컴포넌트를 가장 잘 정리할 수 있을까요?</p><h3 id="--4">클라이언트와 서버 컴포넌트를 함께 사용하는 방법</h3><p>당신의 앱은 서버 및 클라이언트 컴포넌트의 조합일 수 있습니다. 곧 예제를 보겠지만, 먼저 개념을 이해해 봅시다.</p><p>서버 컴포넌트는 클라이언트 컴포넌트를 가져와 렌더링할 수 있지만, 클라이언트 컴포넌트는 내부에서 서버 컴포넌트를 렌더링할 수 없습니다. 클라이언트 컴포넌트에서 서버 컴포넌트를 사용하려면 props로 전달하여 사용할 수 있습니다.</p><p>컴포넌트 계층 구조의 루트에 서버 컴포넌트를 두고 컴포넌트 트리의 말단으로 클라이언트 컴포넌트를 밀어 넣는 것이 좋습니다.</p><p>서버 컴포넌트의 최상단에서 데이터 페칭이 일어날 수 있으며, React가 허용하는 방식대로 전달할 수 있습니다. 사용자 상호 작용(이벤트 핸들러) 및 브라우저 API에 액세스는 말단의 클라이언트 컴포넌트에서 처리할 수 있습니다.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/07/image-186.png" class="kg-image" alt="image-186" width="600" height="400" loading="lazy"></figure><p><em>서버와 클라이언트 컴포넌트를 포함하는 컴포넌트 트리</em></p><h3 id="-rsc-ssr-">잠깐, RSC는 서버 사이드 렌더링(SSR)과 동일하지 않나요?</h3><p>아니요, 그렇지 않습니다. RSC와 SSR 둘 다 이름에 "서버"라는 단어가 들어가 있지만 비슷한 부분은 이 뿐입니다.</p><p>서버 사이드 렌더링(SSR)에서는, 서버에서 날것의 HTML을 클라이언트로 보내고, 그런 다음 모든 클라이언트 사이드 자바스크립트가 다운로드됩니다. React는 HTML을 상호작용 가능한 React 컴포넌트로 변환하기 위해 하이드레이션(hydration) 프로세스를 시작합니다. SSR에서 컴포넌트는 서버에 머무르지 않습니다.</p><p>지금까지 React 서버 컴포넌트를 통해 컴포넌트가 서버에 남아 있고 네트워크 왕복을 거치지 않고 서버 인프라에 액세스할 수 있음을 알게 되었습니다.</p><p>SSR은 애플리케이션의 초기 페이지를 더 빠르게 로드하는 데 유용합니다. 앞으로 SSR과 RSC를 문제없이 함께 사용할 수 있습니다.</p><h2 id="next-js-rsc-mongodb-">Next.js(RSC 포함)와 MongoDB를 사용하여 강의 목록 페이지를 구축하는 방법</h2><p>이제 React 서버 컴포넌트를 사용하는 응용 프로그램을 만들어 보겠습니다. Next.js는 최근 릴리스에서 RSC를 채택한 주요 웹 프레임워크입니다.</p><p>그래서 우리는 이제 Next.js에서 서버 컴포넌트를 만드는 방법과 클라이언트 컴포넌트를 만드는 방법이 어떻게 다른지를 보여주기 위해 강의 목록 페이지를 만들 것입니다.</p><p>여기서는 Next.js나 MongoDB를 자세히 배우지 않을 것입니다. React 서버 컴포넌트가 어떻게 동작하는지 그리고 클라이언트 컴포넌트와 어떻게 다른지 알려주기 위한 예로 이 애플리케이션을 사용하고 있습니다.</p><p>먼저 데이터 저장소에 강의 데이터를 추가해 보겠습니다. 이 앱에서는 MongoDB를 사용했습니다. 아래 이미지는 세 개의 강의에 대해 세 개의 문서가 추가된 것을 보여줍니다.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/size/w1600/2023/07/image-178.png" class="kg-image" alt="image-178" width="600" height="400" loading="lazy"></figure><p><em>Mongo Compass - 강좌 모음</em></p><p>다음으로, MongoDB에 연결하는 유틸리티 함수를 만들겠습니다. 이것은 Mongoose와 MongoDB URI를 사용하여 자바스크립트 기반 프로젝트에서 MongoDB에 연결하는 데 사용할 수 있는 일반적인 코드입니다.</p><pre><code class="language-jsx">import mongoose from "mongoose";

export async function dbConnect(): Promise&lt;any&gt; {
  try {
    const conn = await mongoose.connect(String(process.env.MONGO_DB_URI));
    console.log(`Database connected : ${conn.connection.host}`);
    return conn;
  } catch (err) {
    console.error(err);
  }
}
</code></pre><p><em>MongoDB 연결을 위한 코드 스니펫</em></p><p>이제 MongoDB 문서와 매핑하는 모델을 만들어야 합니다. 여기서는 강의 데이터를 다루고 있으므로, 이에 해당하는 모델은 다음과 같습니다.</p><pre><code class="language-jsx">import mongoose, { Schema } from "mongoose";

const schema = new Schema({
  name: {
      required: true,
      type: String
  },
  description: {
      required: true,
      type: String
  },
  cover: {
    required: true,
    type: String
  },
  rating: {
    required: true,
    type: Number
  },
  price: {
    required: true,
    type: Number
  },
  createdOn: {
    type: { type: Date, default: Date.now }
  },
  link: {
    required: true,
    type: String
  },
  type: {
    required: true,
    type: String
  },
  comments: {
    required: false,
    type: [{ body: String, date: Date }]
  }
});

export const courses = mongoose.models.course ?? mongoose.model("course", schema);
</code></pre><p><em>Mongoose를 사용한 강의 모델</em></p><p>이제 마법이 시작됩니다! Next.js 앱 라우터를 사용하면 모든 컴포넌트가 기본적으로 서버 컴포넌트입니다. 이것은 서버 근처에 위치하고 서버 생태계에 액세스할 수 있음을 의미합니다.</p><p>아래 코드는 일반적인 Next.js 컴포넌트지만 특별한 기능이 있습니다. 이 컴포넌트에서 데이터베이스 연결을 직접 하여 어떤 state와 effect 관리를 하지 않고도 데이터를 직접 쿼리할 수 있습니다. 멋지죠?</p><p>이 컴포넌트에서 기록하는 모든 내용은 브라우저 콘솔에 찍히지 않습니다. 왜냐하면 이것은 서버 컴포넌트이기 때문입니다. 로그는 서버 콘솔에서 확인할 수 있습니다(아마도 <code>yarn dev</code> 명령을 사용하여 서버를 시작한 터미널에서).</p><p>데이터베이스와의 상호 작용은 비동기적 이므로, 호출 시 <code>await</code> 키워드를 사용하고 컴포넌트에는 <code>async</code> 키워드를 사용합니다. 응답을 받으면 이를 자식 컴포넌트에 props로 전달합니다.</p><pre><code class="language-jsx">import { dbConnect } from '@/services/mongo'
import { courses } from '@/models/courseModel'
import { addCourseToDB } from './actions/add-course'

import AddCourse from './components/AddCourse'
import CourseList from './components/CourseList'

export default async function Home() {

  // MongoDB 연결
  await dbConnect();
  
  // 모델을 이용하여 db로 부터 모든 강의를 가져옴.
  const allCourses = await courses.find().select(
  						["name", "cover", "rating"]);
  
  // 서버 콘솔에서 모든 출력값 표시
  console.log({allCourses})

  return (
    &lt;main&gt;
      &lt;div&gt;
        &lt;h1&gt;Courses&lt;/h1&gt; 
        &lt;AddCourse addCourseToDB={addCourseToDB} /&gt;
        &lt;CourseList allCourses={allCourses} /&gt;  
      &lt;/div&gt;
    &lt;/main&gt;
  )
}
</code></pre><p><em>page.tsx - 서버 컴포넌트</em></p><p>Home 컴포넌트에는 아래 내용이 포함되어 있습니다.</p><ul><li>제목(Heading)</li><li>강의 추가 버튼을 래핑한 컴포넌트(AddCourse)</li><li>강의 목록을 표시하는 컴포넌트(CourseList)</li></ul><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/07/Screenshot-2023-07-25-at-9.58.57-AM.png" class="kg-image" alt="Screenshot-2023-07-25-at-9.58.57-AM" width="600" height="400" loading="lazy"></figure><p>강의 목록 페이지</p><p>서버 컴포넌트는 클라이언트 및 서버 컴포넌트 모두 렌더링할 수 있다는 것을 알고 있습니다. <code>AddCourse</code> 컴포넌트는 사용자 인터렉션이 필요하며, 사용자가 버튼을 클릭하여 강의를 추가해야 합니다. 따라서 이는 서버 컴포넌트가 될 수 없습니다 (앞에서 읽은 서버 컴포넌트의 제한 사항을 기억하세요)!</p><p>그러므로 <code>AddCourse</code>를 위한 클라이언트 컴포넌트를 만들어 봅시다. Next.js 앱 라우터를 사용하면 모든 컴포넌트는 기본적으로 서버 컴포넌트입니다. 클라이언트 컴포넌트를 만들고 싶다면 해당 컴포넌트의 맨 위에서(import 문 이전에도 됨) <code>'use client'</code>라는 지시문을 사용하여 명시적으로 만들어야 합니다.</p><pre><code class="language-jsx">'use client'

import { useState } from 'react';
import Modal from './Modal';
import AddCourseForm from "./AddCourseForm";

export default function AddCourse({
  addCourseToDB,
}: {
  addCourseToDB: (data: any) =&gt; Promise&lt;void&gt;
}) {
  const [showAddModal, setShowAddModal] = useState(false);
  const add = async(data: any) =&gt; {
    await addCourseToDB(data);
    setShowAddModal(false);
  }

  return (
    &lt;&gt;
    &lt;button
      onClick={() =&gt; setShowAddModal(true)}
    &gt;
      Add Course
    &lt;/button&gt;
    &lt;Modal 
      shouldShow={showAddModal} 
      body={
        &lt;AddCourseForm 
          saveAction={add} 
          cancelAction={() =&gt; setShowAddModal(false)} /&gt;} /&gt;
    &lt;/&gt;
  )
}
</code></pre><p><em>AddCourse - 클라이언트 컴포넌트</em></p><p><code>CourseList</code> 컴포넌트는 어떠한 이벤트 핸들러도 필요하지 않으므로, 서버 컴포넌트로 유지할 수 있습니다.</p><pre><code class="language-jsx">import Image from 'next/image'
import Link from 'next/link'

export default function CourseList(courseList: any) {
  const allCourses = courseList.allCourses;
  return(
    &lt;div&gt;
      {
        allCourses.map((course: any) =&gt;
        &lt;Link key={course['_id']} href={`/courses/${course['_id']}`}&gt;
          &lt;div&gt;
            &lt;Image
              src={course.cover}
              width={200}
              height={200}
              alt={course.name}
            /&gt;
            &lt;h2&gt;{course.name}&lt;/h2&gt;
            &lt;p&gt;{course.rating}&lt;/p&gt;
          &lt;/div&gt; 
        &lt;/Link&gt; 
      )}
    &lt;/div&gt;  
  )

}
</code></pre><p><em>CourseList - 서버 컴포넌트</em></p><p>또한 브라우저의 개발자 도구에서 <code>Sources</code> 탭을 확인하여 클라이언트에 다운로드되는 내용과 서버에 남아 있는 내용을 식별할 수 있습니다. 여기서 <code>page.tsx</code> 파일이나 <code>CourseList.tsx</code> 파일을 볼 수 있나요? 아니요. 왜냐하면 그것들은 서버 컴포넌트이며 클라이언트 번들의 일부가 아니기 때문입니다.</p><p>우리는 앱에서 명시적으로 클라이언트 컴포넌트라고 표시한 컴포넌트만 볼 수 있습니다.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/07/image-179.png" class="kg-image" alt="image-179" width="600" height="400" loading="lazy"></figure><p><em>클라이언트 번들 확인</em></p><p>이 애플리케이션의 흐름을 통해 이론이 실제와 어떻게 연결되는지 보여주었기를 바랍니다. 이제 React 앱에서 서버 컴포넌트를 사용하는 방법을 이해하셨을 것입니다.</p><h2 id="--5">요약</h2><p>요약하면 다음과 같습니다.</p><ul><li>React 서버 컴포넌트는 네트워크 왕복 없이 백엔드 접근이 가능합니다.</li><li>React 서버 컴포넌트를 통해 네트워크 워터폴을 피할 수 있습니다.</li><li>React 서버 컴포넌트는 자동 코드 분할(splitting)을 지원하며 번들 크기를 제로로 줄여 앱의 성능을 향상시킵니다.</li><li>이러한 컴포넌트는 서버 측에 있으므로 클라이언트 사이드 이벤트 핸들러, state 및 effect에 액세스할 수 없습니다. 이는 이벤트 핸들러나 useState, useReducer, useEffect와 같은 React 훅을 사용할 수 없음을 의미합니다.</li><li>React 서버 컴포넌트는 클라이언트 컴포넌트를 가져와 렌더링할 수 있지만, 반대로는 불가능 합니다. 그러나 서버 컴포넌트를 클라이언트 컴포넌트에 props로 전달할 수 있습니다.</li></ul><h2 id="--6">마치기 전에..</h2><p>이상으로 마무리합니다. 이 글이 유익하고 통찰력을 얻었기를 바랍니다.</p><p>저와 소통해보세요.</p><ul><li>제 YouTube 채널인 <code>tapaScript</code>에서 교육을 진행하고 있습니다. JavaScript, ReactJS, Node.js, Git 및 웹 개발의 기본을 배우고 싶다면 <a href="https://www.youtube.com/tapasadhikary?sub_confirmation=1">구독</a>해주세요.</li><li>웹 개발 및 프로그래밍 팁을 매일 놓치고 싶지 않다면 <a href="https://twitter.com/tapasadhikary">Twitter</a> 또는 <a href="https://www.linkedin.com/in/tapasadhikary/">LinkedIn</a> 팔로우를 해주세요.</li><li><a href="https://github.com/atapas">GitHub</a>에서 제 오픈 소스 작업을 확인해보세요.</li></ul><p>다음 글에서 뵙겠습니다. 그 동안 자신을 돌보며 행복하게 지내세요.</p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
