Redux

2023. 2. 1. 11:11개발/실무용 메모

Redux

Redux 로 상태 관리 하기

Redux 란?

  • 프로젝트 규모가 커지거나, 관리해야 할 상태 (State)가 많아질때, 혹은 컴포넌트 구조가 복잡해질때 보다 쉽게 상태관리를 하기 위해서 사용.
  • 예시 이미지 (출처 : 링크)

Redux 에서 사용되는 키워드

  • Action, Reducer, Store 핵심 3가지 + dispatch, Subscribe 추가 키워드 2가지

액션 (Action)

  • 상태에 어떠한 변화가 필요할때, 발생시킴. 하나의 객체로 표현됨.
  • "액션 타입 선언"과, "액션 생성 함수"를 만든뒤 상태변화가 필요할때 dispatch를 통해 reducer로 보내주는 구조.
  • 액션 생성자를 통해 액션 객체를 만들고 리덕스 스토어로 보냄
  • 리덕스 스토어가 액션 객체를 받으면 스토어의 상태값이 변경됨, 액션은 스토어에 데이터를 넣을수 있는 유일한 방법
  • 예제소스
    • 액션 타입 선언
    //type 필드만 반드시 포함해야 하는 필수 프로퍼티이고, 나머지는 마음대로 정의
    {
    	type: "ADD_TODO"
    }
    
    {
    	type: "ADD_TODO",
    	text: "리덕스 배우기"
    }
    
    • 액션 생성자(액션 생성 함수)
    // actions.js
    // 액션 생성자
    // 다른 컴포넌트에서 쉽게 액션을 발생시키기 위해 사용하는 용도 
    // -> 따라서 export 키워드로 다른 파일에서 사용 가능하도록 해줌
    // 액션 생성함수를 사용하는것이 필수는 아님, 액션 발생시킬때마다 직접 액션 객체를 생성해도 무관
    export function addTodo(text) {
      return { 
    		type: "ADD_TODO", 
    		text 
    	}; 
    }
    
    // 화살표 함수로도 작성가능
    const addTodo = (text) => ({
    	type: "ADD_TODO",
    	text
    });
    

리듀서 (Reducer)

  • 리듀서는 현재상태와, 액션 두가지의 파라미터를 전달받아 다음 상태를 반환하는 순수 함수
  • 예제소스
// reducer.js
import { ADD_TODO } from './actions';

const initialState = {
	text : '',
}

export function todoApp(state = initialState, action) {
	if(action.type === "ADD_TODO") {
		return Object.assign({},state,{text : action.text})
	}
}
  • 리듀서 분리 및 합치기 (리듀서 리팩토링 예제 링크)
    function counter(state, action) {
      
      switch(action.type) {
        case INCREMENT:
          return state+1
        case DECREMENT:
          return state-1 
        defualt:
          return state
      }
    }
    
    function logged( state, action) {
      switch(action.type) {
        case LOG_IN:
          return true
        case LOG_OUT:
          return false
        default:
          return false
      }
        
    }
    
    export default function reducer(state = initalState, action) {
      return {
        counter : counter(state.number, action),
        isLogged: logged(state.isLogged, action)
      }
    }
    
    • 리덕스에서 제공하는 CombineReducer 함수를 사용하면 다음과 같이 재작성 가능
    export default function reducer(state = initalState, action) {
      return {
        counter : counter(state.number, action),
        isLogged: logged(state.isLogged, action)
      }
    }
    
    ==============================================================
    import { combineReducers } from 'redux';
    
    const counter_logged = combineReducers({
      counter,
      logged
    });
    
    export defualt counter_logged;
    
export const LOG_IN = 'log/IN'
export const LOG_OUT = 'log/OUT'

export const INCREMENT = 'counter/INCREMENT';
export const DECREMENT = 'counter/DECREMENT';


const initialState = {
  isLogged : true,
  number : 0
}

export const login = () => ({ type: LOG_ON })
export const logout = () => ({ type: LOG_OUT })
export const increase = (value) => ({ type: INCREMENT })
export const decrease = (value) => ({ type: DECREMENT })

export default function reducer(state = initalState, action) {
  
  switch(action.type) {
    case INCREMENT:
      return { number: state.number+1 }
    case DECREMENT:
      return { number: state.number-1 }
    case LOG_IN:
      return { isLogged : true }
    case LOG_OUT:
      return { isLogged : false }
    default:
      return state
  }

}

스토어 (Store)

  • 하나의 앱에서 하나의 스토어만 사용하는것을 지향
  • 디스패치 (dispatch)
    • 디스패치는 스토어의 내장함수중 하나이며, 액션을 파라미터로 전달함. → 스토어는 리듀서 함수를 실행시켜서 해당 액션을 처리하는 로직을 실행하여 새로운 상태를 만듦.
  • 구독 (subscribe)
    • 구독도 디스패치처럼 스토어의 기본 내장함수
    • 'Dispatch' 를 통해 전달된 'Action'을 'Reducer' 가 받아 'Store' 에 있는 state를 변경시킬때 마다 'Subscribe' 은 변화를 감지함
  • 예제 소스
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { increase, decrease, login, logout } from 'store/actions/counter' 
import store from 'store'

console.log(store.getState());

// 상태가 바뀔때마다 기록
let unsubscribe = store.subscribe(() =>
  console.log(store.getState())
);

// 액션들을 보냄
store.dispatch(increase());
store.dispatch(decrease());
store.dispatch(login());
store.dispatch(logout());

// 상태 변경을 더 이상 받아보지 않음
unsubscribe();

class App extends Component {
  render() {
    return (
      <div> </div>
    )
  }
}

export default App;

'개발 > 실무용 메모' 카테고리의 다른 글

RadixUI  (0) 2023.02.01
ReScript  (0) 2023.02.01
React  (1) 2023.02.01
Rendering  (0) 2023.02.01
SSR - Next.j  (0) 2023.02.01