[React] Westagram Live Review

24035 단어 ReactReact

Westagram Live Review

지금까지 진행한 Westagram작업을 라이브 리뷰를 받으며 수정할 사항을 체크하고 다른 동기님들의 코드를 함께 보며 나에게 필요한 부분을 정리하고자 기록한다.

JSX 리팩토링 목록

✅ localhost:3000 삭제

Mock Data를 만드는 과정에서 fetch에 'http://localhost:3000/data/commentData.json'로 로컬호스트 주소를 입력했었다.

localhost:3000는 바뀔 수 있는 값이다.

실제로3001, 3002으로 바뀔 때마다 다시 fetch 함수에 수정했었고 이 과정이 번거롭게 느껴졌다.

그런데 이것을 '/data/commentData.json' 로 적어도 자동으로 local host가 들어간다는 사실을 배웠다!!

✅ method: 'GET' 삭제

GETfetch 함수의 method의 기본 값이지만, 나는 GET이라고 끝까지 적는 게 아직 초보 단계에서 익숙해지기 쉽고 또 메소드를 파악하기 빠른 것 같아 표시했었다.

하지만 삭제하는 것이 좋다고 한다. 😢

✅ 정말 기본이자 중요한 네이밍!

로직을 보고 네이밍을 해석하는 것이 아니라 네이밍만 보고 로직을 이해할 수 있도록 해야한다.

  • mock data에서 id, value라고 적었지만 실제로는 value에는 여러 값이 들어있기 때문에 values라고 수정해야한다.

  • 로그인 유효성 검사를 위해 정규 표현식을 사용했는데 이때 변수명을 regExp라고 지었다.
    무엇을 위한 정규표현식인지 변수명을 지어줘야한다.
    emailValidationPattern로 변경하면 좋을 것 같다.

  • 한 번 더 생각하는 과정이 필요한 btns와 같은 줄여쓰는 네이밍 작성을 지양해야 한다.
    buttons로 변경하는 것이 좋다.

✅ config.js 생성

현재 westagram 프로젝트에서는 fetch를 쓴 곳이 적지만 실제 프로젝트에서는 많은 fetch 함수를 사용해야하는데 만약 백엔드 주소가 바뀌면 어떻게 될까?
하나 하나 변경해야하는 대참사가 일어난다.

실제로 처음에 페어 백엔드분의 API만 사용하면 되지만 나중에 merge하고 배포하면 API를 바꿔야 한다.

때문에 초기 세팅때부터 이런 API를 관리하는 파일을 만들어야 한다.

config.js를 생성해 상수로 API 주소 값을 관리하는 것이 좋다.

//config.js
const BASE_URL = 'http://10.58.3.11:8000';

export const API = {
  SIGN_IN: `${BASE_URL}/users/signin`,
  SIGN_UP: `${BASE_URL}/users/signup`,
};


// login.js
import { API } from '../../../config';

fetch(API.SIGN_IN, {
  // ...  
});

✅ ID 삭제

id'root'와 같은 명확한 이유로 꼭 필요한 상황에만 사용하고 스타일링이 목적이라면 className을 사용해야한다.

section id="main"className="main"으로 변경해야하며,
순수 JS에서 DOM을 조자하기 위해 사용했던 button id="loginSubmitBtn"이런 방식도 전부 className으로 변경해야한다.

✅ useRef를 사용하는 2가지 용도

  1. DOM 요소를 잡기 위해 사용
  2. 컨테이너처럼 사용
    함수 실행이 끝난다는 것은 함수 안에 변수들도 가비지컬렉션의 대상이 된다는 것을 의미한다.
    하지만 useRef를 사용하면 함수가 종료되도 살아있고, 언마운트 시에도 남을 수 있다.
    이것이 바로 클로저 기술이다!!

✅ setState는 비동기다.

state를 업데이트하는 것은 바로 그 즉시 일어나지 않는다.

