<p style="text-align:justify;">프론트엔드 개발에서 상태(State)는 UI와 데이터의 흐름을 관리하는 핵심 요소입니다. 이를 효과적으로 처리하기 위해, 프론트엔드 라이브러리인 리액트(React)에서는 useState라는 강력한 도구를 제공하는데요. useState를 사용하면 초깃값을 설정하고, 상태를 변경하며 이를 기반으로 UI를 갱신하는 과정을 아주 간단하게 처리할 수 있습니다.</p><p style="text-align:justify;"> </p><figure class="image image_resized" style="width:100%;"><img src="https://www.wishket.com/media/news/2967/image1__1_.png"><figcaption><출처: 작가, ChatGPT></figcaption></figure><p style="text-align:justify;"> </p><p style="text-align:justify;">리액트의 useState는 마치 스마트홈 시스템처럼 작동합니다. 버튼 하나로 조명과 온도를 자동으로 제어할 수 있는 편리함을 제공합니다. 하지만 이런 자동화 시스템이 없다면, 우리는 각 방의 조명을 일일이 켜고 끄고 온도를 수동으로 조절해야 하겠죠. 그렇다면 리액트 없이, 순수 자바스크립트만으로도 이런 상태 관리 방식을 직접 구현할 수 있을까요?</p><p style="text-align:justify;"> </p><p style="text-align:justify;">사실 바닐라 자바스크립트만 활용해도 비슷한 방식의 상태 관리 로직을 만들 수 있습니다. 이번 글에서는 리액트의 useState가 어떻게 상태를 관리하고 UI를 갱신하는지 간단히 살펴본 다음, 바닐라 자바스크립트를 활용해 유사한 상태 관리 로직을 구현하는 방법을 알아보겠습니다.</p><div class="page-break" style="page-break-after:always;"><span style="display:none;"> </span></div><h3 style="text-align:justify;"><strong>리액트의 ‘useState’</strong></h3><p style="text-align:justify;">리액트는 컴포넌트에서 상태를 관리하기 위해 useState라는 훅(Hook)을 제공합니다. 여기서 훅이란, 상태와 리액트의 라이프사이클 기능을 사용할 수 있도록 만든 도구로, 대표적인 훅으로는 useState, useEffect, useContext 등이 있습니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">리액트의 useState는 상태 변경 시 Virtual DOM을 통해 필요한 부분만 업데이트합니다. 이는 상태와 UI를 자동으로 연결하고 최적화된 성능을 제공합니다. 반면, 바닐라 자바스크립트에서는 상태와 UI를 명시적으로 연결해야 하며, 수동으로 DOM을 조작해야 합니다.</p><p style="text-align:justify;"> </p><h4 style="text-align:justify;"><strong>1) useState 사용 예시</strong></h4><p style="text-align:justify;">상태(State)는 UI와 데이터 흐름을 관리하는 데 중요한 역할을 하며, 리액트의 useState는 이를 간단하고 효율적으로 처리할 수 있도록 설계되었습니다. useState를 활용한 간단한 카운터 예제 코드를 살펴보면서, useState에 대해 좀 더 자세히 알아볼게요.</p><p style="text-align:justify;"> </p><pre><code class="language-javascript">import 리액트, { useState } from "리액트"; function Counter() { const [count, setCount] = useState(0); return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); }</code></pre><p style="text-align:justify;"> </p><p style="text-align:justify;">위의 코드에서 useState(0)은 초깃값을 0으로 설정하는 역할을 합니다. 리액트는 이 초깃값을 기억하고, count라는 변수를 통해 현재 상태 값을 제공합니다. 상태 값을 변경하려면 setCount라는 함수를 호출하면 되는데요, 위 코드에서는 버튼을 클릭할 때 setCount(count + 1)를 호출해서 상태 값을 1씩 증가시키고 있습니다.</p><p style="text-align:justify;"> </p><h4 style="text-align:justify;"><strong>2) useState를 사용하면 좋은 점</strong></h4><p style="text-align:justify;">이렇게 상태가 변경되면 리액트는 변경 사항을 감지하고, 컴포넌트를 다시 렌더링하여 최신 상태를 화면에 반영합니다. 즉, 버튼을 누를 때마다 숫자가 증가하는 것을 확인할 수 있죠. 이 과정을 리액트는 매우 효율적으로 처리합니다. 상태 변경 시 필요한 부분만 업데이트하고, Virtual DOM을 활용해 실제 DOM 조작을 최소화하여 성능을 최적화합니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">리액트의 useState는 개발자가 복잡한 DOM 조작을 직접 작성할 필요 없이, 상태와 UI를 간단하게 연결할 수 있도록 도와줍니다. 버튼 클릭과 같은 이벤트에 따라 상태가 업데이트되며, 새로운 상태가 반영된 UI를 자동으로 갱신해 주는 점이 바로 useState의 가장 큰 장점이라고 할 수 있습니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;"> </p><h3 style="text-align:justify;"><strong>‘바닐라 자바스크립트’로 상태 관리하기</strong></h3><p style="text-align:justify;">프론트엔드에서 상태(State)는 UI와 데이터 흐름을 관리하는 데 중요한 역할을 합니다. 리액트의 useState는 상태를 간단히 관리하는 강력한 도구지만, 리액트 없이도 바닐라 자바스크립트를 사용하여 유사한 상태 관리 로직을 구현할 수 있습니다. 이를 통해 상태 저장, 상태 변경, UI와 상태 연결, 그리고 다중 상태 관리까지의 개념을 명확히 이해할 수 있습니다.</p><p style="text-align:justify;"> </p><h4 style="text-align:justify;"><strong>1) 상태 정의와 초기화</strong></h4><p style="text-align:justify;">상태는 애플리케이션의 현재 데이터를 저장하는 핵심 요소로, UI 동작을 결정짓는 중요한 역할을 합니다. 예를 들어, 동물 사진 앨범 애플리케이션에서 상태는 현재 선택된 탭(currentTab)과 해당 탭에 맞는 사진 데이터(photos)를 저장합니다. </p><p style="text-align:justify;"> </p><figure class="image image_resized" style="width:100%;"><img src="https://www.wishket.com/media/news/2967/image2.png"><figcaption>동물 사진 앨범 애플리케이션 <출처: 작가></figcaption></figure><p style="text-align:justify;"> </p><p style="text-align:justify;">이 애플리케이션의 초기 상태는 다음과 같이 정의할 수 있습니다.</p><p style="text-align:justify;"> </p><pre><code class="language-javascript">this.state = { currentTab: 'all', // 현재 선택된 탭 photos: [], // 현재 탭에 해당하는 사진 목록 }; </code></pre><p style="text-align:justify;"> </p><p style="text-align:justify;">여기서 currentTab에는 사용자가 선택한 카테고리를 저장하고, photos에는 해당 카테고리에 맞는 사진 데이터를 저장합니다. 리액트의 useState와 유사하게 상태를 객체로 관리하며 초깃값을 명시적으로 설정합니다.</p><p style="text-align:justify;"> </p><h4 style="text-align:justify;"><strong>2) 초기화와 데이터 로드</strong></h4><p style="text-align:justify;">바닐라 자바스크립트로 상태를 관리할 때, 초기화와 데이터 로드는 애플리케이션의 안정성을 확보하는 중요한 과정입니다. 리액트에서는 useEffect를 통해 컴포넌트가 처음 렌더링 될 때 초기 데이터를 설정하고 상태를 관리하지만, 바닐라 자바스크립트에서는 초기 데이터를 요청하고 상태를 업데이트하는 로직을 명시적으로 작성해야 합니다. 초기화 작업을 제대로 수행하지 않으면, UI에 잘못된 데이터가 표시되거나 예상치 못한 동작이 발생할 수 있습니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">초기 상태를 설정하고 데이터를 로드하는 로직은 애플리케이션이 첫 화면을 제대로 렌더링하기 위해 필수적입니다. 예를 들어, 동물 사진 앨범 애플리케이션에서는 기본 탭(all)에 대한 사진 데이터를 로드하고 이를 상태에 저장해야 합니다. 이러한 초기화 작업을 담당하는 init 함수는 다음과 같이 구현할 수 있습니다.</p><p style="text-align:justify;"> </p><pre><code class="language-javascript">const init = async () => { try { const initialPhotos = await request('all'); // 기본 탭의 사진 데이터 요청 this.setState({ ...this.state, // 기존 상태 유지 photos: initialPhotos, // 초기화된 사진 데이터 저장 }); } catch (error) { console.error('Error loading initial data:', error); // 오류 처리 } }; init(); </code></pre><p style="text-align:justify;"></p><p style="text-align:justify;">위의 코드는 애플리케이션이 로드될 때 실행되고, 데이터를 요청한 후 이를 상태에 저장하고, UI는 변경된 상태를 반영하여 기본 탭의 사진을 렌더링합니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">이 초기화 로직은 상태 관리의 첫 단추를 잘 끼우는 작업입니다. 상태가 정확히 설정되지 않으면, 이후 상태 변경 및 UI 갱신 과정에서도 오류가 발생할 수 있습니다. 리액트의 useEffect처럼 초기 데이터를 설정하고 비동기 처리를 할 수 있지만, 바닐라 자바스크립트에서는 이를 명시적으로 호출해야 한다는 차이점이 있습니다.</p><p style="text-align:justify;"> </p><h4 style="text-align:justify;"><strong>3) 상태 변경과 UI 갱신</strong></h4><p style="text-align:justify;">리액트에서는 상태 변경이 발생하면 Virtual DOM을 활용해 변경된 부분만 효율적으로 갱신합니다. Virtual DOM은 실제 DOM에 변경 사항을 최소한으로 적용하도록 최적화된 방식으로, 개발자가 직접 DOM 조작 로직을 작성하지 않아도 됩니다. 하지만 바닐라 자바스크립트에서는 이러한 자동화가 없으므로, 상태 변경 시 명시적으로 DOM과 상태를 연결하는 로직을 작성해야 합니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">바닐라 자바스크립트에서 상태 변경과 UI 갱신을 처리하기 위해 setState 메서드를 구현할 수 있습니다. 이 메서드는 새로운 상태를 받아 내부 상태를 갱신한 뒤, 상태 변화에 따라 하위 컴포넌트를 업데이트합니다. 아래는 이러한 과정을 보여주는 예제 코드입니다.</p><p style="text-align:justify;"> </p><pre><code class="language-javascript">this.setState = (newState) => { this.state = newState; tabBar.setState(this.state.currentTab); // 탭 UI 갱신 content.setState(this.state.photos); // 사진 UI 갱신 }; </code></pre><p style="text-align:justify;"> </p><p style="text-align:justify;">setState 메서드는 상태를 업데이트하며, UI의 상태를 연결하는 두 가지 작업을 수행합니다. 예를 들어, 사용자가 탭을 변경하면 currentTab 상태가 업데이트되고, 이에 따라 photos 상태도 변경됩니다. 이렇게 변경된 상태는 각각 tabBar와 content 컴포넌트로 전달되어 UI가 새롭게 렌더링 됩니다. 리액트에서는 이러한 상태 변경과 UI 갱신 과정을 Virtual DOM과 Reconciliation 등을 통해 자동화하지만, 바닐라 자바스크립트에서는 이를 명시적으로 처리해야 합니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">따라서 리액트와 비교했을 때, 바닐라 자바스크립트의 접근 방식은 더 많은 작업을 요구하지만, 상태와 UI가 어떻게 연결되는지에 대한 명확한 이해를 제공합니다. 아래와 같은 로직은 상태와 UI를 연결하는 기본 원리를 익히는 데 아주 효과적이며, 이 과정을 통해 리액트의 상태 관리와 UI 갱신 메커니즘이 제공하는 편리함과 최적화의 가치를 더 깊이 이해할 수 있습니다.</p><p style="text-align:justify;"> </p><h4 style="text-align:justify;"><strong>4) 다중 상태 관리</strong></h4><p style="text-align:justify;">리액트의 useState는 여러 상태를 독립적으로 관리하면서도, 상태 간의 의존성을 자연스럽게 처리합니다. 예를 들어, 동물 사진 앨범 애플리케이션에서는 currentTab과 photos가 서로 밀접하게 연결되어 있습니다. </p><p style="text-align:justify;"> </p><p style="text-align:justify;">바닐라 자바스크립트에서는 상태를 객체로 관리하며, 상태 간의 의존성을 처리하는 로직을 명시적으로 작성해야 합니다. currentTab은 사용자가 선택한 탭을 나타내며, 이에 따라 photos 상태가 업데이트됩니다. </p><p style="text-align:justify;"> </p><figure class="image image_resized" style="width:100%;"><img src="https://www.wishket.com/media/news/2967/image3__1_.png"><figcaption><출처: 작가></figcaption></figure><p style="text-align:justify;"> </p><p style="text-align:justify;">예를 들면, 사용자가 ‘판다’ 탭을 클릭하면, currentTab은 ‘판다’로 변경되고, 이 값에 따라 photos 상태가 새로운 데이터로 갱신됩니다. 이러한 상태 간 의존성을 처리하기 위해 이벤트 핸들러와 상태 갱신 로직을 명시적으로 작성해야 합니다.</p><p style="text-align:justify;"> </p><pre><code class="language-javascript">const tabBar = new TabBar({ $app, initialState: this.state.currentTab, onClick: async (name) => { const newPhotos = await request(name); // 새로운 사진 데이터 요청 this.setState({ ...this.state, currentTab: name, photos: newPhotos, }); }, }); </code></pre><p style="text-align:justify;"> </p><p style="text-align:justify;">위 코드는 탭 클릭 이벤트가 발생했을 때 onClick 핸들러를 호출하여 currentTab과 photos 상태를 업데이트하며, 상태가 변경되면 setState 메서드가 호출되고, 변경된 상태를 기반으로 Tabbar와 Content 컴포넌트가 갱신됩니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;"> </p><h3 style="text-align:justify;"><strong>바닐라 자바스크립트 상태 관리의 장점</strong></h3><p style="text-align:justify;">바닐라 자바스크립트로 상태 관리를 구현하는 경험은 리액트와 같은 라이브러리, 혹은 프레임워크가 내부적으로 어떻게 동작하는지 이해하고, 상태 관리의 기본 개념을 체계적으로 익히는 데 매우 유용합니다. 이 과정을 통해 단순히 어떠한 도구를 사용하는 수준을 넘어, 상태 관리의 본질을 깊이 이해하고 응용할 수 있는 능력을 갖출 수 있습니다.</p><p style="text-align:justify;"> </p><h4 style="text-align:justify;"><strong>1) 리액트 동작 원리 이해</strong></h4><p style="text-align:justify;">리액트는 상태 변경 시 Virtual DOM을 활용해 필요한 부분만을 효과적으로 업데이트합니다. 이는 성능 최적화를 위해 매우 중요한 요소이고, 리액트의 주요 강점 중 하나라고 할 수 있습니다. 하지만 이러한 과정을 자동화로만 경험한다면, 그 내부 원리를 완전히 이해하기 어렵습니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">바닐라 자바스크립트로 상태 관리를 직접 구현해 보면, 상태와 UI가 어떻게 연결되고, 어떤 방식으로 UI가 갱신되는지를 명확하게 이해할 수 있습니다. 예를 들어, 바닐라 자바스크립트에서는 상태 변경 후 특정 DOM 요소를 수동으로 업데이트해야 하므로, 리액트가 제공하는 편리함과 최적화의 중요성을 실감할 수 있습니다. 그리고 이를 통해 리액트의 상태 관리와 렌더링 최적화 메커니즘을 더 깊이 이해할 수 있습니다.</p><p style="text-align:justify;"> </p><h4 style="text-align:justify;"><strong>2) 프레임워크 없이 상태를 관리하는 기본기 강화</strong></h4><p style="text-align:justify;">리액트와 같은 프레임워크는 상태 관리와 UI 갱신을 자동화하여 개발을 편리하게 만듭니다. 그러나 이러한 추상화는 기본적인 원리를 배우기 전에 사용된다면, 프레임워크에 과도하게 의존적인 개발자로 성장할 위험이 있습니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">바닐라 자바스크립트를 활용해 상태를 정의하고, 상태 변경에 따른 UI 갱신 로직을 작성하는 과정은 상태 관리의 기본기를 탄탄히 다지는 데 효과적입니다. 이 경험은 리액트뿐 아니라 Vue, Svelte 등 다른 프레임워크를 배울 때도 큰 도움이 됩니다. 또한 프레임워크가 제공하지 않는 상황에서도 유연하게 문제를 해결할 수 있는 역량을 길러줍니다.</p><p style="text-align:justify;"> </p><h4 style="text-align:justify;"><strong>3) 커스터마이징 가능성</strong></h4><p style="text-align:justify;">모든 프로젝트가 리액트 같은 프레임워크를 필요로 하지는 않습니다. 특히 간단한 애플리케이션이나, 특정 환경에서는 리액트의 추상화된 상태 관리 방식이 오히려 불필요한 복잡성을 불러올 수 있죠.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">바닐라 자바스크립트로 상태를 관리하면, 프로젝트의 요구사항에 맞게 로직을 완전히 커스터마이징할 수 있습니다. 예를 들어, 소규모 프로젝트에서는 상태 관리와 UI 업데이트를 단순화하여 성능과 개발 속도를 모두 최적화할 수 있는데요. 리액트의 상태 관리 방식이 적합하지 않은 프로젝트 환경에서는 바닐라 자바스크립트를 활용한 방식이 더 적합할 때도 많습니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;"> </p><h3 style="text-align:justify;"><strong>마치며</strong></h3><p style="text-align:justify;">바닐라 자바스크립트를 통해 상태 관리의 기본기를 배우는 과정은 단순히 리액트를 대체하기 위한 것이 아닙니다. 이는 상태와 UI를 연결하는 원리를 깊이 이해하고, 개발자로서의 기본기를 강화하는 데 중점을 둔 학습 과정입니다. 이러한 경험은 리액트뿐만 아니라, 다른 프레임워크와 라이브러리를 사용하는 데도 큰 도움이 됩니다.</p><p style="text-align:justify;"> </p><p style="text-align:justify;">결국 바닐라 자바스크립트를 활용한 상태 관리 학습은 개발자들에게 더 나은 설계를 고민하게 하고, 다양한 환경에서 문제를 해결할 수 있는 역량을 키워줍니다. 그리고 단순히 도구를 사용하는 개발자가 아닌, 도구의 한계를 넘어설 수 있는 개발자로 성장할 수 있도록 도와줄 겁니다.</p><hr><p style="text-align:justify;"><참고></p><p style="text-align:justify;">인프런 - <a href="https://inf.run/WfRmY"><u>한 번에 끝내는 자바스크립트</u></a></p><p style="text-align:justify;"> </p><p style="text-align:center;"><span style="color:#999999;">©️요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.</span></p>