Fix: DefaultProps css 속성 이름 변경
prayinforrain opened this issue · comments
👨🔧 버그 수정 사항
제가 맡기로 했는데.. 지금은 안 할 거고 까먹을까 봐 미리 이슈로 적어둬요
- DefaultProps, DefaultPropsWithChildren 타입의 css 속성 이름 수정
이유는 차가운 게시판을 참고해 주세요. 대충 emotion이 css
라는 이름의 속성을 사용하고 있기 때문에 의도치 않은 동작을 할 위험이 있어요.
사실 모로 가던 도로 가던 도착은 하는데 지금 상태에서 css라는 속성은 계속 undefined로 넘어오게 돼요. 이상해요
css
속성의 새 이름을 추천받아요. materal-ui에서는 cx
였던 것 같아요
📖 참고 사항
지금 각자 브랜치에서 작업중일 수도 있는데 어쩌죠? 마땅한 해결책이 안떠올라요.
그냥 각자 브랜치에 업데이트 받아서 PR 쓰는게 제일 나을 것 같긴 해요 어차피 스쿼시 머지라 ㅋㅋ...
이름만 바꾼다고 되는 게 아니였어요...
우선 DefaultProps의 css property는 Interpolation<Theme>
타입이에요.
그런데 { css } from '@emotion/styled'
가 만들어내는 객체는 SerializedStyles
타입이에요.
여태껏 별다른 에러 없이 의도한대로 작동하는것처럼 보였기 때문에 이 두 타입이 어떻게든 형변환이 되나보다 대충 넘겨짚고 있었는데..
지금까지 커스텀 스타일을
css?.toString()
처럼 덧붙이는 형태로 사용했었는데 이 사용법에 문제가 있어요. 참고할만한 사용사례는 Flexbox
에요.
앞서 말했듯이 { css } from '@emotion/styled'
는 아래와 같은 SerializedStyles
타입의 객체를 반환해요.
그런데 이 객체의 toString
메소드는 아래와 같은 문자열을 반환해요.
You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop).
즉 저 css?.toString()
이라는 부분은 애초에 아무 기능을 할 수가 없어요.
우리가 지금까지 생각했던 사용방식은 잘못된 것이였어요... 😥
너무 복잡한 상황이라 정리가 깔끔하게 안되는데, 당장 떠오르는 선택지는 두 가지가 있을 것 같아요.
- css props를 제거한다.
- 사실 emotion이
css
props를 이미 컴포넌트의 최상위 element에 렌더링해 주기 때문에 굳이 우리가 css props를 따로 뚫어 줄 이유가 없어보여요. - 아래 케이스도 정말 한정적이고 사실 저런 복잡한 컴포넌트라면 오히려 css를 넘겨준다는 발상 자체가 좀 이상할 것 같아요.
- 사실 emotion이
- 유지하되
React.CSSProperties
타입으로 변경한다.- 이러면 커스텀 스타일을 최상위가 아닌 element에 넘겨줘야 할 때 활용할 수 있어요.
- 실제로 사용되진 않았지만 예시로는 Modal 컴포넌트가 있어요.
- Modal 컴포넌트에 커스텀 스타일을 넘겨야 한다면 최상위 컴포넌트인
ModalWrapper
가 아닌ModalBox
에 css를 넘겨주어야 할 거에요. - 이런 상황에서 props로 받은 css를 직접 전달해 줄 수 있어요.
- Modal 컴포넌트에 커스텀 스타일을 넘겨야 한다면 최상위 컴포넌트인
- 참고로 이렇게 변경될 경우 props에 들어가는 형태는
{ 'backgroundColor': 'red' }
처럼 key-value object로 넘겨주어야 해요.
그리고.. 의사 결정이나 도움이 필요한 상황을 표시하기 위해 help wanted
라벨을 만들었어요.
세영: 우재님 이거 이번에 하고있는 작업들 싹 머지되면 props 이름 바꾸고 Flexbox 컴포넌트만 수정하면 되는거 아닌가요 ..??!
이우재: 이름을 바꿨더니
적용이 안돼요
그러니까 애초에 멀쩡해보이게 움직였던 이유가 우리가 잘 붙인게 아니라 emotion이 정해준 className이 ...props 스프레딩으로 추가되어서 작동한거였어서
css 프로퍼티 이름을 변경하면 저게 동작하지 않아서 우리가 실제로 css를 컴포넌트에 붙여줘야 하는 상황인데
css``로 만들어지는 object로는 그게 불가능해요
세영: 아아 이해했어요
css로 들어가있던 애들은 사실 이모션 컴파일 단계에서 전부 className으로 변환되는거죠?
이우재: 네맞아요
세영: 음 저거 처음에 만든 이유가
적어두신 > Modal 컴포넌트에 커스텀 스타일을 넘겨야 한다면 최상위 컴포넌트인 ModalWrapper가 아닌 ModalBox에 css를 넘겨주어야 할 거에요.
이런거보다는 기존 컴포넌트에 커스텀 스타일을 추가하고 싶은 경우가 있어서 만들었는데
동작이 이런거면 props 정의안해도 사용 가능한거니까 빼도 괜찮을 것 같은데요?
근데 이건 Props 정의에서 빼는게 아니라 사용한 부분들을 다 뺴면 될 것 같아요
Props에서 빼면 컴포넌트에 css 자체를 아예 못넣을거에요 ..!
이우재: 아 그 확인했는데
타입에서 제거해도 뭔가 기본 프로퍼티로 정의되어있어요
세영: 아하 그래요 ??!
이우재: emotion이 뭔가 조작하나봐요
세영: jsx import source에서 넣어주나봐요
이우재: 아직도 어떻게 되어있는지 모르겠어요.....
세영: 그럼 빼면 될거같아요 !!!!
게더에서 토론한 결과 일단 삭제하는 것으로 정했습니다. css props는 그대로 사용이 가능하기 때문에 큰 변화는 없을 거에요(아마)
생긴것만 보고 css props를 props라고 생각한게 문제였어요.
이번 기회에 CSS-in-JS가 어떻게 컴파일되는지 생각해보면 좋겠네요 ^^
https://emotion.sh/docs/css-prop#import-the-jsx-function-from-emotionreact
(cds도 tsconfig에서 jsxImportSource 설정해주고 있어요!)
"jsx": "react-jsx",
"jsxImportSource": "@emotion/react",
얘가 수상해서 이모션 열어봤더니 css props가 있는 경우에는 일반적인 jsx랑 다른걸 리턴해요.
// @flow
import * as ReactJSXRuntime from 'react/jsx-runtime'
import Emotion, { createEmotionProps } from './emotion-element'
import { hasOwnProperty } from './utils'
export const Fragment = ReactJSXRuntime.Fragment
export function jsx(type: any, props: any, key: any) {
if (!hasOwnProperty.call(props, 'css')) {
return ReactJSXRuntime.jsx(type, props, key)
}
return ReactJSXRuntime.jsx(Emotion, createEmotionProps(type, props), key)
}
저 Emotion, createEmotionProps 안에 보니까 우재님이 예상한 것처럼 css props를 컴파일해서 내부 style 태그와 className으로 관리하고 있었어요.
const Insertion = ({ cache, serialized, isStringTag }) => {
registerStyles(cache, serialized, isStringTag)
const rules = useInsertionEffectAlwaysWithSyncFallback(() =>
insertStyles(cache, serialized, isStringTag)
)
if (!isBrowser && rules !== undefined) {
let serializedNames = serialized.name
let next = serialized.next
while (next !== undefined) {
serializedNames += ' ' + next.name
next = next.next
}
return (
<style
{...{
[`data-emotion`]: `${cache.key} ${serializedNames}`,
dangerouslySetInnerHTML: { __html: rules },
nonce: cache.sheet.nonce
}}
/>
)
}
return null
}
let Emotion = /* #__PURE__ */ withEmotionCache<any, any>(
(props, cache, ref) => {
let cssProp = props.css
...
return (
<>
<Insertion
cache={cache}
serialized={serialized}
isStringTag={typeof WrappedComponent === 'string'}
/>
<WrappedComponent {...newProps} />
</>
)
}
)
https://github.com/emotion-js/emotion/blob/main/packages/react/src/jsx-runtime.js
https://github.com/emotion-js/emotion/blob/314a5fb08b0f730e7aa88da0c974dfea13cc9b32/packages/react/src/emotion-element.js#L84
https://github.com/emotion-js/emotion/blob/314a5fb08b0f730e7aa88da0c974dfea13cc9b32/packages/react/src/emotion-element.js#L19
- #44 (comment)
선민님이 확인해주셔서 봤는데 제가bind
의 사용법을 잘못 이해하고 있었어요. 저 PR로는 해결이 안돼요..
DefaultProps
에서 css
를 지우면 Template.args
에서 TypeError가 나지만 막상 실행해보면 className으로 알아서 변환되어 들어가고 있어요. 이건 우리가 처음 생각한 대로에요.
만약 컴포넌트의 Props에는 css
를 명시하지 않고, story의 args 타입에서는 css
를 가지고 있도록 할 방법이 있다면 {...props}
로 스프레딩해도 괜찮을 것 같은데 그 방법을 모르겠어요. args에 style: {}
로 스타일을 지정할 수 있긴 한데 잘...모르겠어요.
그래서 다른 예제가 없을까 찾아봤는데 애초에 추가 스타일을 지정한 예시를 아직 못찾았어요.
생각해 보면 args
는 UI의 usecase의 경우의 수를 나타내는? 옵션인데 이걸 극적으로 보여주기 위해 args에 추가 스타일을 지정하는게 잘못된건가 싶기도 하고 답을 못내리겠어요. 흠..
제가 뒤져본 레퍼런스는 여기에요. 스토리북 공홈에서 예제 프로젝트들을 공개해뒀네요..