LoginSignup
4
2

More than 3 years have passed since last update.

React.jsでemotionを使うときはJSX Pragmaをつける必要がありまして。

Posted at

普通にimportしただけだと動かない

EmotionというCSSフレームワークを使ってちょっとお試しで実装していました。

package.jsonは以下の通りとなっております。

{
  "dependencies": {
    "@emotion/core": "^10.0.28",
    "next": "9.4.4",
    "react": "16.13.1",
    "react-dom": "16.13.1"
  },
  "devDependencies": {
    "@types/node": "^14.0.22",
    "@types/react": "^16.9.43",
    "typescript": "^3.9.6"
  }
}

スタイルを設定したいページにEmotionをimportしたのですが・・・。

import { Global, css, jsx } from "@emotion/core";

これだけだとスタイルが適応されないので調査いたしました。
どうやら下記のように@jsx jsxがないとうまいことコンパイルされないようでした。

/** @jsx jsx */
import { Global, css, jsx } from "@emotion/core";

jsxをコンパイルする際は、Emotionは独自のコンパイラを通す必要があり、/** @jsx jsx */というJSX Pragmaの記述をしないと動きませんでした。

以下、名著「りあクト! TypeScriptで極める現場のReact開発」から引用

「Emotion はちょっと他のライブラリと違って特殊なことをしているので、使うにあたっていくつか注意事項があるのね。Emotion の文法を使って記述したJSXは通常React.createElement() ではなくEmotion が提供するコンパイラを通す必要があるの。」
「@emotion/core からインポートしてるjsx というのがそのコンパイラね。で、JSX リテラルで書いたコードをそれに渡すためにファイル冒頭で/** @jsx jsx */ の『JSX Pragma』というマジックワードを記述してあげてるの」
「えっ、言われるまで気づきませんでした。そうなんですね」
「さらに、これに起因する注意点が三つあるの。ひとつめは『親コンポーネントでJSX Pragma を使用したら、子のコンポーネントでもJSX Pragma を使わなければならない』こと」
「使わないとどうなるんですか?」
「『ReferenceError: React is not defined』って怒られてコンパイルに失敗するね。場合によっては直上の親コンポーネントにもJSX Pragma が必要なときもある。Presentational Component をインクルードしてContainer Component を作るときとか、それ自体がEmotion を使ってなくてもJSX Pragma を書かないとコンパイルが通らない」

コンパイルエラーとありますが、私の環境ではエラーは出ずに、スタイルが当たらないという状況でした。

実装例

Emotionでは子コンポーネントでもJSX Pragmaの記述が必要ということで、
お試しとして、Indexからヘッダーを呼び出すものを実装してみました。

↓こんな感じです。

src
│
└─pages
    index.tsx
    header.tsx
header.tsx
/** @jsx jsx */
import { Global, css, jsx } from "@emotion/core";

const globalCss = css`
  * {
    margin: 0;
    padding: 0;
  }
`;

const styles = {
  titleBase: css`
    height: 168px;
    width: 100%;
  `,
  title: css`
    height: 168px;
    width: 100%;
    font-family: Roboto;
    font-size: 64px;
    color: #ffffff;
    background: #2f80ed;
  `,
};

interface Props {
  title: string;
}

const Header = (props: Props) => {
  return (
    <>
      <Global styles={globalCss} />
      <div css={styles.titleBase}>
        <h1 css={styles.title}>{props.title}</h1>
      </div>
    </>
  );
};

export default Header;
index.tsx
import Header from "./header";
/** @jsx jsx */
import { css, jsx } from "@emotion/core";

const styles = {
  content: css`
    height: 100%;
    width: 100%;
    font-size: 64px;
  `,
};

export default function Index() {
  return (
    <>
      <Header title="タイトル" />
      <div css={styles.content}>Content</div>
    </>
  );
}

起動させると、こんな感じで表示されます。

Emotionをjsxで使いたい場合、JSX Pragmaを忘れずにつける必要がありました。気を付けたいですね

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2