[React] Clean Code - 깔끔하고 더 나은 코드를 쓰는 방법

bomhada·2022년 5월 31일
2

📘 React study 

목록 보기
14/15
post-thumbnail

코드를 작성하다보면 순간순간 고민되던 부분들이 있습니다.
지금 내가 쓴 코드를 나중에 다시 보거나 다른 사람들이 읽었을 때 과연 쉽게 이해할 수 있을까라는 생각을 하다가클린코드라는 글을 읽고, 다시 정리하는 글을 쓰게 되었습니다.

1. 하나의 상태만을 위한 상태 렌더링

단일 조건인 조건부 렌더링에는 &&를 사용하세요.

만약 상태가 true일 때만 무언가를 렌더링하고, false일 때 아무것도 렌더링 하고싶지 않을 경우,
삼항연산자보다는 &&연산자(논리 AND 연산자)를 사용하세요.

👎 Bad

function App() {
  return (
    <div>
      {showConditionalText ? <p>The condition must be true!</p> : null}
      // 삼항연산자를 사용하면 null 같이 불필요한 코드가 늘어납니다.
    </div>
  )
}

👍 Good

function App() {
  return (
    <div>
       {showConditionalText && <p>The condition must be true!</p>}
      // 삼항연산자를 활용하면 조건별 렌더링을 더 가시적으로 표현할 수 있습니다.
    </div>
  )
}

2. 두 상태에서의 각기 다른 렌더링

다중 조건인 조건부 렌더링에서는 삼항연산자를 사용하세요.

만약 하나의 상태가 true일 때와 false일 때, 각각 다른 것을 렌더링 하려고 한다면,
삼항연산자를 사용하세요.

👎 Bad

function App() {
  return (
    <div>
      {showConditionOneText && <p>The condition must be true!</p>}
      {!showConditionOneText && <p>The condition must be false!</p>}
    </div>
  )
}

👍 Good

function App() {
  return (
    <div>
      {showConditionOneText ? (
        <p>The condition must be true!</p>
      ) : (
        <p>The condition must be false!</p>
      )}
    </div>
  )
}

3. Boolean 프로퍼티

Boolean 값을 props로 넘길 때는 true를 생략하세요.

truty 프로퍼티는 myTrutyProp처럼 따로 값을 할당하지 않아도 prop만으로 컴포넌트에 참으로 평가되는 값을 제공할 수 있는 경우가 있습니다.
예를 들어, myTrutyProp = {true}라고 적을 필요가 없습니다.

👎 Bad

import React from 'react'

const HungryMessage = ({ isHungry }) => (
  <span>{isHungry ? 'I am hungry' : 'I am full'}</span>
)

export const BooleanPropBad = () => (
  <div>
    <span>
      <b>This person is hungry: </b>
    </span>
    <HungryMessage isHungry={true} />
    <br />
    <span>
      <b>This person is full: </b>
    </span>
    <HungryMessage isHungry={false} />
  </div>
)

👍 Good

import React from 'react'

const HungryMessage = ({ isHungry }) => (
  <span>{isHungry ? 'I am hungry' : 'I am full'}</span>
)

export const BooleanPropGood = () => (
  <div>
    <span>
      <b>This person is hungry: </b>
    </span>
    <HungryMessage isHungry />
    <br />
    <span>
      <b>This person is full: </b>
    </span>
    <HungryMessage isHungry={false} />
  </div>
)

4. String 프로퍼티

문자열 값을 props로 넘길 때는 쌍따옴표를 이용하세요.

문자열 프로퍼티 값은 중괄호{} 나 백틱``을 쓰지 않아도 쌍 따옴표 만으로 할당할 수 있습니다.

👎 Bad

const Greeting = ({ personName }) => <p>Hi, {personName}!</p>

function StringPropValuesBad() {
  <div>
    <Greeting personName={"John"} />
    <Greeting personName={'Matt'} />
    <Greeting personName={`Paul`} />
  </div>
}

👍 Good

const Greeting = ({ personName }) => <p>Hi, {personName}!</p>

function StringPropValuesGood () {
  <div>
    <Greeting personName="John" />
    <Greeting personName="Matt" />
    <Greeting personName="Paul" />
  </div>
}

5. 이벤트 핸들러 함수

인자가 Event객체 뿐인 이벤트 핸들러 함수는 함수명만 입력하세요.

만약에 이벤트 핸들러가 이벤트 객체에 대해 하나의 인수만을 갖는다면,
이벤트 핸들러 함수를 onChange={handleChange} 이런식으로 선언해도 됩니다.
onChange={e => handleChange(e)}이런식으로 익명 함수로 묶지 않아도 됩니다.

👎 Bad

function App() {
  const [inputValue, setInputValue] = useState("");
  const handleChange = event => {
    setInputValue(event.tartget.value);
  }
  
  return(
    <>
      <input value={inputValue} onChange={e => handleChange(e)} />
    </>
  );
}

👍 Good

function App() {
  const [inputValue, setInputValue] = useState("");
  const handleChange = event => {
    setInputValue(event.tartget.value);
  }
  
  return(
    <>
      <input value={inputValue} onChange={handleChange} />
    </>
  );
}

