본문 바로가기
Javascript/상태관리

[Redux] 리덕스 기본구조 이해하기

by codnjs779 2021. 11. 12.

 미루고 미뤘던,,, 리덕스 공부를 다시 시작했다. 전에 인강 살짝씩 들었을때 음.,,,, 뭔말인지 정말 이해가 안가서 이번에 공부를 시작하기 전에 많이 위축돼 있었는데 제로초님 인강 듣고 조금은 이해가 갔다. (다행,,, 계속 이해 안될까봐 걱정했는데😂)

강의 내용을 바탕으로 리덕스를 왜 사용하는지, 기본 구성을 어떻게 만들어야 하는지에 대해 정리하려고한다.

 

 

리덕스는 어떤 상황에서 써야할까? 


 리액트를 사용해서 프로젝트를 만들다 보면 props로 데이터를 넘겨받는데 한계가 있다. 부모-> 자식으로 넘겨주는 구조인데, 만약  ... ->조부모-> 부모 -> 자식 ->... 이런식으로 과정이 늘어날 경우에는? 
 그리고 만약 조부모의 데이터 요소를 자식요소에서 사용해주기 위해 일부러 부모요소까지 거쳐서 자식에게 데이터를 나눠줘야하는 상황이 발생할 수 있다. 비효율적인 일을 줄여주고 전역에서 데이터를 쉽게 관리할 수 있도록 하기위해 리덕스를 사용한다. 또한, 리덕스는 상태관리 도구이다. 리덕스에 컴포넌트를 모아서 관리하기 때문에 리덕스를 사용하면 state를 안써줘도 되는 경우도 발생한다. (그렇다고 state가 필요 없다는게 아님! 필요한 상황이 있을때는 사용해야함) 

 

 

 

리덕스 작동 원리

리덕스의 작동원리

 

action에 바뀌었으면 하는 내용을 담아줌 -> dispatch를 한다 -> state에 담긴 상태들이 변화한다. 

위의 그림에서 표현한대로 하면 a를 b로 변경하는 것이다. 

dispatch를 하면 과거의 기록부터 계속 쌓이면서 남기 때문에 거슬러 올라갈 상황일 때 매우 유용하다.

이런식으로 동작을 하다보면 단점이 있는데, 미리 액션들을 만들어 둬야하고 객체를 매번 새로 만들어 줘야한다는 점이다.  

 

 

 

리덕스 코드

 

1. 초기값 설정해주기 
const {createStore} = require('redux');

const initialState = {
    compA:'a',
    compB:12,
}

 

2. store 생성해주기
const store  = createStore(reducer,initialState);

스토어는 데이터들의 묶음이기 때문에 2번째 인자로 initialState가 들어간다. 

 

 

3. action함수 생성하기
const changeCompA = (data) => {
    return{
        type: 'CHANGE_COMP_A',
        data,
    }
}

const changeCompB = (data) => {
    return{
        type: 'CHANGE_COMP_B',
        data,
    }
}

type은 액션의 이름이다. data부분에 직접적으로 기본값을 바꾸는 내용이 들어갈 수 도 있다. 예를 들면, 

data: 'b' 이런식으로! 그렇지만 만약 다른 내용으로 변경하고 싶으면 계속 변수명을 지어서 해줘야하고 확장성이 떨어지기 때문에 확장성 있게 액션함수를 쓰려면 data를 인자로 받아서 dispatch에서 해당 액션을 실행할때 넘겨주면 그 인자를 dispatch가 Reducer에 넘겨주게 된다. 아래와 같은 형태로 쓰면 된다. 

 

store.dispatch((changeCompA('b')));
store.dispatch((changeCompB(20)));

 

4. 리듀서

리듀서는 새로운 state를 만들어주는 역할을 한다. 

const reducer = (prevState, action) => {

    switch(action.type) {
        case 'CHANGE_COMP_A':
            return{
                ...prevState,
                compA:action.data,
               
            };
            
         case 'CHANGE_COMP_B':
               return {
                   ...prevState,
                    compB:action.data,   
                };
                
                default:
                    return prevState;
    }
};

각 액션마다 바뀐 내용이 다르다. 'CHANGE_COMP_A' 는 'a' -> 'b' 로 변경,  'CHANGE_COMP_B' 는 12 -> 20으로 변경

의 내용이 들어간다. 그때마다 모든 부분을 수정해주는게 아니라 이전 내용을 스프레드 연산자를 사용해서 기억하고 있다가, 해당 액션이 작동할 때 바뀐부분만 변경해주면 된다.  

 

 

5. 전체코드
const {createStore} = require('redux');

//리듀서
const reducer = (prevState, action) => {
    switch(action.type) {
        case 'CHANGE_COMP_A':
            return{
                ...prevState,
                compA:action.data,
               
            };
            case 'CHANGE_COMP_B':
                return {
                    ...prevState,
                    compB:action.data,
                    
                };
                default:
                    return prevState;
    }
};

//초기값
const initialState = {
    compA:'a',
    compB:12,
}


//스토어 생성
const store  = createStore(reducer,initialState);


//액션함수
const changeCompA = (data) => {
    return{
        type: 'CHANGE_COMP_A',
        data,
    }
}

const changeCompB = (data) => {
    return{
        type: 'CHANGE_COMP_B',
        data,
    }
}


store.dispatch((changeCompA('b')));
store.dispatch((changeCompB(20)));