[styled-components] Transient props(`$propName`) 사용 시 주의할 점 (feat. shouldForwardProp)

Maria Kim·2024년 1월 13일
1
post-thumbnail

v6부터 Transient props를 권하고 있다.

If haven't migrated your styling to use transient props ($prefix), you might notice React warnings about styling props getting through to the DOM in v6.
styled-components 공식문서 - What do I need to do to migrate to v6

styled-components는 v6부터 기본값으로 들어가던 shouldForwardProp을 제거했다. 그리고 Transient props를 기본적으로 사용하길 원하는 듯하다.

마이그레이션을 진행해 본 사람들은 모두, props를 사용하는 곳에서 React의 경고와 styled-components에서의 경고가 함께 뜨는 경험을 했을 것이다.

하지만, styled-components에 사용할 props를 Transient prop로 변경해도 될까?

결론부터 말하자면,
바로 직접적으로 사용할 styled-component만 Transient props를 사용해야 한다.

만약 해당 컴포넌트가 Base Component처럼 HOC에 포함될 수 있는 경우라면, shouldForwardProp을 사용해야 한다.

사용하면 문제가 되는 코드 예시

const SelectAllCheckbox = () => {
  ...
  return <CheckAllCheckbox $fixedWidth={50} />;
};
function CheckAllCheckbox(props) {
  ...
  return <StyledCheckboxCell {...props} />;
}

const StyledCheckboxCell = styled(CheckboxCell)`
  @media ${({ theme }) => theme.devices.mobile} {
    min-width: 30px;
  }
`;
export const CheckboxCell = ({ className, ...restProps }) => {
  ...
  return (
    <TableHead align='center' className={className} {...restProps}>
      // ...
    </TableHead>
  );
};
export const TableHead = styled('th')(({ $fixedWidth }) => ({
  padding: '0.4rem',
  ...($fixedWidth && { width: $fixedWidth + 'px', minWidth: $fixedWidth + 'px' }),
}));

코드 요약

  • 최종적으로 $fixedWidth가 사용되는 곳
    : TableHead styled 컴포넌트

  • $fixedWidth 전달 경로
    : SelectAllCheckbox => CheckAllCheckbox => StyledCheckboxCell => CheckboxCell => TableHead

  • styled 컴포넌트
    1. TableHead
    2. CheckboxCell을 감싼 StyledCheckboxCell

설명

위 코드는 TableHead 컴포넌트에서 사용한 $fixedWidth props를 SelectAllCheckbox에서 부터 내려주고 있다.

이 코드를 작성한 사람은 $fixedWidthCheckAllCheckboxCheckboxCell에서
props를 다 넘겨줬으니 당연히 props가 전달됐을 것이라 생각할 수 있다.

그리고 StyledCheckboxCell에서 작성한 스타일은 CheckboxCell에서 className를 통해 잘 들어갔을 것이다.

하지만, 코드를 실행해 보면 $fixedWidth와 관련된 코드가 추가되지 않은 것을 확인 할 수 있을 것이다.

그리고 급히, console을 찍어보면, CheckAllCheckbox의 props에는 $fixedWidth가 있지만 CheckboxCell에서는 props에 $fixedWidth가 없다. 😱

없어진 props

자, 다시 공식 문서로 돌아가 Transient props에 대해 알아보자.

styled-components 공식문서 - Transient props

공식 문서에 적힌 것처럼 똑똑한 styled-component는 $로 시작하는 props를 제거한다. 하지만 마지막으로 만난 styled에서 이것이 작동하는 것이 아니다. styled를 만나면 바로 $로 시작하는 props를 제거하고 아래 React node나 DOM에서 사용되는 것을 방지하는 것이다.

코드에서 보면 StyledCheckboxCell에서 style을 CheckboxCell에 추가할 때, $fixedWidth가 제거된 것이다.

해결하기

그렇다면, 방법이 없는 것일까?

그럴 리가, 이때 shouldforwardprop를 사용하면 된다.

styled-components 공식문서 - shouldforwardprop

수정된 코드(shouldForwardProp 사용)

const SelectAllCheckbox = () => {
  return <CheckAllCheckbox fixedWidth={50} />;
};

function CheckAllCheckbox(props) {
  return <StyledCheckboxCell {...props} />;
}

const StyledCheckboxCell = styled(CheckboxCell)`
  @media ${({ theme }) => theme.devices.mobile} {
    min-width: 30px;
  }
`;

export const CheckboxCell = ({ className, ...restProps }) => {
  return (
    <TableHead align='center' className={className} {...restProps}>
      // ...
    </TableHead>
  );
};

export const TableHead = styled('th').withConfig({
  shouldForwardProp: prop => !['fixedWidth'].includes(prop),
})(({ fixedWidth }) => ({
  padding: '0.4rem',
  ...(fixedWidth && { width: fixedWidth + 'px', minWidth: fixedWidth + 'px' }),
}));

언제나 그렇듯 공식 문서를 잘 읽자. 마이그레이션 시에는 어디에서 문제가 생길지 모르니, 확실히 변경되는 부분에 대해 잘 읽어보자.

profile
Frontend Developer, who has business in mind.

0개의 댓글