오브젝트 타입 state, Redux로 CRUD 구현하기

YUKI KIM·2021년 12월 21일
1

최근에 토이 프로젝트를 하고 있는데 있는데 오브젝트(딕셔너리) 타입의 state를 redux를 이용하여 관리할 일이 있었다. 이 과정에서 배운 것들을 포스팅으로 남겨 정리하고자 한다.


나의 state

원래 리스트 타입으로 state를 관리했으나 시간 복잡도 측면에서도 그렇고, 딕셔너리 타입인 게 개발하기에도 용이하다 생각되어 store에 있는 state를 대대적으로 변경 했다.

그래서 어떻게 생겼냐면...

clubs: {
	clubId : {
		clubTitle: '제목',
		clubDescription: '내용'
	},
	clubId : {
		clubTitle: '제목',
		clubDescription: '내용'
	}
}

실제로는 이렇게 간단하지 않지만 설명에 용이하기 위해 간단히 나타낸다! state 안에는 각각의 클럽을 구분하는 clubId가 있고 그 안에는 클럽의 정보를 담고 있는 오브젝트가 또 있다. 즉, clubID가 Key이고, {clubTitle, clubDescription}이 Value이다.


Key, Value 렌더링하기

나의 state 안에는 많은 club 정보들이 담겨 있다. 만약 state의 타입이 Key:Value 형태의 오브젝트가 아닌, 리스트라면 map()으로 맵핑하여 각각의 요소를 출력해주면 되지만, Object는 간단한 처리가 더 필요하다.

Object.entries()

Object.entries: array 형태로 [key, value]를 반환
Object.keys: key만 반환
Object.values: value만 반환

map() 함수는 리스트에 사용 가능하므로 Object를 리스트 형식으로 반환해주어야 한다. 따라서 Object.entries로 [key, value]를 반환해준다. 그리고 반환된 값을 맵핑 해주면 원하는 결과를 얻을 수 있다.

{Object.entries(props.clubs).map(([key, value]) => (
	<div key={key}>
		<h1>{value.clubTitle}</h1>
		<h1>{value.clubDescription}</h1>
	</div>
))}

본격적으로 CRUD 구현

근데 사실 read는 useSelector를 사용하면 되므로 본 절에서는 create, update, delete에 대해서 언급할 것임.

action 정의

export const ADD_CLUB = 'ADD_CLUB';
export const DELETE_CLUB = 'DELETE_CLUB';
export const EDIT_CLUB = 'EDIT_CLUB';

let nextId = Math.floor(Math.random() * 10000000);

export const addClub = (clubTitle, clubDescription) => {
    return {
        type: ADD_CLUB,
        clubId: nextId++,
        club: {
            clubTitle,
            clubDescription
        }
    }
}

export const deleteClub = (clubId) => {
    return {
        type: DELETE_CLUB,
        clubId
    }
}

export const editClub = (clubId, clubTitle, clubDescription) => {
    return {
        type: EDIT_CLUB,
        clubId: clubId,
        club: {
            clubTitle,
            clubDescription
        }
    }
}

addClub에서 clubId: nextId++를 해주는 이유는 새로고침 하지 않았을 때 다른 값이 들어가도록 하기 위해서 (오브젝트의 Key값이 unique하도록) 해줬다.

그리고 각각의 함수의 파라미터는 직관적으로 쉽게 이해 가능할 것이라 예상되므로 따로 설명을 더 달진 않겠다. 그리고 이제 action을 정의했으므로 reducer를 정의해주면 끝이다!

create reducer

case ADD_CLUB:
	const newData = {};
	newData[action.clubId] = action.club;
	return Object.assign({}, state, newData);

새롭게 추가할 club 오브젝트를 생성하고 원래 state와 새로 추가할 club 오브젝트를 Object.assign()을 이용하여 합쳐준다.

delete reducer

case DELETE_CLUB:
	const deleteState = {...state};
	delete deleteState[action.clubId];
	return deleteState;

state에 직접 delete 하는 것이 아닌, {...state}를 통해 새로 할당해주어 원하는 값을 delete 해준다. 직접 state를 조작하지 않는 것이 중요!

update reducer

case EDIT_CLUB:
	const editState = {...state};
	editState[action.clubId] = action.club;;
	return editState;

update는 delete와 매우 유사한 방식을 갖는다. delete 할 때 처럼 {...state}를 통해 새로 할당해주고 원하는 clubId에 접근하여 새로운 club으로 업데이트 해준다.

그리고 정의한 create, delete, update reducer를 모두 합치면 아래와 같다.

import { INITIAL_STATE } from '../store/store'
import { ADD_CLUB, DELETE_CLUB, EDIT_CLUB } from "../actions"

const clubs = (state = INITIAL_STATE, action) => {
    switch (action.type) {
        case ADD_CLUB:
            const newData = {};
            newData[action.clubId] = action.club;
            return Object.assign({}, state, newData);
        case DELETE_CLUB:
            const deleteState = {...state};
            delete deleteState[action.clubId];
            return deleteState;
        case EDIT_CLUB:
            const editState = {...state};
            editState[action.clubId] = action.club;;
            return editState;
        default:
          return state;
      }
};

export default clubs;

레퍼런스

profile
유키링と 욘데 쿠다사이

1개의 댓글

comment-user-thumbnail
2021년 12월 21일

redux로 CRUD 구현 도움 많이 됐습니다 감사합니다!!!!

답글 달기