💻 Frontend
코드숨_코드리뷰 스터디 4주차 회고
1. 학습한 내용
1-1) Flux Architecture와 Redux
- Flux Architecture는 페이스북에서 상태관리 문제를 해결하기 위한 일종의 패턴이다. ex) 좋아요를 눌렀을 때 실제 상태값으로 변경이 되지 않아 다른 유저들에게는 보이지 않는 에러가 발생
- 규모가 커질수록 MVC 패턴의 데이터 관리는 복잡도를 야기하고, 어디에서 에러가 발생하는지 추적하기 어렵다
- 이를 보완하기 위해서 Flux Architecture를 구축했는데 핵심적인 특징은 2가지이다. 1) Action이 Dispatcher를 통해 Store에 전달되는 흐름(단방향 데이터 흐름을 구축)하고, 2) Store와 App의 관심사를 분리한다.
- 참고자료
1-2) React에서 Redux 활용
- 상태관리(데이터와 조작)을 store 한 곳에서 하자
- 그리고 이를 연결해주는 곳이 App이다.
어떻게 하냐
기존에 App에서 처리해주는 것은 handler함수에서 state와 setState를 통해 바꿔준다.
const [state, setState] = useState({
newId: 100,
taskTitle: '',
tasks: [],
});
const { newId, taskTitle, tasks } = state;
function handleChangeTitle(event) {
setState({
...state,
taskTitle: event.target.value,
});
}Store를 활용해서 상태관리에 대한 관심사를 분리한다면 아래와 같이 updateTaskTitle이 하는 일을 모르게 된다.
function handleChangeTitle(e){
return setState(updateTaskTitle(state,e.target.value))
}그렇다면 위와 같은 형태의 관심사 분리를 redux를 활용해본다면?
redux의 주요 구성요소는 아래와 같다.
- reducer로 기존 상태와 액션을 받아서 다른 상태로 변경해주는 함수이다. reducer는 다음과 같은 구조를 갖게 된다.
function reducer(state, action) {
// ...
return state;
}- 그렇다면 action은 뭐냐? 상태를 업데이트하게 되는 함수를 말한다.
action의 구성요소는 아래와 같다. 무슨 액션인지 나타나는 type과 인자 값으로 실리는 payload로 구성.
export function updateTaskTitle(taskTitle) {
return {
type: 'updateTaskTitle',
payload: taskTitle,
};
}- Store는 위와같이 state와 action으로 구성된 reducer를 store로 감싸주면 전체 상태값을 저장하는 하나의 객체가 만들어지게 된다. 이러한 스토어는 액션이 발생하면 reducer를 실행해 상태값을 새로운 값으로 업데이트한다.
const store = createStore(reducer);- Provider로 최상위 App 컴포넌트를 감싸주면 App에서 store에 접근할 수 있다.
ReactDOM.render(
<Provider>
<App />
</Provider>
,
document.getElementById('app'),
);- store에 있는 state와 action을 실제로 꺼내거나, 발생시키는데 편리한 useDispatch, useSelector 훅을 이용할 수 있다.
function selector(state) {
return {
taskTitle: state.taskTitle,
tasks: state.tasks,
};
}
export default function App() {
const { taskTitle, tasks } = useSelector(selector);
function handleChangeTitle(event) {
useDispatch(updateTaskTitle(event.target.value));
}1-3) Redux를 테스트하는 방법
Redux가 사용된 파일을 테스트 하기 위해서는 다음과 같은 단계가 필요하다
- mocks 폴더 생성 및 가짜함수 생성
__mocks__라는 이름으로 폴더를 생성하게 되면, 해당 모듈을 import한 jest 파일에서 해당 파일에 있는 함수로 모킹을 한다.
// __mocks__
export const useDispatch = jest.fn();
export const useSelector = jest.fn((selector) => selector({}));- react-redux 모킹 및 가짜함수를 통한 결과값 반환 (useSelector,useDispatch)
import { useSelector, useDispatch } from 'react-redux';
describe('FormContainer', () => {
jest.mock('react-redux');
useSelector.mockImplementation((selector) => selector({
title: '투썸플레이스',
sort: '카페',
location: '신도림',
}));
const dispatch = jest.fn();
useDispatch.mockImplementation(() => dispatch);
...
...
expect(dispatch).toBeCalledWith({
type: 'ADD_RESTAURANT',
1-4) reducer에서 switch, if 사용하지 않기
reducer 공식문서에서는 보통 switch문의 예제를 보여준다.
그러나 switch문과 if문을 왜 사용하면 안좋은지를 알아보자
let number = 2;
switch (number) {
case 1:
let message = "first number";
console.log(message)
break;
case 2:
let message = "second number";
console.log(message)
break;
case 3:
let message = "third number";
console.log(message)
break;
default
let message = "second number";
console.log(message)
break;
}
//This throws a syntax error: identifier "message"
//has already been declared우선 switch의 경우에는 호이스팅 이슈가 있다.
switch case 문 안에서 동일한 변수를 선언할수 없다.
중괄호를 적게 되면 변수 범위를 제한할 수 있다고는 하지만, 중괄호를 적지 않았을 때를 계속 신경써야한다.
아래의 참고자료에 더 자세하게 나와있다.
if 문은 복잡해질수록 코드의 가독성이 현저히 떨어지게 된다.
우리가 그렇다면 리덕스에서 각각의 type에 맞는 값을 불러오는데 더 깔끔한 코드를 어떻게 만들 수 있을까?
두 가지 방법이 있다.
- 객체형태의 actionCreator를 만들어서 해당 값에 맞는 함수를 리턴
const initialState = {
id: 100,
title: '',
sort: '',
location: '',
restaurants: [],
};
const actionCreator = {
UPDATE_INPUT: (state, { payload }) => {
const { name, value } = payload;
return ({
...state,
[name]: value,
}
);
},
ADD_RESTAURANT: (state) => {
const {
id, title, sort, location, restaurants,
} = state;
return {
...state,
id: id + 1,
title: '',
sort: '',
location: '',
restaurants: [
...restaurants, {
id, title, sort, location,
}],
};
},
};
export default function reducer(state = initialState, action) {
if (actionCreator[action.type]) {
const { payload } = action;
return actionCreator[action.type](state, { payload });
}
return state;
}- Redux-actions
위와 같이 반복되는 Action선언과 함수형태로 reducer를 선언하는 것을 도와주는 redux-actions라이브러리를 사용할 수도 있다.
이를 사용하면 아래와 같이 코드를 만들 수 있게 된다.
import { handleActions, createAction } from 'redux-actions';
const UPDATE_TASK_TITLE = 'task/UPDATE_TASK_TITLE';
const ADD_TASK = 'task/ADD_TASK';
const DELETE_TASK = 'task/DELETE_TASK';
export const updateTaskTitle = createAction(UPDATE_TASK_TITLE);
export const addTask = createAction(ADD_TASK);
export const deleteTask = createAction(DELETE_TASK);
const initialState = { newId: 100, taskTitle: '', tasks: [] };
const reducer = handleActions({
[UPDATE_TASK_TITLE]: (state, { payload }) => ({
...state,
taskTitle: payload.taskTitle,
}),
[ADD_TASK]: (state) => {
const { newId, tasks, taskTitle } = state;
return {
...state,
newId: newId + 1,
taskTitle: '',
tasks: [...tasks, { id: newId, title: taskTitle }],
};
},
[DELETE_TASK]: (state, { payload }) => {
const { tasks } = state;
return {
...state,
tasks: tasks.filter((task) => task.id !== payload.id),
};
},
}, initialState);- 그냥 제일 쉬운 RTK(toolkit)쓰자..
- 사실 toolkit은 위의 모든 것들을 쉽게 쓸 수 있게 헬퍼함수들이 잘 구축되어있다..
- 이번에는 Redux 본연에 대해서 좀 더 깊게 알아보기 위해 toolkit을 쓰진 않았지만
- 현업에서 쓴다면 걍 toolkit 쓸 것 같다..!!
1-5) 기타
Redux test
- 정규표현식으로 테스트를 넣을 경우 포함된 것들을 모두 찾아주지만
- 문자열로 넣어주면 완성된 텍스트가 있는지를 찾아줌

2. 회고
Redux 깊게 이해하기 및 test코드 작성 적응하기
- redux를 깊게 알아보는데 도움이 되었다. 특히 기본 구조는 알고 있었지만,
- switch,if를 사용하지 않고 각 action들을 호출하는 것을 공부하면서 리덕스 구조가 더 확 이해가 되었다.
- 뿐만 아니라 redux-actions와 toolkit의 헬퍼가 어떤 부분을 편리하게 해주는지 알게 된 계기가 되었다.
- redux 테스트 구조를 짜고보니 아직 속도는 빠르진 않지만 어느정도 적응이 되는 것 같다.
- 그런데 시간이 너무 오래걸려서 이걸 현업에서 쓸 수 있는 수준이 되려면 어느정도 속도,생산성이 나와야되나 고민이다.
학습에 소홀했던 주간
- 코드숨 과정을 하면서 그간 잘 안밀리면서 했는데, 한 주 동안 2곳의 면접과 주말 가족모임이 겹치게 되면서 이래저래 시간을 못썼다.
- 사실 면접을 보고나서도 빨리 털어내고 할 것들을 했어야했는데, 고민과 후회가 머릿속에 떠나지 않아 집중이 잘 안됐다.
- 집중하기 위해서 산책도하고, 차를 마셔보기도 했는데 좀 처럼 멘탈이 잘 잡히지 않는 걸 보니 부담감과 조급함이 계속 쌓여서 터진 것 같다. 그래서 일요일 과제마감이 되어서야 결국 코드리뷰 PR을 보내게 됐다.
- 그래서 천천히 하자는 생각에 오늘은 좀 쉬다가 밤늦게서야 이렇게 회고를 쓰면서 다시 정신차리자는 다짐을 한다.
프로젝트 준비하기
- 코드숨 뿐만 아니라 개인적으로 Ts를 학습하고 있는데 거의 끝나간다.
- 이제 어느정도 테스트코드를 짜는 법을 알았으니 프로젝트를 하려고 한다.
- 어떤 프로젝트를 하면 좋을지 5주차에는 고민을 해봐야겠다.


