콘텐츠로 건너뛰기

[Reactjs] 리액트 정리 1편 : redux project 소개(1)

2020년에 쓴 이 리액트 리덕스 코드는 2026년 9월 기준 React 19.3 에서 그대로 돌지 않습니다. ReactDOM.render 가 React 19 에서 제거됐고 hashHistory, IndexRoute 는 React Router v3 시절 API 라서, 바꾼 코드를 4절에 정리했습니다. 리덕스를 쓰는 이유와 데이터 흐름 설명은 지금도 유효합니다.

필자가 리액트와 리덕스를 처음 써 보게 된 과정

안녕하세요? 정리하는 개발자 워니즈 입니다. 필자가 초년 개발자 시절에는 프론트엔드를 주로했었습니다. 프론트엔드라곤 하지만 운영프로젝트에 소속이 되어서 자바스크립트 를 활용하여 소소하게 기능 수정을 하는 수준이였습니다.

그러던 중, reactjs 라는 것을 알게되었고 17년 4월즈음에는 5일짜리 교육도 다녀왔었습니다. 리액트 js의 가장 기초적인 부분을 배웠지만, 기존에 개발하던 방식과는 사뭇 달랐습니다.

콤포넌트들을 만들어두고 그것을 마치 레고 블록 조립하듯이 화면을 개발해가는 과정이였습니다.

급하게나마 리액트 & 리덕스를 사용해본 내용을 정리해보고자 합니다.

지난 글들은 아래를 참고 해주시면 됩니다.

Reactjs 리액트 정리 1편 : redux project 소개(1) 설명 이미지 1

1. 리덕스를 사용하는 이유?

리액트만 사용하면 되지 리덕스까지 같이 사용할 필요가 있을까? 라는 생각을 했었습니다. 그런데 요즘의 웹의 추세는 빠른 속도로 사용자에게 제공을 해주어 만족도를 높여야 합니다. 그러기 위해서는 DOM 구조의 특성을 봐야 합니다.

Reactjs 리액트 정리 1편 : redux project 소개(1) 설명 이미지 2

  • 왼쪽의 그림에서 보이시는 것처럼 root component에서 제일 최하위 컴포넌트까지 변화를 일으키기 위해서 거쳐가야될 수많은 컴포넌트들이 있습니다. 한개를 업데이트 하기 위해서는 비효율적인 상태 변경을 보입니다 .
  • 리덕스의 가장큰 장점은 명확하게 상태를 관리한다는 것입니다. Store라는 객체를 사용하여 상태 저장소처럼 사용을 하고 모든 컴포넌트들은 이 Store의 변경에 따라서 자신의 컴포넌트 상태를 개별로 업데이트 합니다.

Reactjs 리액트 정리 1편 : redux project 소개(1) 설명 이미지 3

  • 리덕스를 사용하는 또하나의 가장큰 이유는 상태 변경에 대한 시간 여행이 가능하다는 부분이다. 리덕스로 만들어진 앱은 모든 상태들의 변경에 대해서 내부적으로 이력관리를 하고 있습니다. 그렇기 때문에 버그를 찾는 부분에서 굉장히 수월해집니다.

2. 리덕스로 진행중인 앱 소개

wonizz github

  • Project Structure
.
├── build                    # 전체 소스 빌드
├── public                   # Main HTML page and Static public assets 
├── src                      # Application source code
│   ├── components           # Global Reusable Components
│   │   └── Article          # PD page all component
│   │   └── Home             # Home page all component
│   ├── constants            # action 정의서 
│   ├── reducers             # all reducers definition
│   │   ├── createStore.js   # Create and instrument redux store
│   │   └── reducers.js      # Reducer registry and injection
│   └── agent.js             # 외부 API 연계 호출 (데이터)
│   └── index.js             # 페이지 Router 정의 

필자의 소스를 완벽히 공유할 순 없지만, 만들어진 소스에 대한 소개를 해보려고 합니다.

