-
Notifications
You must be signed in to change notification settings - Fork 1
[이슈 해결] styled로 만든 컴포넌트에 boolean attribute를 제공할 때 발생하는 이슈
Emotion의 똥꼬집
다음과 같이 내가 작성한 커스텀 컴포넌트를 작성하였다.
import styled from '@emotion/styled';
import { IconPlus } from '@tabler/icons';
import { useState } from 'react';
interface StyledIconPlusProps {
opened: boolean;
}
const StyledIconPlus = styled(IconPlus, transientOptions)<StyledIconPlusProps>`
transition: transform 0.2s ease-in-out;
${({ opened }) => opened && `transform: rotate(45deg);`}
`;
const Mycomponent = () => {
const opened = useState(false);
return(
<StyledIconPlus size={24} opened={opened} />
)
}
그런데 이렇게 작성할 경우 아래와 같은 에러가 발생하게 된다.
Warning: Received
false
for a non-boolean attributeopened
. If you want to write it to the DOM, pass a string instead:opened
=”false” oropened
={value.toString()}. If you used to conditionally omit it withopened
={condition && value}, passopened
={condition ? value : undefined} instead.
-
기본 HTML Tag(
div
,svg
) 에 대한attirubute
들은 DOM에 표시 된다.-
StyledIconPlus
는 기본 태그인svg
를 추상화한 컴포넌트다. -
가령
<StyledIconPlus size={24} hello="world" />
라고 작성하면hello
라는 attribute가 아래 처럼 실제 DOM에 기입된다.
-
-
그런데 DOM
attribute
에는boolean
타입이 아니라 문자열만 들어갈 수 있다. 왜냐하면 이는 모든 DOM 요소는 HTML에 작성되어야 하기 때문이다.
따라서 이를 해결하려면 DOM 요소에 해당 attirbute
가 기입되지 않도록 설정해 주어야 한다.
이를 위한 조치로 emotion
에서는 shouldForwardProps
라는 인터페이스를 제공한다.
const TabsStyled = styled(MuiTabs, {
shouldForwardProp: prop =>
isPropValid(prop) && prop.startsWith('$')
})`
color: ${props =>
props.$myCustomVariantThatStartsWithDollarSign ? 'hotpink' : 'turquoise'};
`
위와 같이 작성하면 $ 표시로 된 attribute
들은 DOM에서 표시하지 않겠다라는 것을 의미한다.
그런데 이걸 모든 컴포넌트를 정의할때마다 사용하는것은 매우 불편하다. 이를 간소화 하면 아래와 같이 작성할 수 있다.
아래와 같은 유틸함수를 정의하고
import { CreateStyled } from '@emotion/styled';
const transientOptions: Parameters<CreateStyled>[1] = {
shouldForwardProp: (propName: string) => !propName.startsWith('$'),
};
export { transientOptions };
이 유틸함수를 아래의 컴포넌트처럼 기입해주면 사용성이 조금 더 간결해진다.
interface StyledIconPlusProps {
$opened: boolean;
}
const StyledIconPlus = styled(IconPlus, transientOptions)<StyledIconPlusProps>`
transition: transform 0.2s ease-in-out;
${({ $opened }) => $opened && `transform: rotate(45deg);`}
`;
이는 $opened
라는 attribute를 DOM에는 표시하지 않도록하여 에러가 나는 것을 막아준다.
이것도 사실 불편한데 이는 사실 emotion
의 똥꼬집(?) 때문이다.
대체제인 Styled-components
는 5.1 버전부터 저 위의 유틸함수를 정의하고 사용할 필요없이 원하는 attribute 앞에 $
표시만 붙이면 DOM에 표시하지 않도록 하는 기능을 해주는데…
https://github.com/emotion-js/emotion/issues/2193 에서 볼 수 있듯이 수많은 사람들이 이 기능의 추가를 요청하고 있음에도 똥꼬집을 부리며 안해주고 있다.
처음으로 Emotion
의 불편함을 체감할 수 있었다….
기초적인 tag
가 포함된 컴포넌트에 boolean
타입의 속성을 전달해야 한다면 2차적인 해결책 을 사용해야 한다.