2022. 9. 1. 19:37ㆍReact/NFT Airdropper
안녕하세요!
제가 알고 있는 얼마 없는 Web 3.0 지식을 모두에게 나누고자 새로운 웹을 기획했습니다.
제목은 바로 Mintty 하루만에 대충 웹 기획이 끝났네요. 폰트랑 스타일 정의도 대충 끝났구요.
일단 요런 느낌이고 개발하면서 새로 써보는 기술들을 조금씩 정리해보려고 합니다.
각설하고 클론코딩하면서 css 걱정은 없었는데,
혼자 하니 css부터 뭔가 심상치 않습니다..
이번에 새로 찍먹해볼 기술은 @emotion/sytled로 해보는 Theme만들어주기!
아래 블로그에서 보고 영감을 받아서 Typescript로 한번 바꿔봤습니다.
ts에서는 tsconfig라던가 더 설정해줘야하는게 몇몇 개 있더라구요.
또 interface가 업데이트되면서 몇 개 바뀌기도 했구요.
이건 제가 참고한 블로그
이건 공식문서
1. @emotion 설치와 tsconfig.json / .babelrc 설정
새 프로젝트를 시작할 때마다 항상 패키지가 어렵습니다..
일단 저는 이렇게 깔아줬습니다.
npm i @babel/preset-react @emotion/babel-plugin @emotion/core @emotion/react @emotion/styled
@emotion/core와 @babel/preset-react는 확실하지 않습니다.
그냥.. 안되는 것 같길래 한 번 깔아봤어요.
2022.09.06 - @emotion/core는 deprecated 되었다고 하네요. 이게 @emotion/react로 업데이트 되었답니다!
다음은 tsconfig.json을 만져줘야합니다.
"compilerOptions": {
...
"jsx": "react-jsx",
"jsxImportSource": "@emotion/react",
...
},
jsxImportSource를 꼭 저렇게 설정해주셔야 나중에 sytled-component에서 props의 타입이 제대로 들어갑니다.
혹여나 props.theme의 하위 object를 제대로 declare 해줬는데도 불구하고 typescript compiler가 제대로 잡아내지 못한다면, 이런 문제일 확률이 높습니다.
마지막으로 디렉토리 최상단에 .babelrc를 만들어줍시다!
.babelrc
{
"plugins": ["@emotions"]
//만약 다른 babel plugin 설치한 경우는 "plugin": ["@emotions", ..otherBabelProps] 나열해서 써주세요.
}
단.. 한줄...!
당연한 이야기지만 다른 babel 플러그인을 설치하셨으면, 계속 나열해서 적어주세요.
2. Theme.ts와 Theme.d.ts 생성
자 이제 패키지는 세팅이 끝났네요.
Theme를 만들어봅시다.
Theme은 정의되어있는 interface를 저희가 받아와서 override 해주거나 저희가 추가로 declare 해줘야하는데요.
놀랍게도 내용이 비어있습니다.
간혹 emotion/styled를 처리하다가 이런데에서 오류가 나는 일들이 종종 있습니다.
background-color: ${({ theme }) => theme.color.bgGrey20 };
// TS2339: Property 'colors' does not exist on type 'Theme'.
회사다닐땐 이거 때문에 하나 둘씩 globalStyle로 옮겨가다가 이제 더 이상 theme을 안쓰곤 했다는 웃픈이야기가 있는데요.
이 원인 중 하나가 typescript에서 저희가 정의한 Theme의 type을 해독하지 못해서라고 합니다.
결론적으로는 같은 이름의 declare file을 만들어줘서 해결이 가능합니다.
theme.tsx
import { Theme } from "@emotion/react";
const theme: Theme = {
fontSizes: {
xs: '12px',
sm: '16px',
base: '24px',
md: '36px',
lg: '48px',
xl: '64px',
xxl: '96px',
xxxl: '128px',
},
colors: {
black: '#12101D',
white: '#FFFFFF',
primary: '#B672FD',
secondary: '#E7266C',
}
}
export default theme;
theme.d.ts
import '@emotion/react';
declare module '@emotion/react' {
export interface Theme {
fontSizes: {
xs: string;
sm: string;
base: string;
md: string;
lg: string;
xl: string;
xxl: string;
xxxl: string;
};
colors: {
black: string;
white: string;
primary: string;
secondary: string;
};
}
}
이렇게 해주면 자동으로 웹스톰에서는 자동으로 Nesting이 됩니다.
2022.09.01 declare 파일과 theme.tsx가 연결되지 않아 typescript compiler에서 에러를 확인했습니다.
최하단 추가항목을 봐주세요.
3. Index.tsx에서 Theme 설정
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import theme from "./style/theme";
import { ThemeProvider } from "@emotion/react";
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<ThemeProvider theme={theme}>
<App/>
</ThemeProvider>
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
이렇게 해주면 저희가 src 폴더에서 정의해주는 하위 컴포넌트의 styles.tsx에서 이런 식으로 가져오는게 가능합니다.
styles.tsx
import styled from "@emotion/styled";
export const WallpaperLayout = styled.div`
color: ${({ theme }) => theme.colors.black};
`;
다만 이러면 문제가 명색에 Theme인데, 하나로 일괄 적용됩니다.
이 Theme가 가장 많이 이용되는게 다크모드/일반 모드 일텐데요.
크게는 세 가지 방법이 생각납니다.
1. os 세팅을 보고 테마를 가져오거나,
2. (서버에서 정보를 내려준다면) redux나 swr같은 전역 저장소로 유저가 고른 걸 가져오거나,
3. (사용자가 UI로 직접 설정을 변경해준다면) hooks를 직접 만들어주거나,
이렇게 되는데요.
음.. 이 설정은 나중에 한 번 공유하겠습니다.
이번 프로젝트에서 한/영 전환되는 기능도 넣고자 하니.. hooks로 바꾸거나 하는 건 꼭 넣어야하겠네요.
고럼 이만!
테마와 함께 즐거운 리액트 되세요!
2022.09.01 - 긴급 수정 사항이 있습니다.
포스트를 마치고 나서 Theme은 잘 들어오지만 Typescript compiler가 type을 감지하지 못하는 버그를 발견했습니다.
export const WallpaperLayout = styled.div`
color: ${({ theme }) => {
console.log(theme);
return theme.colors.black;
}};
`;
다음과 같이 콘솔을 찍어봤는데
ThemeProvider나 타 설정의 문제가 아니라고 생각합니다.
theme.d.ts를 제대로 binding이 안되었다고 판단했습니다.
결론적으로 두 파일을 하나에 합치면 typescript 에러도 나지 않는 것을 확인할 수 있었습니다.
theme.tsx(theme.d.ts는 삭제)
import { Theme } from "@emotion/react";
declare module '@emotion/react' {
export interface Theme {
fontSizes: {
xs: string
sm: string
base: string
md: string
lg: string
xl: string
xxl: string
xxxl: string
};
colors: {
black: string
white: string
primary: string
secondary: string
};
}
}
const theme: Theme = {
fontSizes: {
xs: '12px',
sm: '16px',
base: '24px',
md: '36px',
lg: '48px',
xl: '64px',
xxl: '96px',
xxxl: '128px',
},
colors: {
black: '#12101D',
white: '#FFFFFF',
primary: '#B672FD',
secondary: '#E7266C',
}
}
export default theme;
혼선을 드려 죄송합니다.
수정사항 발생 시 바로바로 업데이트하겠습니다.
'React > NFT Airdropper' 카테고리의 다른 글
[React] article 안의 한/영 전환은 어떻게 구현해야 할까? (1) | 2022.09.24 |
---|---|
[React] 마우스 애니메이션 훅(Hooks) 만들기 (1) | 2022.09.23 |
[CSS] hover할 때 글자아래 줄이 쳐지는 효과 만들기 - pseudo el에 대해 (0) | 2022.09.22 |
[React] url params 변경시 애니메이션 넣기 (0) | 2022.09.15 |
Typescript가 window.ethereum을 거부할때.. (0) | 2022.09.08 |