[개발일지] 22년 32주차 - contextAPI와 기획

FeRo 페로·2022년 8월 14일
0

최종 프로젝트가 시작이 되었다. 벌써? 시작한 지 얼마 되지 않은 거 같은데 참 시간이 빠르다. 캠프에서 리액트부터 리액트 쿼리, 리덕스까지. 혼자 공부할 때는 닿을 수 없는 속도로 많은 것들을 공부했다. 옆에서 열심히 하는 동료들 덕분에 지쳐도 쉴 수 없었던 것 같다. 항상 주변에 함께 하는 동료들에게 감사하다.

최종 프로젝트를 시작하는 단계이기 때문에 실질적인 코딩 아직 많이 하지 않았다. 그래서 이렇게 짬이 나는 시간들을 이용해서 Nomad의 React Master 강의와 지난 번에 보다가 마지막 contextAPI에서 시간 상 다 못봤던 제로초님의 리액트 강의까지. 못 다 본 강의들과 조금 더 리액트에 대한 이해도를 높이기 위한 강의를 보고 있다. 얼른 보고 실질적인 작업 단계에서 더 나아진 코드를 쓸 수 있도록 노력하는 중이다.

오늘은 이번 주에 공부했던 내용 중 contextAPI에 대해서 정리를 하고 이번 프로젝트에 대한 이야기를 조금 해볼까 한다.

contextAPI

제로초님 강의를 보면 useReducer를 먼저 알려준다. 그래서 state와 setState를 함께 관리하는, 즉 전역 상태 관리에 대해서 알려준 다음에 contextAPI를 알려준다. 처음에 useReducer를 배우고 나서, 나는 redux와 redux toolkit, 그리고 recoil을 써보았다. 그러고 나서 예전에 제로초님 강의 봤던 것을 떠올려 보니, 그럼 useReducer를 통해서 dispatch와 reducer를 만들었는데, 그렇다면 여기서는 store를 어떻게 생성하고 제공해 줄 수 있는지에 대한 궁금함이 생겼다. 그 답이 contextAPI였다. 사용법은 리덕스와 매우 유사했다. 그도 그럴 것이 Redux를 만든 Dan Abramov가 리액트 팀으로 합류한 뒤에 나온 것이 useReducer와 contextAPI이니, 이상할 것은 없다.

import { useReducer, createContext } from "react";
import Table from "./table";

// 1. createContext를 통해서 contextAPI를 만들어 주고, default Value를 설정해준다.
// redux에서 initial data를 통해서 reducer의 기본 state를 만들고, 그걸 바탕으로 store를 만드는 것처럼 여기서는 createContext를 통해서 그 작업을 해준다.
export const TableContext = createContext({
  tableData: [],
  dispatch: () => {},
});

export const START_GAME = "START_GAME";

const initState = {
  tableData: [],
  timer: 0,
  result: "",
};

const reducer = (state, action) => {
  switch (action.type) {
    case START_GAME:
      return {
        
        ...
        
      };
        
    ...
        
    default:
      return state;
  }
};

const MineSearch = () => {
  const [state, dispatch] = useReducer(reducer, initState);
  const { timer, result, tableData } = state;

  return (
    <>
      // 2. redux처럼 Provider로 감싸준다. 그리고 value라는 요소를 통해서 tableData와 dispatch함수를 전달해 준다.
      <TableContext.Provider value={{ tableData: tableData, dispatch }}>
        <Form />
        <div>{timer}</div>
        <Table />
        <div>{result}</div>
      </TableContext.Provider>
    </>
  );
};

export default MineSearch;

이렇게 해주면 끝! 어렵지는 않다. 다만 위 처럼 Provider태그의 value에 저걸 다 적어주면 최적화 하기가 쉽지 않다. 제로초님의 말에 따르면 contextAPI 자체가 최적화 하는 것이 어렵다고 한다. 여러 이유가 있겠지만, 그 기본적인 이유 중 하나가 value 안에 있는 객체이다.
value 안에 보면 tableData와 dispatch함수를 가지고 있는데, MineSearch라는 컴포넌트가 리랜더링 될 때마다 value 안에 있는 저 객체도 새로 생긴다. 근데 Provider에게 제공해주는 정보인 해당 value 객체가 리랜더링 된다는 것은 저 value를 사용하는 다른 자식 컴포넌트들도 모두 리랜더링이 된다는 것이다.