크게는 2개의 폴더로 보시면 됩니다 .

  • public – Main HTML (index.html)
  • src – App source

3. 컴포넌트 구조

  • Component Structure
├── src                      # Application source code
│   ├── components           # Global Reusable Components
│   │   └── Article          # PD page all component
│   │   └── Home             # Home page all component
│   │        └── index.js    # Home page default component 
│   ├── constants            # action 정의서 
│   ├── reducers             # all reducers definition
│   │   ├── createStore.js   # Create and instrument redux store
│   │   └── reducers.js      # Reducer registry and injection
│   │   └── articleList.js   # 제품 목록 노출 reducer
│   └── agent.js             # 외부 API 연계 호출 (데이터)
│   └── index.js             # 페이지 Router 정의 

위의 소스중에서 Router 가 정의된 index.js에 대해서 먼저 보겠습니다.

  • Router index.js
ReactDOM.render((
  
    
      
        
      
    
  
), document.getElementById('root'));

2026년 9월 기준으로 보면 이 코드는 React 19 에서 동작하지 않습니다. ReactDOM.render 는 React 18 에서 deprecated 된 뒤 React 19 에서 제거됐고, hashHistory 와 IndexRoute 는 React Router v3 까지의 API 입니다. 지금 방식으로 바꾼 코드는 4절에 적었습니다.

웹페이지가 호출되면, IndexRouter 인 Home 컴포넌트가 호출이 됩니다.

  • Home > index.js
  componentWillMount() {
    const tab = this.props.token ? 'feed' : 'all';
    const articlesPromise = this.props.token ?
      agent.Articles.feed :
      agent.Articles.all;
    this.props.onLoad(tab, articlesPromise, Promise.all([agent.Tags.getAll(), articlesPromise()]));
  }

참고로 componentWillMount 라는 이름은 지금 deprecated 이고, 공식 문서에서는 UNSAFE_componentWillMount 로 이름이 바뀌었습니다. API 호출 같은 부수효과는 componentDidMount 로 옮기라고 안내합니다.

Home에서 default component 인 index.js가 호출이 될 것이고, 그중에서더 위의 부분과 같이 componentWillmount 함수가 호출되는 시점을 확인해보겠습니다.

Home 페이지가 노출이 될 때, Main List들이 노출이 되어야 되는데 이부분을 API를 통해서 가져오는 부분입니다. 현재는 위와 같이 this.props.onLoad 의 함수가 호출이 됨과 동시에 props에 있는 onLoad함수를 호출합니다.



const mapDispatchToProps = dispatch => ({
  onClickTag: (tag, pager, payload) =>
    dispatch({ type: APPLY_TAG_FILTER, tag, pager, payload }),
  onLoad: (tab, pager, payload) =>
    dispatch({ type: HOME_PAGE_LOADED, tab, pager, payload }),
  onUnload: () =>
    dispatch({  type: HOME_PAGE_UNLOADED })
});

