기술 / / 2023. 1. 4. 11:44

[번역] 프론트엔드 개발자가 꼭 알아야 할 React의 4가지 trap

저는 React를 정말 좋아합니다. 일하는 동안 가장 많이 사용하는 프레임워크 중 하나입니다. 하지만 제가 조건문을 제대로 통제하지 못했기 때문에 거의 포기할 뻔할 상황을 여러 번 맞이했고, 이런 이유 때문에 한동안 React는 정말 힘들었습니다. 혹시 이런 문제가 발생한 적이 있으신가요? React를 활용하며 좋은 조건문을 작성하려면 어떻게 하나요?

0은 악마와 같습니다. 이것으로부터 멀어지세요.

서버에서 데이터를 가져와 목록을 표시해야 하는 이런 코드가 있어야 합니다. 데이터가 비어 있으면 데이터가 표시되지 않아야 합니다.

(예제코드와 함께 보시면 이해가 편합니다.)

const App = () => {
  const [list, setList] = React.useState([]);
  // fatch data ...
  return (
    list.length && (
      <div className="name-list-container">
        {list.map((name) => {
          return <div className="name-list-item">{name}</div>;
        })}
      </div>
    )
  );
};

으악, 이게 왜 이렇게 될까요? 왜 list는 비어있는데, 0이 표시될까요?

See the Pen react-1 by qianlong (@qianlong) on CodePen.

 

 

왜 이런일이 발생할까요?

다행스럽고 감사하게도, 이것은 React의 버그가 아닙니다. 이것은 자바스크립트 자체의 동작방식과 연관되어있습니다.

TIPS (출처: MDN): boolean 연산자에 대한 논리적 AND(&&) 연산자는 모든 피연산자가 참인 경우에만 참이 됩니다. 그렇지 않으면 거짓이 됩니다.

일반적으로 연산자는 왼쪽에서 오른쪽으로 평가할 때 발견된 첫 번째 거짓 피연산자의 값을 반환하거나, 마지막 피연산자의 값이 모두 진실인 경우에는 값을 반환합니다.
const a = 0;
const b = "fatfish";
const c = 1;
const d = "medium";

console.log(a && b); // 0
console.log(c && d); // medium

우리가 a && b를 사용할 때 a가 0이면 바로 반환되고, b의 값은 계산되지 않습니다. 이렇게 한다면, 위의 코드펜의 결과가 0으로 표시되는 이유를 이해하셨을 것입니다.

 

이 문제를 어떻게 해결할 수 있을까요?

이런 문제를 해결하기 위한 여러 방법이 있는데, 크게 두 가지 유형으로 나누어 생각해 볼 수 있습니다.

  1. a를 boolean으로 변경
  2. 삼항연산자 사용 

// 1. Convert list.length to boolean
!!list.length && <Component list={list} />;


// 2. Controlled by specific logic
list.length >= 1 && <Component list={list} />;


// 3. Use ternary expressions and null
list.length ? <Component list={list} /> : null;

 

 

중첩된 삼항연산자를 제거해 주세요.

회사에서 프로젝트를 진행하다 보면 중첩된 삼항연산자로 이루어진 코드를 마주하게 됩니다. 이건 정말 악몽이에요, 이해하기 너무 어렵고 가독성이 정말 너무 떨어집니다.

{
  isUserA ? (
    <ComponentA />
  ) : isUserB ? (
    <ComponentB />
  ) : (
    isUserC ? <ComponentC /> : null
  );
}

여러분, 만약 여러분의 동료가 이런 종류의 코드를 작성하고 있다면, 그가 더 이상 코드를 작성할 수 없을 정도로 많이 먹을 수 있도록 그에게 햄버거 100개를 꼭 사주세요.

 

어떻게 수정할까요?

복잡한 판단을 요구하는 조건문을 만나게 된다면, if else 구문을 사용하는 것이 더 좋은 선택입니다.

