TIL21 : [React] Refactoring Checklist

이후경·2022년 6월 25일
0

개발은 여러명이서 함께하는 것
좋은 코드는 누가 보아도 이해하기 쉽고, 가독성이 좋아야 한다.

reset.scss & common.scss

reset.scss, common.scss의 위치는 index.js에서 한번만

  • reset.scss, common.scss는 기본적으로 index.js에서 import
  • index.html - index.js - 세 가지의 관계를 생각해보면 왜 index.js에서 한 번만 import 하면 되는지 쉽게 이해할 수 있다.
  • 초기화 하는 세팅은 reset.scss에!
  • 모든 컴포넌트에 적용되어야 하는 css는 common.scss에!
  • 변수, mixin등의 경우에는 variables.scss, mixin.scss 별도 파일로 분리해서 필요한 .scss 파일에서 import 해서 사용
    관심사에 따라 모듈화하여 관리하면, 추후에 수정사항이 생길 시 한 가지의 파일만 수정하면 되기 때문에 유지보수가 용이
// style/variables.scss

$theme-background: #f6f4f1;
$theme-light-gray-background: #faf9f8;
$theme-blue: #007aff;
$theme-gray-strong: #888888;
$theme-gray-normal: #cccccc;
$theme-gray-light: #eeeeee;
$theme-white: #fff;
$theme-black: #1c1c1e;
$theme-red: #ff0000;

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

.main {
  .title {
    color: $theme-red;
  }
}

귀찮다고 common.scss 에 프로젝트 전체적으로 적용되는 스타일 과 변수 / 믹스인을 함께 선언 금지
만약 그렇게 하게 되면 변수를 사용하기 위해 각 scss 파일에서 common.scss 를 import 할텐데, 이때 전체적으로 적용되는 스타일이 중복해서 적용

// Bad common.scss 🙅‍♂️ 🙅‍♂️ 🙅‍♂️

$theme-background: #f6f4f1;
$theme-light-gray-background: #faf9f8;
$theme-blue: #007aff;
$theme-gray-strong: #888888;
$theme-gray-normal: #cccccc;
$theme-gray-light: #eeeeee;
$theme-white: #fff;
$theme-black: #1c1c1e;
$theme-red: #ff0000;

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

Sass nesting 활용

자바 스크립트는 모듈 시스템을 통해 모든 css파일들이 합쳐지기 떄문에, 하나의 css에서 작성한 코드가 의도치 않게 다른 파일에 있는 요소에 영향을 줄 수 있다.

+ nesting 외에도 지켜야 할 컨벤션

Layout Properties (position, float, clear, display)
Box Model Properties (width, height, margin, padding)
Visual Properties (color, background, border, box-shadow)
Typography Properties (font-size, font-family, text-align, text-transform)
Misc Properties (cursor, overflow, z-index)

className의 동적 사용

인라인 스타일은 꼭 필요한 경우가 아니라면 지양해야한다. 가장 높은 우선순위를 가지고 있기 때문에 나중에ㅜ 유지보수를 어렵게 만든다.

// inline style 사용 🙅‍♂️
<button
  onClick={handleCommentInputButton}
  style={{ color: isCommentButtonActive ? "#0095f6" : "#b5e1ff" }}
>
  로그인
</button>

// className 사용 🙆‍♂️
<button
  onClick={handleCommentInputButton}
  className={isCommentButtonActive ? "activated" : "deactivated"}
>
  로그인
</button>
.activated {
  color: #0095f6;
}

.deactivated {
  color: #b5e1ff;
}

비구조화 할당, 구조분해 할당 (destructuring)

비구조화 할당(구조분해 할당)은 객체, 배열에 적용할 수 있는 ES6 문법이다.
이 기능을 통해 긴 코드를 간결하게 사용할 수 있다.

// 비구조화 할당 미적용
const handlePasswordInput = event => {
  setPassword(event.target.value);
  ...
}

// 비구조화 할당 적용
const handlePasswordInput = event => {
  const { value } = event.target;
  setPassword(value);
  ...
}

핸들러 함수에서 뿐만 아니라 함수 컴포넌트 바디에서도 props객체에서 비구조화 할당을 적용해 코드를 간결하게 쓸 수 있다.

function PasswordInput (props) {
  return (
    <input value={props.passwordValue} onClick={props.handlePasswordInput}/>
  )
}

// 비구조화 할당 적용
function PasswordInput (props) {
  const { passwordValue, handlePasswordInput } = props;
  return (
    <input value={passwordValue} onClick={handlePasswordInput}/>
  )
}