6. 컴포넌트를 프로퍼티처럼 넘길 때

별도의 props가 없는 컴포넌트를 전달할 때는 컴포넌트명만을 입력하세요.

어떤 컴포넌트(B)에 prop으로 또 다른 컴포넌트(A)를 전달하는 경우,
전달되는 컴포넌트(A)가 아무 props를 받지 않는다면 굳이 함수로 감쌀 필요없이 컴포넌트명만 전달해도 됩니다.

👎 Bad

function CircleIcon() {
  <svg height="100" width="100">
    <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
  </svg>
)

function ComponentThatAcceptsAnIcon ({ IconComponent }){
  <div>
    <p>Below is the icon component prop I was given:</p>
    <IconComponent />
  </div>
}

function UnnecessaryAnonymousFunctionComponentsBad() {
  {/* (역주) CircleIcon은 아무런 인자를 받지 않는데도 함수로 감싸서 전달 */}
  <ComponentThatAcceptsAnIcon IconComponent={() => <CircleIcon />} />
}

👍 Good

function CircleIcon() {
  <svg height="100" width="100">
    <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
  </svg>
)

function ComponentThatAcceptsAnIcon ({ IconComponent }){
  <div>
    <p>Below is the icon component prop I was given:</p>
    <IconComponent />
  </div>
}

function UnnecessaryAnonymousFunctionComponentsBad() {
  {/* (역주) 아무런 인자를 받지 않는 CircleIcon를 함수로 싸지 않고 컴포넌트명으로 전달 */}
  <ComponentThatAcceptsAnIcon IconComponent={CircleIcon} />
}

7. Undefined 프로퍼티

Undefined props는 제외됩니다.
만약 어떤 props가 undefined로 제공되어도 컴포넌트 작동에 문제가 없다면,
props값으로 undefined를 전달하는 것에 대한 대비책을 걱정할 필요는 없습니다.

👎 Bad

function ButtonOne({ handleClick }) {
  <button onClick={handleClick || undefined}>Click me</button>
}

function ButtonTwo({ handleClick }) {
  const noop = () => {}
  return <button onClick={handleClick || noop}>Click me</button>
}

function UndefinedPropsBad() {
  <div>
    <ButtonOne />
    <ButtonOne handleClick={() => alert("Clicked!")} />
    <ButtonTwo />
    <ButtonTwo handleClick={() => alert("Clicked!")} />
  </div>
}

👍 Good

function ButtonOne({ handleClick }) {
  <button onClick={handleClick}>Click me</button>
}

function UndefinedPropsGood() {
  <div>
    <ButtonOne />
    <ButtonOne handleClick={() => alert("Clicked!")} />
  </div>
}

8. 이전 상태(state)에 의존하는 state를 갱신할 때

이전 상태에 의존하는 상태를 갱신할 때는 updater 함수를 전달하세요.

새 state가 이전 state에 의존한다면, 이전 state 값을 이용한 함수(updater 함수)를 전달해야 합니다.
React state의 업데이트는 일괄적으로 처리될 수도 있고,
업데이트를 이렇게 작성하지 않는 것은 예상치 못한 결과를 불러 일으킬 수 있습니다.

👎 Bad

function PreviousStateBad() {
  const [isDisabled, setIsDisabled] = useState(false);
  
  // (역주) 이전 값에 의존하는 상태갱신 함수에 갱신결과값만을 전달하면
  const toggleButton = () => setIsDisabled(!isDisabled)
  
  // (역주) 이 함수의 결과가 정상적으로 작동하지 않음을 알 수 있습니다.
  const toggleButton2Times = () => {
    for (let i = 0; i < 2; i++) {
      toggleButton()
    }
  }

  return (
    <div>
      <button disabled={isDisabled}>
        I'm {isDisabled ? 'disabled' : 'enabled'}
      </button>
      <button onClick={toggleButton}>Toggle button state</button>
      <button onClick={toggleButton2Times}>Toggle button state 2 times</button>
    </div>
  )
}

👍 Good

function PreviousStateGood() {
  const [isDisabled, setIsDisabled] = useState(false);
  
  // (역주) 상태갱신 함수의 인자로 이전 값을 인자로 하는 updater 함수를 전달하면
  const toggleButton = () => setIsDisabled(isDisabled => !isDisabled)

  // (역주) 아래 함수가 의도한대로 동작함을 알 수 있습니다.
  const toggleButton2Times = () => {
    for (let i = 0; i < 2; i++) {
      toggleButton()
    }
  }

  return (
    <div>
      <button disabled={isDisabled}>
        I'm {isDisabled ? 'disabled' : 'enabled'}
      </button>
      <button onClick={toggleButton}>Toggle button state</button>
      <button onClick={toggleButton2Times}>Toggle button state 2 times</button>
    </div>
  )
}

9. 그 외

  • 복잡한 로직을 명확하게 지어진 이름으로 함수를 만드세요.
  • 매직 넘버(숫자가 무엇을 의미하는지 해석해야하는 수)를 상수로 만드세요?
  • 명확한 이름의 변수를 사용하세요.

참고 원문

0개의 댓글