Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

TypeScript + Material-UI v4 のスタイル付きコンポーネント作成ガイド

More than 1 year has passed since last update.

2019年5月下旬に Material-UI v4 が正式にリリースされました。スタイル付きコンポーネントの記法が v3 以前のものと変わったのでメモしておきます。

加筆(2019/12/21)

この記法が、React 16.8 で導入されたフック(hook)であることを補足しました。

環境

create-react-app で作成したディレクトリを前提にしています。

参考: TypeScript React Starter

バージョン

- typescript @3.2.2
- @material-ui/core @4.0.2
- react @16.8.6
- react-dom @16.8.6

v3 からの変更点

v3 でのスタイル付きコンポーネントの記法は以下の記事を参照してください。
v4 で初めて Material-UI を使うという人は読む必要はありません。

TypeScript + React + Material-UI v3 のスタイル付き Components ガイド

  • withStyles(styles)(Component) という記法ではなくなった(互換性はあるため v4 でも利用可能)
  • 代わりに makeStyles という関数を使ってスタイルを定義する
  • className を props で与えるのではなくコンポーネント内で取得する

以下の記法は、React 16.8 で追加された フック(hook) を使っています。

Material-UI v4 での記法

スタイル付きコンポーネント作成の一例です。

MyStyledComponent.tsx
import * as React from 'react';
import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';

// スタイルを定義
const useStyles = makeStyles((theme: Theme) =>
  createStyles({
    root: {
      padding: theme.spacing(2)
    },
    title: {
      borderBottom: `2px solid ${theme.palette.primary.main}`
    }
  })
);

// props の型を定義
type Props = {
  title?: string;
};

// コンポーネントを定義
function MyStyledComponent({ title }: Props) {
  // ここでクラス名を取得
  const classes = useStyles();
  return (
    <div className={classes.root}>
      <h4 className={classes.title}>
        {title || 'My Styled Component'}
      </h4>
    </div>
  );
}

// エクスポート
export default MyStyledComponent;

React & Redux in TypeScript - Static Typing Guide を参考にしています。

1. インポート

// JavaScript の場合は createStyles, Theme は不要
import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';

createStyles は型拡大を防ぐ関数で TypeScript のときのみ任意で使用します。
Theme は Material テーマ (theme) の 型定義で、これを使うことでエディタの補助機能が効き入力が楽になります。

2. フック useStyles を定義

// JavaScript の場合は makeStyles(theme => styleObject)で良い
const useStyles = makeStyles((theme: Theme) =>
  createStyles({
    root: {
      padding: theme.spacing(2)
    },
    title: {
      borderBottom: `2px solid ${theme.palette.primary.main}`
    }
  })
);

ここで定義した useStylesmakeStyles で定義したスタイルオブジェクトの key と className の組を返すフックになります。

const classes = useStyles();
console.log(classes);
// => Object { root: "useStyles-root-41", title: "useStyles-title-56" }

3. コンポーネントの中で className を取得

function MyStyledComponent({ title }: Props) {
  const classes = useStyles();
  return (
    <div className={classes.root}>
      <h4 className={classes.title}>
        {title || 'タイトル'}
      </h4>
    </div>
  );
}

v3 のときは、コンポーネントの props で className を与えていましたが、v4 ではコンポーネントの中でフックを使ってクラス名を取得します。
これによって、コンポーネントの props の型定義 Props を拡張する必要がなくなりました。

したがって、v3 時代の Props extends WithStyles<typeof styles>export default withStyles(styles)(Component) という煩雑な書き方がなくなりすっきりとした表現になっています。

v3 以前からv4 への移行の注意点

v3 時代の withStyles(styles)(Component) という書き方は v4 でも可能です。
互換性がない変更点では、padding などを指定する際に使う theme.spacing が関数になりました。したがって、v3 以前の theme.spacing.unit * 2 という書き方ではエラーを吐いてしまいます。v3 から v4 へ移行するならまず theme.spacing の書き方を変更しましょう。

const useStyles = makeStyles((theme: Theme) => createStyles({
  root: {
    // v3 時代は theme.spacing.unit * 2 という書き方だった
    padding: theme.spacing(2)
  }
});

補足: React の記法について

ここは Material-UI に関係ないので読み飛ばしても構いません。
React + TypeScript の記法の流行り(?)に関する話題です。最終的には好みの問題になります。

Function Component で constfunction どちらを使うべきか

const MyComponent: React.FC<Props> = ({ title }: Props) => (
  <div>{ title }</div>
);
export default MyComponent;
function MyComponent({ title }: Props) {
  return (
    <div>{ title }</div>
  );
}
export default MyComponent;

最近は function 記法を目にすることが多いです。特に理由がなければ、React.FC<Props> はもう使わなくていいかもしれません。

また State を使う場合でも、クラス型コンポーネントを使わずに、React 16.8 で導入された フック で書いているドキュメントが多いです。

Props の定義は typeinterface

interface Props {
  title?: string;
}
type Props = {
  title?: string;
}

最近は type を使うのをよく目にします。
また state を使用する場合でも、 フックを使って、型定義 State を定義しない書き方を多く目にします。

最終的には好みの問題なので、自分のやりやすいように書いてください。

まとめ

ここでは手っ取り早く Material-UI v4 でのスタイル付きコンポーネントの記法について書きました。v4 についてもっと知りたい方は下記の Medium を読むと理解が深まるかと思います。

Material-UI v4 is out
https://medium.com/material-ui/material-ui-v4-is-out-4b7587d1e701

Material-UI
https://material-ui.com

React & Redux in TypeScript - Static Typing Guide
https://github.com/piotrwitek/react-redux-typescript-guide

フックの導入
https://ja.reactjs.org/docs/hooks-intro.html

フックに関するよくある質問
https://ja.reactjs.org/docs/hooks-faq.html

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away