// props 자리에서 바로 비구조화 할당을 할 수도 있습니다.
function PasswordInput ({ passwordValue, handlePasswordInput }) {
  return (
    <input value={passwordValue} onClick={handlePasswordInput}/>
  )
}

Boolean 데이터 타입의 활용

Before 🙅‍♂️
if (event.target.value.includes("@") && event.target.value.length >= 5) {
  setIsIdValid(true);
} else {
  setIsIdValid(false);
}

// After 🙆‍♂️
const { value } = event.target;
const isIdInputValid = value.includes("@") && value.length >= 5;

setIsIdValid(isIdInputValid);

반복되는 코드는 Array.map() 활용

// named export (vs. default export)
export const INFO_LIST = [
  {id: 1, content: "도움말"},
  {id: 2, content: "홍보 센터"},
  {id: 3, content: "API"},
  {id: 4, content: "채용정보"},
  {id: 5, content: "개인정보처리방침"},
  {id: 6, content: "약관"},
  {id: 7, content: "위치"},
  {id: 8, content: "인기 계정"},
]

// Footer.js (Footer 컴포넌트)
import { INFO_LIST } from './footerData.js'

return (
  ...
  {INFO_LIST.map(info => {
     return (
       <li key={info.id}>
         <a href="">{info.content}</a>
       </li>
     )
 });
  • map을 사용할 때는 return 되는 JSX 요소마다 유니크한 key 값이 존재해야한다 (index사용 금지)
  • key 속성은 제일 바깥에 있는 태그에 부여합니다.
  return (
    <li key={el.id}>
      <span>{el.content}</span>
    </li>
  )
})

위 상황에서 INFO_LIST 변수를 함수 컴포넌트 바디에서 선언할 경우 컴포넌트가 render 될 때마다 새로운 변수가 계속 선언되기 때문에, 값이 변하지 않는 변수는 컴포넌트 밖에서 선언합니다.
단 가독성을 위해 상단에 작성하지 말고 코드의 하단의 위치하도록 한다.

'계산된 속성명' 을 이용한 inputHandler 함수 합치기

input 태그에는 name 이라는 속성이 있습니다. 말 그대로 input 태그에 이름을 지어 주는 건데요. 이 name 속성 덕분에 여러 개의 input handler를 하나로 합칠 수 있다

// 비슷하게 생긴 코드가 보이면 줄이는 방법에 대해 고민해보시기 바랍니다!

// Before
const [inputValues, setInputValues] = useState({
  email: "",
  password: "",
});

const handleEmail = event => {
  const { value } = event.target;

  setInputValues({
    ...inputValues,
    email: value,
  })
}

const handlePassword = event => {
  const { value } = event.target;

  setInputValues({
    ...inputValues,
    password: value,
  })
}

return (
    ...
    <input
      className="emailInput"
      type="text"
      onChange={handleEmail}
    />
    <input
      className="passwordInput"
      type="password"
      onChange={handlePw}
    />
    ...
  );
}

// After
const [inputValues, setInputValues] = useState({
  email: "",
  password: "",
});

const handleInput = event => {
  const { name, value } = event.target;
  setInputValues({
    ...inputValues,
    [name]: value,
  })
}

return (
    ...
    <input
      className="emailInput"
      name="email"
      type="text"
      onChange={handleInput}
    />
    <input
      className="passwordInput"
      name="password"
      type="password"
      onChange={handleInput}
    />
    ...
  );

name 속성의 값은 value처럼 event.target으로 가져올 수 있다. (event.target.name)
name 속성은 오직 input 태그에서만 사용할 수 있습니다. 다른 태그에서 사용하려고 시도금지

a tag는 사용하면 새로고침 하는 것처럼 html을 새로 다 받아 오는 반면, Link 를 사용하면 컴포넌트만 바꿔준다. 렌더링 최적화를 위해서 Link 사용하자
외부 사이트 이동시에만 a 링크 사용

import 순서

라이브러리

  • React 관련 패키지
  • 외부 라이브러리

컴포넌트

  • 공통 컴포넌트 → 먼 컴포넌트 → 가까운 컴포넌트

함수, 변수 및 설정 파일
사진 등 미디어 파일(.png)
css 파일 (.scss)

불필요한 state 값 제거

state의 업데이트는 렌더링 발생.
만약 state로 관리하지 않아도 되는 값을 state로 관리할 경우, 일어나지 않아도 되는 렌더링이 발생하게 됩니다. 따라서 불필요한 state 값들은 제거

state로 관리하기 부적합한 값

부모로부터 전달받는 props
시간이 지나도 변하지 않는 값 (UI 변화에 관여하지 않는 값)
컴포넌트 안의 다른 state 나 props 로 계산 가능한 값

profile
나는야 경바

0개의 댓글