그러면 `HOME_PAGE_LOADED’ 라는 타입으로 reducer에게 store를 업데이트 하도록 전달합니다.(dispatch)

  • redcucer > articleList.js
case HOME_PAGE_LOADED:
      return {
        ...state,
        pager: action.pager,
        tags: action.payload[0].tags,
        articles: action.payload[1].articles,
        articlesCount: action.payload[1].articlesCount,
        currentPage: 0,
        tab: action.tab
};

위에 보시는것처럼 HOME_PAGE_LOADED 타입으로 전달이 될 때, state에다가 각 객체들을 담아 둡니다.
그리고나서 Home의 index.js 에서 mapStateToProps 를 통해서 모든 상태를 props로 전달합니다.

  • ArticleList.js (view component)

위에서 전달된 pros를 아래와 같이 viewing component에서는 그냥 노출만 하면됩니다.

{ props.articles.map(article => { return ( ); }) }

4. 2026년 9월 기준으로 다시 쓰면 코드가 어떻게 바뀌나요?

리덕스로 상태를 한곳에 모으고 컴포넌트는 그 상태를 그리기만 한다는 구조는 그대로입니다. 바뀐 것은 앱을 화면에 붙이는 방법, 라우터, 라이프사이클 메서드 이름입니다. npm 레지스트리와 공식 문서를 2026년 9월 28일에 다시 확인한 값입니다.

항목 이 글(2020년) 2026년 9월 기준
React ReactDOM.render 로 렌더링 react 19.3.0 (2026-09-09), createRoot 사용
라우터 hashHistory, IndexRoute (React Router v3 API) react-router 8.4.0 (2026-09-15), createHashRouter 와 index 라우트
데이터 불러오는 시점 componentWillMount UNSAFE_componentWillMount 로 이름 변경, 부수효과는 componentDidMount
react-redux Provider, connect react-redux 9.3.0 (2026-05-15), Provider 는 그대로, 훅 API 를 기본 권장
새 프로젝트 시작 본문 언급 없음 Create React App 은 2025-02-14 신규 앱용 지원 중단 발표, 프레임워크나 Vite, Parcel, RSBuild 안내

ReactDOM.render 는 React 19 에서 무엇으로 바꾸나요?

react-dom/client 의 createRoot 로 바꿉니다. React 19 업그레이드 가이드는 ReactDOM.render 를 제거했다고 밝히고, 루트를 먼저 만든 뒤 그 루트의 render 를 부르는 방식으로 옮기라고 안내합니다.

hashHistory 와 IndexRoute 는 지금 어떻게 쓰나요?

React Router 8.4.0 에서는 createHashRouter 로 라우터를 만들고, IndexRoute 자리는 index: true 인 자식 라우트가 대신합니다. 3절의 index.js 를 지금 방식으로 옮기면 아래와 같습니다.

import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import { createHashRouter } from 'react-router';
import { RouterProvider } from 'react-router/dom';

// App 컴포넌트 안에서 <Outlet /> 을 렌더링해야 Home 이 들어갑니다.
const router = createHashRouter([
  {
    path: '/',
    Component: App,
    children: [{ index: true, Component: Home }],
  },
]);

ReactDOM.createRoot(document.getElementById('root')).render(
  <Provider store={store}>
    <RouterProvider router={router} />
  </Provider>
);

스토어를 만드는 쪽의 변화(createStore 와 Redux Toolkit)는 리덕스 프로젝트 소개 2편의 4절에, props 와 state 의 차이는 리액트 state 와 props 정리에 이어서 적었습니다. 컴포넌트를 나누는 요즘 방식이 궁금하시면 리액트 설계 패턴 책 서평도 참고가 될 것 같습니다.

5. 마치며..

위의 내용에서 보이시는 것처럼 한눈에 보이시나요? 리덕스의 가장큰 단점! 이라고 생각하면 러닝 커브가 있다는 것입니다. 개념에 대해서 완벽히 숙지하고 익히지 않으면, 내용이 다소 어려울 수 있습니다. 그런데 기본적으로 reducer, store, component 정도의 개념만 있으면 우선 반은 성공한거라고 생각합니다.

component에서 액션이 일어나면, reducer에게 전달이 되고, store를 업데이트 한 뒤, 다시 상태변경에 대해서 component에서 변경을 해주면 됩니다.

다음시간에는 리액트 소스를 빌드 해 서, S3로 웹호스팅 해보는 방법에 대해서 올리도록 하겠습니다.

이 글을 쓴 사람

인프라와 DevOps를 실무로 다루면서 겪은 것을 기록합니다. Docker, Kubernetes, AWS, 그리고 AI 도구를 실제로 써 보고 남기는 로그입니다.

Threads·X

새 글이 올라오면 Threads @wonizz.ai 에도 올립니다. 팔로우해 두면 피드에서 바로 볼 수 있습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다