// 동기님 코드
const handleUserInput = e => {
  const {name, value} = e.target;
  setUserInfo({
    ...userInfo,
    [name]: value,
  });
  
  // 이 시점에는 state가 아직 업데이트 되지 않았다.
  
  inputValid(); // 업데이트가 되지 않은 state값으로 함수를 실행한다.
}

setState는 여러 개, 즉 여러 번 일어날 수 있다.
그때마다 리엑트가 동기적으로 렌더링시키면 정말 많은 렌더링이 발생한다.
그래서 리엑트는 Batch 업데이트로 모았다가 한 번에 처리해 한 번만 UI를 그리도록 한다.
때문에 setState는 한 템포 느리다.

이를 맞추기 위해 useEffect를 쓸 수 있다.

  1. setUserInfouseInfo 데이터를 업데이트시킨다.
  2. useInfo 데이터가 업데이트됨을 감지하고 inputValid()를 실행한다.
    이때 업데이트된 상태로 실행할 수 있다.
// 동기님 코드
const handleUserInput = e => {
  const {name, value} = e.target;
  setUserInfo({
    ...userInfo,
    [name]: value,
  });
};

useEffect(()=>{
  inputValid();
}, [userInfo]);

✅ state값에 어떤 특정한 값을 넣는 것을 지양하자

로그인 유효성 검사가 통과되지 못할 시 버튼을 비활성화 시키기 위해 아래처럼 useState 초기값으로 disabled라는 string 값을 넣었었다.

// login.js

const [abel, setAbel] = useState('disabled');

const onInput = () => {
  const isInputValid = handleValidInput();
  isInputValid ? setAbel(null) : setAbel('disabled');
};

// 버튼 JSX
<button type="submit" id="loginSubmitBtn" disabled={abel}>
  로그인
</button>

만약 이처럼 어떤 문자열을 사용하고 싶다면 이것을 상수로 만들고 사용해야한다.
왜냐하면 string 값은 오타 나기 쉽기 때문이다.
상수로 작성을 해두면 자동완성 기능으로 에러 가능성을 줄여준다.

const DISABLED = 'disabled';

function Login(){
  //...로그인 컴포넌트 로직
  
  const [abel, setAbel] = useState(DISABLED);
}

하지만 아래처럼 불리언 값으로 설정하면 더 범용성이 생기기 때문에 좋다.
stringnull이면 다른 구성을 생각하기 어려워진다.

function Login(){
  //...로그인 컴포넌트 로직
  
  const [isDisable, setIsDisable] = useState(true);
  
  const onInput = () => {
    const isInputValid = handleValidInput();
    isInputValid ? setIsDisable(false) : setIsDisable(true);
  };

// 버튼 JSX
<button type="submit" id="loginSubmitBtn" disabled={isDisable}>
  로그인
</button>
}

토글 같은 상황에서는 불리언 값을 할당해서 string을 선택하는 방향으로 바꾸자!

✅ useCallback을 남발하지 말자

useCallback을 사용한다는 것은 결국엔 변했는지 안변했는지 검사 과정이 추가되는 것이기 때문에 어차피 변해도 되는 함수라면 그대로 나두는 것이 좋다.

✅ 에러 메세지만 따로 관리하자

로그인 페이지에서 fetch 함수 내에 에러 메세지를 아래처럼 삼항연산자로 하나의 경우만 처리했었다.

// Login.jsx
res.MESSAGE === 'UNAUTHORIZED'
  ? alert('비밀번호 틀렸습니다.')
  : navigate('/main-soyoung');
};

이 에러 메세지는 '이메일이 올바르지 않을 때', '비밀번호가 올바르지 않을 때' 등 경우의 수도 다양하고 결국 고정값으로 상수 데이터이므로 errorMessages 파일을 따로 만들어 백엔드님이 설정하신 메세지 값을 받아 객체 형태로 보관하면 유지보수도 좋고 훨씬 더 간결해진다.

