티스토리 뷰

바로 직전에 MUI라는 CSS 프레임워크를 갖다 쓰는 것에 대해 비판적인 의견을 나타내는 글을 썼었는데.. 

사실 MUI는 개발자들이 좋아하는 CSS 프레임워크이고 많은 사람들이 여러 가지 이유로 잘 사용하는 CSS 프레임워크이다. 많은 기능을 제공하고(built in API) 잘만 쓰면 아주 편리하기 때문인데 ..처음 MUI를 갖다 쓰면서 간단한 조각을 빌려 쓴 것이 아니라 바로 커스텀을 해야하던 상황이라 그런지 첫인상이 매우 좋지 않았다. CSS도 익숙하지 않은 사람이 만들어진 컴포넌트를 갖다 쓴다는 게 생각처럼 쉽지 않았을 것이고 결국 많은 시간을 소요하는 결과를 낳았다. 

 

현업에서 MUI를 좋아하는 개발자들이 많다는 글을 봐서 그런지 다시 한 번 제대로 사용해보고자 한다. 

MUI로 구성된 프로젝트를 완성해봐야 그래도 내가 이게 좋다 아니다 판단할 기준점이 생길 거 같다. (평소에는 그냥 컴포넌트 몇 개를 가져다 쓰는 정도였으므로)

 

Themeprovider 사용하여 default 값 변경해주기 

최대한 상단에 위치시켜주는 것이 좋다고 한다. index.tsx에 위치시키려다가 그냥 예시대로 App.tsx에 위치시키기로 했다. 

mui에서 제공하는 기본 값을 내가 원하는 값으로 수정해서 그것을 기본값으로 전체적으로 사용하고 싶다면 react context API처럼 theme을 만들어서 내려주면 된다. 

 

기존의 값을 override 해서 커스텀 theme을 만드는 것이다. 

import { routers, MenuContents } from "./router";
import { RouterProvider } from "react-router-dom";
import { AuthProvider } from "./context/AuthContext";
import "./App.css";
import { ThemeProvider, createTheme } from "@mui/material";

const theme = createTheme({
  palette: {
    primary: {
      main: "#df2b5b",
    },
  },
});
function App() {
  return (
    <div className="App">
      <ThemeProvider theme={theme}>
        <AuthProvider>
          <RouterProvider router={routers} />
        </AuthProvider>
      </ThemeProvider>
    </div>
  );
}

export default App;
 

Default theme viewer - Material UI

Here's what the theme object looks like with the default values.

mui.com

 

타입스크립트와 같이 적용할 때에는 issue가 발생했는데 theme을 생성할 때, 

커스텀 property를 만들어서 적용할 경우, 타입에러가 발생한다.

타입 오버라이드를 해줘야 하는데 이 과정이 굉장히 불편하다. 

아래는 Typography의 Variant로 myVariant를 사용하기위해 타입 오버라이드를 interface로 해주는 솔루션이다.

declare module "@mui/material/styles" {
  interface TypographyVariants {
    myVariant: React.CSSProperties;
  }

  interface TypographyVariantsOptions {
    myVariant?: React.CSSProperties;
  }
}

declare module "@mui/material/Typography" {
  interface TypographyPropsVariantOverrides {
    myVariant: true;
  }
}

docs에서도 custom variables를 사용할 때, typescript를 사용하고 있다면 어떻게 처리하라고 알려주고 있다.

 

Theming - Material UI

Customize MUI with your theme. You can change the colors, the typography and much more.

mui.com

The sx prop

컴포넌트의 단일 인스턴스 스타일만 변경하고 싶다면 sx 를 사용하는 것이 좋다.

인라인 css를 넣어주는 느낌으로 사용하는 프롭인데  실제css를 직접 써도되고 MUI에서 제공하는 prop을 써도 동작한다. 

  • sx props는 @mui/system에 포함된 스타일 함수를 패키징하는 CSS의 상위 집합으로 작업할 수 있다. 
  • 아래처럼 진짜 CSS 프로퍼티와 매칭된 이름이 존재한다. 하단은 spacing에 관련된 내용이다. 자세한 내용 docs 
Prop CSS property
m margin
mt margin-top
mr margin-right
mb margin-bottom
ml margin-left
mx margin-left, margin-right
my margin-top, margin-bottom
p padding
pt padding-top
pr padding-right
pb padding-bottom
pl padding-left
px padding-left, padding-right
py padding-top, padding-bottom

 

어우.. 타입스크립트와 mui를 같이 쓰고 있는 경우라면, 커스텀 prop을 만들어줄 때 꽤나 번잡하다. 

 

커스텀 color 타입 정의

import { routers } from "./router";
import { RouterProvider } from "react-router-dom";
import { AuthProvider } from "./context/AuthContext";
import "./App.css";
import { ThemeProvider, createTheme } from "@mui/material";
import { orange, red } from "@mui/material/colors";

interface CustomPaletteColorOptions {
  main?: string;
  dark?: string;
  light?: string;
  superDark?: string;
  superLight?: string;
}

interface CustomPaletteOptions {
  myCustomColor?: CustomPaletteColorOptions;
}

declare module "@mui/material/styles" {
  interface PaletteOptions extends CustomPaletteOptions {}
}
const theme = createTheme({
  palette: {
    primary: {
      main: "#df2b5b",
    },
    secondary: {
      main: orange[500],
    },
    myCustomColor: {
      main: red[400],
      superDark: red[800],
      superLight: red[100],
    },
  },
});
function App() {
  return (
    <div className="App">
      <ThemeProvider theme={theme}>
        <AuthProvider>
          <RouterProvider router={routers} />
        </AuthProvider>
      </ThemeProvider>
    </div>
  );
}

export default App;

Typography 컴포넌트에 sx prop으로 커스텀 color 적용하기

import { Typography } from "@mui/material";
//코드 중략

<Typography sx={{ color: "myCustomColor.main" }}>
        something test
</Typography>
  • 보면 color의 값을 스트링으로 주고 myCustomColor.main으로 객체에 속성으로 접근하고 있다.
  • 같은 방법으로 myCustomColor.superLight / superDark에 접근하면 된다.

sx 속성 말고도 styled()를 사용하여 컴포넌트의 스타일을 커스텀해줄 수 있다. 

styled() from @mui/material/styles 

styled component를 사용했을 때도 styled() 함수 내부에 기존에 만들어둔 컴포넌트를 넘겨서 그 값에 추가적으로 커스텀한것과 동일한 것처럼 보인다. 🤔

🔺사용 이슈 발생

sx에서 사용하는 CSS shortcut인 p(= padding)을 쓰니 값이 먹지 않았다. mui에서 제공하는 shortcut이라 가능한 줄 알았으나 sx 내부에서만 사용이 가능한 듯 하다.

 

다시 찾아보니 이 styled 함수는 emotion에서 제공하는 styled 함수이다.  CSS in JS와 같은 원리로 동작하는 듯하다. 

import { styled } from "@mui/material/styles";
import { Button, Typography } from "@mui/material";

const MyCustomBtn = styled(Button)({
    padding: 20, // ✅works!
    p: 20 //❌not working
  });
  
//mui/materail에서 Button 컴포넌트를 인자로 넘겨주어서 p 속성을 사용할 수 있을 줄 알았다.
const MyCustomBtn = styled(Button)({
   sx: {
  	p: 20 //❌not working
  }
  });

더 자세한 내용은 docs를 참고하면 된다. 

 

댓글