본문 바로가기

Libraries/Redux

[Redux] redux-actions

728x90

 

redux-actions에 대해서 알아보자!

 


 

 

 1. FSA (Flux Standard Action) 

 

- Flux 아키텍처의 Action 객체를 위한 하나의 표준이다.
- Action 객체에 표준화된 규칙을 적용해서 체계적으로 관리하기 위한 목적으로 만들어졌다.


 

 (1) FSA가 적용된 Action 객체 

 

{
	type: 'ADD_TODO',
	payload: {
		text: 'Do something.'
	}
}

 

 

 (2) 규칙 

 

- Action은 반드시 일반적인 자바스크립트 객체 형태여야 한다.
- type 프로퍼티를 가진다. (필수)
- error, payload, meta 프로퍼티를 가질 수 있다. (옵션)
이것들 외의 프로퍼티는 가질 수 없다.

 

type: 액션의 성질을 나타냄. 해당 액션으로 상태가 어떻게 변할 것인가

payload: 액션에 함께 실어 보낼 데이터. 규약상 error가 true일 경우, payload는 반드시 에러 객체여야 한다.

error: 액션이 에러인지 여부를 나타내는 boolean 속성

meta: payload와 별개로, 액션에 대한 메타 데이터를 나타내기 위한 속성. 어떤 종류의 값이든 될 수 있다.

 

 


 

 

 2. redux-actions 

 

리덕스를 위한 FSA(Flux Standard Action)을 적용하기 쉽게 도와주는 라이브러리

  

 


 

 

 3. redux-actions 주요 API 

 

 (1) createAction(s) 

액션 생성자 함수를 만들어 준다.
파라미터로 액션 타입을 넣어주면, 해당하는 액션 타입을 가진 액션 생성자 함수를 만들어서 리턴한다.
그리고 이 액션 생성자 함수를 호출하면 액션 객체가 생성된다.

 

createAction() 예시 코드

export const increase = createAction('INCREASE');
export const decrease = createAction('DECREASE');

increase();          // { type: 'INCREASE' }
decrease();          // { type: 'DECREASE' }
increase(10);        // { type: 'INCREASE', payload: 10 }
decrease([10, 20]);  // { type: 'DECREASE', payload: [10, 20] }

 

createActions() 함수는 여러 개의 액션 생성자 함수를 한 번에 만들 수 있게 해준다.

파라미터로 actionMap을 받는다.actionMap의 key는 액션 타입이 되고, value에는 payload creator 함수가 들어간다.(payload creator 함수는 액션 객체에 함께 실려보낼 payload 객체를 만들어주는 함수임)

호출된 createActions() 함수는 액션 생성자 함수들이 들어있는 객체를 리턴한다.

 

createActions() 예시 코드

const { increase, decrease } = createActions({
		INCREASE: (amount) => {
				return { amount };
		},
		DECREASE: (amount) => {
				return { amount };
		},
});

 

결론적으로 createAction(s) 함수를 사용해서 만들어진 액션 생성자 함수를 호출하면Flux Standard Action 규칙을 준수하는 액션 객체들이 만들어진다.

 

 

 (2) handleAction(s) 

액션을 핸들링(처리)하기 위한 함수.즉, handleAction() 함수의 역할은 리듀서를 생성하는 것이다.

 

handleAction() 예시 코드

const reducer = handleAction(
	'INCREASE',
	(state, action) => {
			return {
				count: state.count + action.payload.amount
			}
	},
	{ count: 0 } // defaultState
);

 

<코드 설명>

액션 타입(INCREASE)에 대한 리듀서를 생성해서 리턴한다.

첫 번째 파라미터로 액션 타입이 들어가고,두 번째 파라미터로 실제 액션을 처리하기 위한 리듀서 함수가 들어간다.세 번째 파라미터로는 초깃값을 나타내는 defaultState가 들어간다.

handleAction() 함수를 호출하면 해당 액션 타입을 처리하는 리듀서 함수를 리턴한다.

 

handleActions() 예시 코드

여러 개의 액션에 대한 리듀서를 만들어주는 함수

const reducer = handleActions(
	{
		INCREASE: (state, action) => {
			return {
				count: state.count + action.payload.amount
			};
		},
		DECREASE: (state, action) => {
			return {
				count: state.count + ction.payload.amount
			};
		},
	},
	{ count: 0 }  // defaultState
};

 

<코드 설명>

첫 번째 파라미터로 reducerMap이 들어가고, 두 번째 파라미터로 defaultState(초깃값)이 들어간다.
(이 때, reducerMap의 key는 액션 타입, value는 리듀서 함수임)
함수를 호출하면 액션들을 모두 처리할 수 있는 리듀서 함수를 리턴하고,이 리듀서를 Redux Store에 넣어서 사용할 수 있다.

 

 

 (3) combineActions 

