안녕하세요!

FE 개발자 유진주입니다.

Web/React

[처음 만난 리덕스] 2. Redux 시작하기

ypearl 2023. 12. 25. 02:04

Redux 구성 요소

  • Store(스토어)
    : Redux의 데이터들을 저장하기 위한 저장소
  • State
    : Redux Store에 저장되어 있는 데이터
  • Action(액션)
    : Redux Store에 저장된 데이터에 변화를 주기 위한 행동
     (JavaScript 객체 형태로 존재)
  • Action 생성자
    : Action 객체를 생성하는 역할을 하는 함수
  • Reducer
    : 입력에 어떤 처리를 해서, 원하는 결과로 축소시키는 과정
    = Action이 발생하면, Action을 실제로 처리하는 역할을 하는 함수

 

Immutability (불변성)

: 리덕스 원칙 중

2. State is read-only

3. Changes are made with pure functions

 

=> Redux State 생성 후에는 값을 바꿀 수 없다!

 

 

Redux를 사용해야 하는 경우

1. 하나의 상태를 여러 컴포넌트에서 접근해야 할 경우

예) 로그인 여부

 

 

2. 한 곳에서 상태들을 관리하고 싶을 경우

*그렇다고, 모든 state를 Redux Store에 넣는 것이 정답은 아님

=> 꼭 필요한 state들만 Redux를 통해 관리하자!

 

 

Redux vs Context API

Context API?

React 컴포넌트들 사이, 데이터를 기존의 props를 통해 전달하는 방식대신,

컴포넌트 트리를 통해 곧바로 컴포넌트로 전달하는 새로운 방식 제공
(어떤 컴포넌트든지 데이터에 쉽게 접근 가능)

 

기존 방식 vs Context 사용 방식

 

- 여러 개의 Component들이 접근해야 하는 데이터일 때 사용
예) 로그인 여부, 로그인 정보, UI 테마 등의 데이터

 

 

공통점

- Prop Drilling 문제를 해결하기 위한 방법

* Prop Drilling: 여러 단계에 걸쳐 Props를 통해 데이터를 전달하는 것

 

 

차이점

1. redux-devtools

: 모든 상태 변화를 시각적으로 확인할 수 있게 해주고,

  이전 상태로 돌아가 하나씩 액션을 실행하며 디버깅할 수 있음

 

2. Context API는 특정 Context에 의존하는 컴포넌트들을 분리 가능

: 해당 Context와 관련이 없는 컴포넌트는 애초에 데이터에 접근이 불가능해지기에

  의도치 않게 발생할 수 있는 사이드 이펙트를 사전에 방지할 수 있음

 

3. 데이터 처리 방식

  • Redux: 전체 애플리케이션 데이터를 Redux Store라는 하나의 거대한 객체로 관리
    - 사전에 정의된 Action과 Reducer를 통해서만 상태 변경 가능
  • Context: 오로지 하나로 구성되어 있지도 않고, 데이터를 별도로 관리하지도 않음
    - Context는 State를 들고 있는 것이 아닌, State를 전달하기 위한 통로의 역할만 함

 

Redux와 Context의 데이터 처리 방식 차이

 

그럼 둘 중 무엇을 사용해야 하는가?

: 상황에 따라 판단

 

  • 규모 ↑, 상태 ↑ → Redux
  • 규모 ↓, 상태 ↓ → Context API

 

 

[실습] Counter 애플리케이션 만들기

- HTML에서 JS와 Redux만을 이용해서 진행

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>처음 만난 리덕스 - Counter</title>
</head>
<body>
    <p>Counter: <span id="value">0</span></p>
    <div>
        <button id="increment">+</button>
        <button id="decrement">-</button>
    </div>

    <script>
        function counter(state, action){ // Reducer: 현재 State와 Action 객체를 받아 변경된 새로운 State를 리턴
            if(typeof state ==="undefined"){
                return 0;
            }

            switch(action.type){
                case "INCREMENT":
                    return state +1;
                case "DECREMENT":
                    return state -1;
                default:
                    return state;

            }
        }

        var store = Redux.createStore(counter); // createStore 함수를 통해 Store 생성
        var valueElem = document.getElementById("value"); // value id를 가져옴

        function render() { // render 함수: Redux Store에 있는 count값을 valueElement에 넣음
            valueElem.innerHTML = store.getState().toString(); // store.getstate 함수 - Redux Store의 전체 State 가져옴
        }

        render();
        store.subscribe(render); // Redux Store의 State가 변경될 때마다 render 함수 호출

        // 실제 Redux Action을 Dispatch하는 코드
        document
            .getElementById("increment") // 버튼 element 가져와 클릭 이벤트 리스너 추가
            .addEventListener("click", function() {
                store.dispatch({type: "INCREMENT"}); // 액션 타입
            });
       
        document
            .getElementById("decrement")
            .addEventListener("click", function() {
                store.dispatch({type: "DECREMENT"});
            });
    </script>
</body>
</html>

 

 

실행 결과