그래서 아래와 같이 해주면 훨씬 좋다!

  // value객체에 들어갈 값을 미리 변수에 담아두는데 그걸 메모이제이션한다.
  const value = useMemo(
    () => ({ tableData: tableData, dispatch }),
    [tableData]
  );
  
  ...
  
  return (
    <>
      <TableContext.Provider value={value}>
    
      ...
  
    </>


// 자식 컴포넌트
// 자식 컴포넌트에서는 아래처럼 TableContext의 dispatch함수에 접근할 수 있다.
// redux의 useSelector처럼 사용한다고 생각하면 된다.
const { dispatch } = useContext(TableContext);

이렇게 해주면 useMemo를 통해서 value 안에 들어가는 값들을 메모이제이션을 할 수 있고 그 덕분에 불필요하게 자식 컴포넌트들까지 리랜더링이 되는 것을 방지할 수 있다.

createContext를 통해서 리덕스의 store 역할을 하는 친구를 만들고, 이렇게 Provider를 설정해주고 나면 사용준비는 끝났다. 위 코드의 마지막에 있는 코드처럼 사용하고 싶은 자식 컴포넌트에 가서 useContext라는 훅을 통해서 TableContext라는 store에 접근할 수 있다.

contextAPI를 배우고 나서는 작은 프로젝트에서는 사용하기 좋지만 프로젝트의 크기가 늘어났을 때는 여지없이 리덕스를 찾게 된다는 말을 조금이나마 이해할 수 있게 되었다. 특히나 비동기 통신을 할 거면 thunk가 내장되어 있는 toolkit을 안 쓸 이유가 없고 프로젝트의 크기가 커져 state가 많이 생긴다면 그 역시 toolkit을 안 쓸 이유가 없다.

그래도 알고 안쓰는 것과 모르고 안쓰는 것의 차이는 크니까 이번 기회를 통해서 알아보았다.

기획

최종 프로젝트이기 때문에 기획을 지난 주들과는 비교도 안될 정도로 꼼꼼하게 했다. 정말 한 주를 통째로 기획하는데 썼다. 고심 끝에 주제를 정하고 계속해서 주제에 대한 스코프를 고민하고 토의를 했다. 그리고 더하고, 빼고를 반복했다.
그 과정에서 여러 레퍼런스를 참고하고 모든 조원들의 의견들을 담으려고 했었다. 사실 처음에는 기획하는 김에 몇 일 간 코딩을 안할 수 있다는 생각도 들었지만 시간이 지날수록 차라리 코딩이 더 쉽겠다는 생각이 들 만큼 기획은 매우 어려웠고 머리가 아픈 작업이었다. 특히나 최종 프로젝트에서는 디자이너분도 함께 한다. 그래서 우리들의 의견 뿐만 아니라 디자이너분의 생각도 더해지기 때문에 프로젝트의 기획 단계에서 고려해야 할 부분은 더 커졌다.

그래도 지금은 어느 정도 기획이 마무리가 되었고 이제는 구현만 하면 되는 단계이다. 나는 이번 프로젝트에서 메인과 로그인/회원가입을 맡게 되었다. 지난 주에 이어서 또 다시 로그인/회원가입을 맡게 되었지만 지난 주에는 다 만들고 보니 눈에 밟히는 부분들이 있었다. 그래서 이번에 다시 만들면서 더 완성도 있는 결과를 내야겠다는 생각을 했다.

메인 페이지에서는 kakao map을 사용한다. 지도는 아직까지 해보지 않은 도메인이라서 매우 기대된다. 특히나 어제 kakao map을 어느 정도로 커스텀이 가능한지 docs를 보면서 해보았는데 생각보다 큰 범위에서 커스텀이 가능한 거 같았다. 특히나 마커나 클러스터 역시 커스텀이 가능해서 그 부분은 디자이너 분과 소통을 통해서 최대한 좋은 결과물을 낼 수 있도록 노력해야겠다.

디자이너분과의 협업은 처음인데 다행히도 현직에 있는 디자이너분과 함께 하게 되어 영광으로 생각하고 있다. 나처럼 경험이 부족한 프로그래머에게 생각하지도 못한 부분을 조언해주시기 때문이다. 벌써 기획단계에서부터 우리가 생각하지도 못한 부분을 짚어주거나 새로운 시각을 제시해주셔서 도움이 많이 되었다. 프로젝트 끝까지 함께 좋은 결과물을 낼 수 있으면 좋겠다.

profile
주먹펴고 일어서서 코딩해

0개의 댓글