액션 타입 또는 액션 생성자 함수들을 하나로 합쳐주는 함수.파라미터로 합칠 액션 타입 또는 액션 생성자 함수들을 넣어준다.createActions() 함수로 만든 액션 생성자 함수들을 combineActions() 함수의 파라미터로 넣을 수 있다.

 

예시 코드

const reducer = handleActions(
	{
		[combineActions('INCREASE', 'DECREASE')]: (state, action) => {
			return {
				count: state.count + action.payload.amount
			};
		},
	},
	{ count: 0 }  // defaultState
);

 

 


 

 

 4. redux-actions을 적용하는 전체 과정 

 

// 필요한 함수들을 redux-actions 패키지로부터 import
import { createActions, handleActions, combineActions } from 'redux-actions';

// createAction() 함수로 액션 생성자 만들기
// 두 가지 액션 타입(increase, decrease)에 대한 액션 생성자를 생성함
const { increase, decrease } = createActions({
    INCREASE: (amount) => {
        return { amount };
    },
    DECREASE: (amount) => {
        return { amount };
    },
});

// handleActions() 함수와 combineActions() 함수를 사용해서
// increase, decrease를 처리할 수 있는 리듀서를 생성
const reducer = handleActions(
    {
        [combineActions(increase, decrease)]: (state, action) => {
            return {
                count: state.count + action.payload.amount
            };
        }
    },
    defaultState
);

// 외부에서 가져다쓸 수 있도록 export 하고, 실제 리덕스 Store에 넣어준다.
export default reducer;

 

 


 

5. Todo 프로젝트에 react-actions 적용하기 

 

*참고  (아래 게시글에서 이어지는 코드입니다.)

https://dev-ini.tistory.com/286

 

[Redux] Redux로 프로젝트 시작하는 법 (간단한 Todo 프로젝트 만들어보기)

Redux랑 React 연동해서 간단한 프로젝트를 만들어볼 것이다.   * 필자는 Vite를 사용하여 React 개발 환경을 설정하였다. (참고 ) https://dev-ini.tistory.com/58)* Toolkit은 사용하지 않은 버전이다. 추후 학

dev-ini.tistory.com

 

 

 (1) 터미널에 명령어를 입력해서,redux actions 패키지를 설치한다. 

npm install --save redux-actions

 

완료 후 터미널 화면

 

package.json

 

 

 (2) src > redux 안에 actions 폴더를 만들고, todoAction.js 파일을 만든 후 아래와 같이 작성한다. 

todoAction.js

import { createActions, handleActions } from 'redux-actions';

const initialState = [];

export const { addTodo, removeTodo, removeAll } = createActions({
    ADD_TODO: (text) => {
        return { text };
    },
    REMOVE_TODO: () => {
        return {};
    },
    REMOVE_ALL: () => {
        return {};
    }
});

const reducer = handleActions(
    {
        [addTodo]: (state, action) => {
            return state.concat(action.payload.text);
        },
        [removeTodo]: (state) => {
            return state.slice(0, -1);
        },
        [removeAll]: () => {
            return [];
        }
    },
    initialState
);

export default reducer;

 

 

(3) src > redux > reducers > index.js 파일을 다음과 같이 수정한다.

import { combineReducers } from "redux";
// import todoReducer from "./todoReducers";
// import todoReducer from "../ducks/todoDock";
import todoReducer from "../actions/todoAction"; // 이렇게 작성


const rootReducer = combineReducers({
    todo: todoReducer, 
});

export default rootReducer;

 

 

 (4) src > redux > containers > TodoAppContainer.js 파일을 다음과 같이 수정한다. 

import { connect } from "react-redux";

// import { addTodoActionCreator, removeAllActionCreator, removeTodoActionCreator } from "../actions";
// import { addTodoActionCreator, removeAllActionCreator, removeTodoActionCreator } from "../ducks/todoDock";
 import {
     addTodo as addTodoActionCreator,
     removeTodo as removeTodoActionCreator,
     removeAll as removeAllActionCreator
 } from "../actions/todoAction";

import TodoApp from "../../components/TodoApp";

function mapStateToProps(state) {
  return {
    todoItems: [...state.todo, ...(state.fetchTodos?.data || [])], 
  };
}


function mapDispatchToProps(dispatch) {
  return {
    addTodo: (text) => {
      dispatch(addTodoActionCreator(text));
    },
    removeTodo: () => {
      dispatch(removeTodoActionCreator());
    },
    removeAll: () => {
      dispatch(removeAllActionCreator());
    },
  };
}


export default connect(mapStateToProps, mapDispatchToProps)(TodoApp);

 

이렇게 하면 적용이 완료된다!

728x90