원티드 프리온보딩 프론트엔드 사전과제

support·2022년 10월 19일
0

Today I Learned

목록 보기
11/11

원티드 프리온보딩 프론트엔드 코스

💁‍♀️ 깃헙 주소

부트캠프에서 프로젝트 할 때 기능구현은 할 수 있었지만
좋은 코드와 나쁜 코드의 기준을 알기 어려웠다.
지금도 그 기준에 대해서 공부 중이지만 언제나 리팩토링은 어렵다.

원티드에서 하는 프리온보딩 코스를 알게 되었고

평소 고민하고 있던 것을 조금 더 깊이있게 배울 수 있을 것 같아서 사전과제를 구현하게 되었다.

사전과제는 간단한 회원가입 • 로그인 / Todo List 구현 이었다.
여기서 주의해야 하는건 React-Query 같은 기능구현에 직접적으로 연관된 라이브러리 사용은 허용되지 않고 사용 가능한 라이브러리가 정해져 있다는 것

나는 Axios , react-router-dom 과
스타일을 위해서 Emotion , React-Icons , react-toastify 를 사용해서 구현했다.


1. 로그인 / 회원가입

1) 렌더링

로그인과 회원가입에서 react-hook-form을 사용할 수 없었기 때문에
useref를 사용해서 렌더링 최적화를 시켜주려 했다.

하지만 입력된 이메일과 비밀번호가 위 조건을 만족할 때만 버튼이 활성화 되도록 해주세요
라는 조건이 실시간으로 입력을 받아 보여줘야 한다고 생각했기 때문에
useref를 사용했을 때의 이점을 찾지 못해 useState와 useCallback 을 사용했고 관련 로직을 hook으로 빼서 구현했다.

2) axios 모듈화
axios 로직에서 불필요한 부분이 반복 작성되는 것을 막기 위해서 모듈화를 한 뒤 필요한 부분만 불러오는 방식을 사용했다.
api/client.js

import axios from "axios";

export const apiClient = axios.create({
  baseURL: process.env.REACT_APP_API_URL,
  headers: {
    "Access-Control-Allow-Origin": "*",
    "Content-Type": "application/json",
  },
});

apiClient.interceptors.request.use((config) => {
  const accessToken = localStorage.getItem("access_token");

  if (accessToken && config.headers) {
    config.headers["Authorization"] = `Bearer ${accessToken}`;
  }
  return config;
});

api/auth.js

import { apiClient } from "./client";

export const loginApi = async (email, password) => {
  return apiClient.post("/auth/signin", { email, password });
};

component/auth/Login.jsx

  const handleLoginClick = () => {
    loginApi(userInfo.email, userInfo.password)
      .then((res) => {
        notice("success", "로그인 성공");
        localStorage.setItem("access_token", res.data.access_token);
        navigate("/todo");
      })
      .catch((err) => {
        notice("error", err.response.data.message);
      });
  };

2. 투두 리스트

Todo -> 데이터 받아와 내려주기 , access_token 이 있는지 확인하고 리다이렉트 처리
TodoHeader -> 로그아웃
TodoCreate -> TodoList 생성
TodoList -> Todolist 수정 • 삭제 함수 관리
TodoItem -> item의 수정 삭제 상태 변경

1) 렌더링

TodoCreate 에서 실시간 으로 추가해줘야 하는 것이 아니라 버튼을 눌렀을 때
List에 추가되면 됐기 때문에 useRef를 사용해서 렌더링을 줄여줬다.

2) 서버 요청 감소

서버 요청을 줄이기 위해 받아온 데이터를 상태에 담아 내려주고 성공했을 때만 변경시켜줬다.

  const handleTodoUpdate = useCallback(
    (content) => {
      updateTodoApi(content.id, content.todo, content.isCompleted)
        .then(() => {
          const idx = todoData.findIndex((list) => list.id === content.id);
          setTodoData([
            ...todoData.slice(0, idx),
            content,
            ...todoData.slice(idx + 1),
          ]);
        })
        .catch((err) => {
          console.log("주 에러 : ", err);
        });
    },
    [todoData]
  );

