최근에 토이 프로젝트를 하고 있는데 있는데 오브젝트(딕셔너리) 타입의 state를 redux를 이용하여 관리할 일이 있었다. 이 과정에서 배운 것들을 포스팅으로 남겨 정리하고자 한다.
원래 리스트 타입으로 state를 관리했으나 시간 복잡도 측면에서도 그렇고, 딕셔너리 타입인 게 개발하기에도 용이하다 생각되어 store에 있는 state를 대대적으로 변경 했다.
clubs: {
clubId : {
clubTitle: '제목',
clubDescription: '내용'
},
clubId : {
clubTitle: '제목',
clubDescription: '내용'
}
}
실제로는 이렇게 간단하지 않지만 설명에 용이하기 위해 간단히 나타낸다! state 안에는 각각의 클럽을 구분하는 clubId
가 있고 그 안에는 클럽의 정보를 담고 있는 오브젝트가 또 있다. 즉, clubID
가 Key이고, {clubTitle, clubDescription}
이 Value이다.
나의 state 안에는 많은 club 정보들이 담겨 있다. 만약 state의 타입이 Key:Value 형태의 오브젝트가 아닌, 리스트라면 map()
으로 맵핑하여 각각의 요소를 출력해주면 되지만, Object는 간단한 처리가 더 필요하다.
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>
))}
근데 사실 read는 useSelector
를 사용하면 되므로 본 절에서는 create, update, delete에 대해서 언급할 것임.
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를 정의해주면 끝이다!
case ADD_CLUB:
const newData = {};
newData[action.clubId] = action.club;
return Object.assign({}, state, newData);
새롭게 추가할 club 오브젝트를 생성하고 원래 state와 새로 추가할 club 오브젝트를 Object.assign()
을 이용하여 합쳐준다.
case DELETE_CLUB:
const deleteState = {...state};
delete deleteState[action.clubId];
return deleteState;
state에 직접 delete 하는 것이 아닌, {...state}
를 통해 새로 할당해주어 원하는 값을 delete 해준다. 직접 state를 조작하지 않는 것이 중요!
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;
redux로 CRUD 구현 도움 많이 됐습니다 감사합니다!!!!