코드숨 소프트웨어 개발의 지혜 <리액트 편> 9기 과정 중 8주간의 정규 과정이 드디어 마무리됐다. 길다면 길고, 짧다면 짧지만 TDD를 배우고, 여러 프론트엔드 기술에 대해 공부할 수 있는 값진 시간이었다.
코드숨
이번 주 과제는 크게 세 가지였다.
- Redux Toolkit 도입
- CSS-in-JS 라이브러리인 Emotion을 이용한 스타일링
React.memo,useCallback등을 이용한 컴포넌트 성능 최적화
Redux Toolkit
개인적으로 제일 비중을 뒀던 주제다. 아샬 님이 강의에서 설명한 createSlice와 ducks pattern 이외에도 공식 문서에서 소개하는 기능들을 최대한 많이 사용해 보려고 했다.
가장 시간을 많이 썼던 건 createAsyncThunk다. 이전 과제를 진행하면서 비동기 작업을 처리하는 방법에 대해 Redux 공식 문서를 참고했을 때, createAsyncThunk를 사용하고, 로딩이나 에러 같은 상태 처리도 간편해 보여서 꾸준히 관심을 갖고 있었다.
export const loadRegions = createAsyncThunk(
'regions/loadRegions', async () => {
const regions = await fetchRegions();
return regions;
},
);
const { reducer, actions } = createSlice({
name: 'regions',
initialState: {
regions: {
data: [],
status: 'idle', // 'idle' | 'loading' | 'succeeded' | 'failed'
error: '',
},
},
extraReducers(builder) {
builder
.addCase(loadRegions.pending, (state) => {
const { regions } = state;
return {
...state,
regions: {
...regions,
status: 'loading',
},
};
})
.addCase(loadRegions.fulfilled, (state, { payload: data }) => {
const { regions } = state;
return {
...state,
regions: {
...regions,
data,
status: 'succeeded',
},
};
})
.addCase(loadRegions.rejected, (state, { error: { message } }) => {
const { regions } = state;
return {
...state,
regions: {
...regions,
status: 'failed',
error: message,
},
};
});
},
});
이번 과제에서는 위와 같이 지역 목록을 가져오는 작업에만 사용해봤다. 원래는 모든 API 요청에 사용해 볼 생각이었는데 생각보다 진도를 못 나가서 그러지 못한 점이 많이 아쉽다.
기존에 Redux Thunk를 직접 이용한 방법과 비교해 보자면, 처음 써보는 거라 테스트를 작성하는 게 좀 어려웠지만, Redux Toolkit에서 자체적으로 pending, fulfilled, rejected 같이 상태에 따른 액션 타입을 지정해 주니 별다른 고민을 하지 않고, 일관된 코드를 작성할 수 있다는 점이 정말 좋았다. 그 덕분에 컴포넌트 레이어에서도 상태에 따른 화면을 구성을 쉽게 할 수 있었다.
다음은 역시 Redux Toolkit 공식 문서를 참고한 건데, 기능이라고 하기는 좀 애매하고, ducks pattern의 연장선 상이라 할 수 있을 것 같다.
// RegionsContainer.jsx
const regions = useSelector((state) => state.regions.regions);
const selectedRegion = useSelector((state) => state.regions.selectedRegion);
기존에 useSelector의 인자로 전달하는 selector 함수는 위와 같이 각 컴포넌트에서 직접 작성했었다.
// regionsSlice.js
export const selectRegions = (state) => state.regions.regions;
export const selectSelectedRegion = (state) => state.regions.selectedRegion;
// RegionsContainer.jsx
const regions = useSelector(selectRegions);
const selectedRegion = useSelector(selectSelectedRegion);
하지만 위와 같이 selector 함수를 slice.js에서 정의해놓는다면 각 컴포넌트에서는 그 selector 함수들을 가져다 쓸 수 있다.
특정 기능과 관련된 것들을 하나의 파일에서 관리하는 ducks pattern 관점에서 그 selector 함수들 역시 같은 파일에서 관리함으로써 응집도를 높일 수 있고, 일관된 상태 접근 방법을 제공할 수 있다는 큰 장점이 있다.
Emotion
CSS-in-JS 라이브러리는 예전에 styled-components를 써본 적이 있는데 요즘에는 Emotion을 더 많이 쓰는 추세라고 한다. 복잡한 기능까지 사용한 건 아니라 큰 차이점을 느끼진 못했다. 그보다 스타일링 관련 코드를 어떻게 관리하면 좋을지가 여전히 고민이다.
const Button = styled.button({
opacity: 0.9,
borderColor: 'transparent',
borderRadius: '.375rem',
padding: '.5rem 1rem',
backgroundColor: royalBlue,
cursor: 'pointer',
fontWeight: 500,
color: white,
'&:hover': {
opacity: 1.0,
},
});
위와 같이 버튼을 스타일링한 컴포넌트가 있을 때, 나는 이 컴포넌트가 여러 곳에서 쓰인다면, 스타일링을 재활용하기 위해 이 코드만 별도로 컴포넌트화하는 게 맞는다고 생각했는데, CSS-in-JS 철학으로는 CSS 코드가 단순히 스타일링이 아닌 실제 기능을 하는 컴포넌트 코드와 같이 있는 게 좋다는 피드백을 받았다. 아마 다음과 같은 형태일 것이다.
const StyledButton = styled.button({
...
});
export default function Button({ ... }) {
...
return <StyledButton ... />;
}
이에 대해서는 아직 결정을 내리지 못했는데, 앞으로 CSS-in-JS에 대한 경험을 쌓아나간다면 나름의 기준이 생기지 않을까 싶다.
컴포넌트 성능 최적화
사실 다른 주제에 시간을 쓰느라 이 주제엔 별로 시간을 쓰지는 못했다. 실무에서 사용하는 Flutter에도 React를 따라 만든 Hooks가 존재하는데 거기서도 useMemo()와 useCallback()은 자주 사용하기 때문에 대수롭지 않게 생각했던 것 같기도 하다.
예전에 React를 공부할 때, 당장 성능에 문제가 없으면 함부로 쓰지 말라는 글을 보기도 했고.. 아무튼 성능 최적화를 제대로 적용하려면 React Developer Tools를 이용해 컴포넌트가 언제 Re-rendering 되는지 확인하면서 진행해야 하는데 급하게 하느라 제대로 했는지는 확신이 서지 않는다. 남은 포트폴리오 과정에서 이 부분에 대해 좀 더 신경 써야겠다.
다음은
정규 과정 8주는 끝났지만, 나에겐 아직 포트폴리오 과정 4주가 남아 있다. 어제 윤석 님과 앞으로 일정에 대해 얘기를 나눴는데 세부적인 기능에 대해서는 변경될 가능성이 있지만 코인(가상화폐)과 관련된 프로그램을 만들 계획이다. 8주 동안 배운 것들을 기반으로 실전 같은 연습을 하는 시간이 될 것 같다. 7주 차부터 집중력이 좀 떨어졌었는데 다시 시작한다는 기분으로 남은 4주 동안도 열심히 해야겠다.
'교육 > 코드숨' 카테고리의 다른 글
| [코드숨] 리액트 7주 차 회고 (0) | 2022.07.25 |
|---|---|
| [코드숨] 리액트 6주 차 회고 (2) | 2022.07.18 |
| [코드숨] 리액트 5주 차 회고 (0) | 2022.07.11 |
| [코드숨] 리액트 4주 차 회고 (0) | 2022.07.03 |
| [코드숨] 리액트 3주 차 회고 (0) | 2022.06.26 |