처음에 TodoList와 TodoItem 을 나누지 않고 로직을 구현해서
체크박스를 컨트롤 하는 로직이 복잡해졌고
컴포넌트를 나누며 로직을 분리시키느라 두번 일을 하게 되었다.
어떻게 구현할 것인지 더 생각을 하고 코드를 짜자 🥲


3. emotion

참고 디자인

이 디자인을 보고 나중에 개인프로젝트에서 써보고 싶다 라는 생각을 했어서
이번에 emotion으로 구현해봤다.

1) Global Style

공통 스타일을 위해서 emotion의 Global으로 적용해줬다.

/** @jsxImportSource @emotion/react */
import { Global } from "@emotion/react";
...
import { customBodyStyle } from "./shard/globalStyle";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <Router>
      <Global styles={customBodyStyle} />
      <App />
    </Router>
  </React.StrictMode>
);

2) 화면 관리 hook 사용

Login 과 Sign up을 눌렀을 때 화면이 바뀌어야 했기 때문에
화면을 관리할 수 있는 hook을 사용했다.

import { useCallback, useState } from "react";

export const useIsShown = (initialValue) => {
  const [isShown, setIsShown] = useState(initialValue ?? false);

  const onOpen = useCallback(() => {
    setIsShown(true);
  }, []);

  const onClose = useCallback(() => {
    setIsShown(false);
  }, []);

  return [isShown, onOpen, onClose];
};
const Auth = () => {
  const [isShown, onOpen, onClose] = useIsShown();

  return (
    <div css={mainContainer}>
      <SignUp onOpen={onOpen} onClose={onClose} />
      <Login isShown={isShown} onOpen={onOpen} />
    </div>
  );
};

export default Auth;

(아 먼저 색상변수화를 해놓고 시작했어야 했는데 ...)


4. 배포

netlify로 배포를 시도했고 당연히 오류가 났다. 해결해보자...

1) Build command 를 CI= npm run build 로 설정하기

  1. Build command

2) public 폴더 아래에 _redirects 파일 생성 후 아래 내용 입력

라우터 네임이 붙은 페이지를 리로딩하면 404로 연결되는 오류 해결

/* /index.html 200

3) .env 파일 안의 내용을 읽어올 수 없기 때문에 변수 설정
4) peer dependency 충돌 해결 - 충돌이 났을 때 옵션 설정


5. 성능 최적화

필요없는 파일 정리, memo 씌우기, react_devtools 를 클릭했을 때만 작동하기 등등 설정해줘서 lighthouse 성능 100점을 만들었다.

그런데 왜 코드가 그대로 보이는가...

create-react-app으로 만든 React 프로젝트를 빌드하여
배포하게 되면 기본으로 webpack에 의해 번들링 된 파일과
해당 파일에 대응되는 sourcemap이 만들어진다.

-> sourcemap 제거하기

sourcemap 이란

배포용으로 빌드한 파일과 원본 파일을 서로 연결시켜주는 기능이다.
압축해서 배포한 파일에서 에러가 났을 때 어디에서 에러가 났는지 알기 쉽도록 해주는 디버깅을 위한 파일이다.

배포시 단점
1. 내부코드가 그대로 노출되기 때문에 난독화를 한 의미가 없다.
2. 빌드시 메모리 부족(OOM) 이슈가 발생할 수 있다.

package.json 수정

"build": "GENERATE_SOURCEMAP=false react-scripts build"


해결!

3개의 댓글

comment-user-thumbnail
2022년 12월 6일

와.. 정말 잘 만드셨네요. 결과물도 너무 깔끔하시네요 !!
혹시 저는 만들면서 CORS를 package.json에 proxy를 추가해서 해결했었는데
배포를 하니 CORS에 다시 통신이 막히더라구요... 어떻게 해결하셨나요 ?

1개의 답글