// errorMessages.js
export const ERRORS = {
  UNAUTHORIZED: '존재하지 않는 아이디입니다.',
  INVAILDPASSWORD: '비밀번호 틀렸습니다.',
  ALRREADY_EXIST: '이미 존재하는 아이디입니다.',
};

// Login.jsx
.then(res => {
  console.log(res);
  ERRORS[res.MESSAGE]
    ? alert(ERRORS[res.MESSAGE])
    : navigate('/main-soyoung');
});

프로젝트 세팅 때 백엔드동기님과 꼭 메세지를 같이 맞추고 시작하자!

✅ fetch 함수 실행 전 return

프론트에서 만든 로그인 버튼 비활성화을 위한 유효성 검사 로직을 fetch에 활용할 수 있다!
fetch로 서버에 통신하기 전 프론트에서 미리 올바르지 않은 값을 인식하고 return 시키면 된다!!

const goToMain = e => {
    e.preventDefault();

    const isInputValid = handleValidInput();
    if (isInputValid) return; // 유효하지 않을 경우 return 탈출!

    fetch(API.SIGN_IN, {
      // doing...
    })
};

scss 리팩토링 목록

✅ 태그 셀렉터는 왠만해서는 지양하자

태그 셀럭터는 정말 중복되는 가능성이 높으면 사용하고 왠만하면 지양하자.

✅ & 연산자 활용하기

sass는 중첩 안에서 상위(부모) 선택자를 참조하여 치환할 수 있는 & 키워드를 제공한다!
sass... 너.. 만난지 얼마되지 않았지만 정말 굉장하구나!

    .lineOr {
      // 코드

      .txt {
        // 코드
      }
    }

    .lineOr::after,
    .lineOr::before {
      // 코드
    }

위처럼 따로 분리할 필요없이 중첩으로 넣어 & 키워드로 처리할 수 있다.

    .lineOr {
      // 코드

      &::after,
      &::before {
        // 코드
      }

      .txt {
        // 코드
      }
    }

✅ 스타일링이 필요가 없다면 className을 제거 + scss 파일 제거

class는 해당 요소를 다른 요소와 구분짓고, css에서 선택자로 사용하여 스타일링을 부여하기 위해 존재한다.

때문에 스타일링이 필요 없다면 굳이 className을 사용할 필요가 없다. 또한 scss도 필요가 없다.

✅ 네스팅 미디어쿼리

네스팅에서는 미디어쿼리로 따로 작성할 필요가 없이 해당 태그 바로 밑에 넣으면 된다.

절대 경로

@import '../../../../../styles/variables.scss';

✅ alt에는 이미지라고 적지 않아도 된다.

img 태그에 alt 작성 시 '하트 버튼 이미지', '즐겨찾기 버튼 이미지' 이런 식으로 '이미지'라는 단어를 함께 붙였는데 이미 이미지 태그라는 것을 알기 때문에 필요 없다고 한다.

✅ event를 받아 함수를 호출할 때는 단축가능

// before
onClick = { e => handleClick(e)}

// after
onClick = {handleClick}

기타

  • 업데이트는 기존 값을 지키고 새 값을 생성해야한다.
    원본은 불변성을 유지해야하기 때문에 항상 copy를 뜨고 변화를 구현하는 것을 잊지말자!
  • 최대한 state를 줄여 렌더링을 줄이는 것이 중요하다.
  • 하나의 컴포넌트에는 하나의 관심사만 다뤄야한다. 관심사 분리를 할 때는 반드시 scss도 함께 분리해줘야한다.
  • div는 이미 block 속성인데 width: 100%를 줄 필요가 없다.
    하지만 부모 요소가 display: flex;면 자식은 자동으로 inline-block 속성으로 변경되기 때문에 이때는 필요하다면 width:100% 를 사용해도 된다.
  • 관심사끼리 코드를 묶어주거나 hook끼리 묶어두는 등 다양한 방식으로 코드를 묶어줄 수 있지만 중요한 것은 방식을 한 가지로 통일해야한다.

좋은 웹페이지 즐겨찾기