const renderCompnent = () => {
  let component = null
  if (isUserA) {
    component = <ComponentA />
  } else if (isUserB) {
    component = <ComponentB />
  } else if (isUserC) {
    component = <ComponentC />
  }
  return component
}

 

"||"와 "&&"는 조심해야 합니다.

만약 당신이 "||"와 "&&"를 섞어서 사용하신다면, 꼭 조심해 주세요. 왜냐면 이런 방식은 실수를 유발하기가 쉽기 때문입니다.

const App = (props) => {
  return (
    props.name || props.name2 && <div className="user-info">fatfish</div>
  )
}

ReactDOM.render(<App name="medium" />, document.getElementById('app'))

"fatfish"를 표시하고 싶은데, name1이나 name2의 프로퍼티가 전달될 경우, 우리가 예상하는 결과를 얻기가 어려울 것입니다.

See the Pen Untitled by qianlong (@qianlong) on CodePen.

 

왜 이런 일이 발생할까요?

&&연산자는 더 높은 우선권을 갖습니다. 다음 코드를 통해 확인해 보세요.

 

const App = (props) => {
  return (
    props.name || (props.name2 && <div className="user-info">fatfish</div>)
  )
}

ReactDOM.render(<App name="medium" />, document.getElementById('app'))

 

const App = (props) => {
  return (
    (props.name || props.name2) && <div className="user-info">fatfish</div>
  )
}

ReactDOM.render(<App name="medium" />, document.getElementById('app'))

이것이 당신이 원하는 결과일 것입니다. 훌륭해요!

 

 

"props.children"로 조건을 판단하지 마세요

이 코드는 매우 간단하며, Vue.js의 slot과 유사한 기능을 구현하여 통과할 때 자식을 렌더링 하고 통과하지 않을 경우 빈 요소를 표시합니다.

const Container = ({ children }) => {
  if (children) {
    return (
      <div className="children-container">
        <p>The content of children is:</p>
        { children }
      </div>
    ) 
  } else {
    return (
      <div className="empty">empty</div>
    )
  }
}

이것도 큰 함정을 유발할 수 있습니다.

 

"empty"라는 문자열을 보고 싶다면 어떻게 해야 할까요?

 

react tip

const Container = ({ children }) => {
  if (children) {
    return (
      <div className="children-container">
        <p>The content of children is:</p>
        { children }
      </div>
    ) 
  } else {
    return (
      <div className="empty">empty</div>
    )
  }
}

const App = () => {
  const [ list, setList ] = React.useState([])
  
  return (
    <Container>
      {
        list.map((name) => {
          return <div className="name-item">{ name }</div>  
        })
      }
    </Container>
  )
}
ReactDOM.render(<App />, document.getElementById('app'))

 

자, 우리 한번 <Container /> 컴포넌트에 children이 무엇을 뜻하는지 로그를 찍어볼까요?

const Container = ({ children }) => {
  console.log(children, 'children')
  // ...
}

react tip2

네, 맞습니다. "children"으로 전달된 데이터는 빈 배열입니다. 그래서 "the content of children is: "는 "empty" 대신에 빈 배열을 나타내고 있어요.

 

 

어떻게 수정할까요?

React.Children.toArray를 사용한다면, 이 문제를 쉽게 해결할 수 있습니다. 그렇게 한다면 당신은 "empty"를 표시할 수 있을 것입니다. 만약 당신이 꼭 children을 조건부 판단식으로 사용하기를 원한다면 저는 이런 방식으로 사용하시기를 제안해 드립니다.

 

const Container = ({ children }) => {
  // if (children) {
  // Pay attention here
  if (React.Children.toArray(children).length) {  
    return (
      <div className="children-container">
        <p>The content of children is:</p>
        { children }
      </div>
    ) 
  } else {
    return (
      <div className="empty">empty</div>
    )
  }
}

원문
https://javascript.plainenglish.io/as-a-front-end-engineer-4-react-traps-you-should-know-about-4adb126672f6

 

As a Front-End Engineer, 4 React Traps You Should Know About

The 4 React traps you must stay away from

javascript.plainenglish.io



반응형

 

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유