Skip to content
Mithril.js 2
Main Navigation ガイドAPI

日本語

English
简体中文
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
한국어
Italiano
Polski
Türkçe
čeština
magyar

日本語

English
简体中文
繁體中文
Español
Français
Русский
Português – Brasil
Deutsch
한국어
Italiano
Polski
Türkçe
čeština
magyar

外観

Sidebar Navigation

はじめに

インストール方法

シンプルなアプリケーション

リソース

JSX

レガシーブラウザでの ES6+ の利用

アニメーション

テスト

例

サードパーティとの統合

パスの取り扱い

主要な概念

Virtual DOM ノード

コンポーネント

ライフサイクルメソッド

Key(キー)

自動再描画システム

その他

フレームワークの比較

v1.x からの移行

v0.2.x からの移行

API

このページの内容

JSX ​

説明 ​

JSX は、JavaScript のコード中に HTML のタグを記述できる構文拡張です。JavaScript の標準仕様ではありませんが、アプリケーション開発において必須ではありません。しかし、JSX を利用することで、コードの可読性や保守性が向上し、開発効率を高めることができます。チームのコーディングスタイルに合わせて、導入を検討すると良いでしょう。

jsx
function MyComponent() {
  return {
    view: () => m('main', [m('h1', 'Hello world')]),
  };
}

// 次のように記述できます:

function MyComponent() {
  return {
    view: () => (
      <main>
        <h1>Hello world</h1>
      </main>
    ),
  };
}

JSX 内では、中括弧 {} を使用して JavaScript の式を埋め込むことができます。

jsx
var greeting = 'Hello';
var url = 'https://google.com';
var link = <a href={url}>{greeting}!</a>;
// <a href="https://google.com">Hello!</a> が生成されます

コンポーネントは、コンポーネント名の先頭を大文字にする規則に従うか、プロパティとしてアクセスすることで使用できます。

jsx
m.render(document.body, <MyComponent />)
// m.render(document.body, m(MyComponent)) と同等
<m.route.Link href="/home">Go home</m.route.Link>
// m(m.route.Link, {href: "/home"}, "Go home") と同等

セットアップ ​

JSX を使用する最も簡単な方法は、Babel プラグインを利用することです。

Babel の利用には npm が必要です。npm は Node.js をインストールする際に自動的にインストールされます。npm をインストール後、プロジェクトフォルダを作成し、以下のコマンドを実行してください。

bash
npm init -y

Webpack と Babel を組み合わせて使用する場合は、以下のセクションを参照してください。

Babel をスタンドアロンツールとしてインストールするには、次のコマンドを実行します。

bash
npm install @babel/core @babel/cli @babel/preset-env @babel/plugin-transform-react-jsx --save-dev

.babelrc ファイルを作成します。

json
{
  "presets": ["@babel/preset-env"],
  "plugins": [
    [
      "@babel/plugin-transform-react-jsx",
      {
        "pragma": "m",
        "pragmaFrag": "'['"
      }
    ]
  ]
}

Babel を実行するための npm スクリプトを設定します。package.json を開き、"scripts" の下に次のエントリを追加します。

json
{
  "name": "my-project",
  "scripts": {
    "babel": "babel src --out-dir bin --source-maps"
  }
}

これで、次のコマンドを使用して Babel を実行できます。

bash
npm run babel

Webpack で Babel を使用する ​

Webpack をまだバンドラーとしてインストールしていない場合は、次のコマンドを実行します。

bash
npm install webpack webpack-cli --save-dev

次の手順に従って、Babel を Webpack に統合します。

bash
npm install @babel/core babel-loader @babel/preset-env @babel/plugin-transform-react-jsx --save-dev

.babelrc ファイルを作成します。

json
{
  "presets": ["@babel/preset-env"],
  "plugins": [
    [
      "@babel/plugin-transform-react-jsx",
      {
        "pragma": "m",
        "pragmaFrag": "'['"
      }
    ]
  ]
}

次に、webpack.config.js というファイルを作成します。

jsx
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, './bin'),
    filename: 'app.js',
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /\/node_modules\//,
        use: {
          loader: 'babel-loader',
        },
      },
    ],
  },
  resolve: {
    extensions: ['.js', '.jsx'],
  },
};

すでに Webpack に詳しい方は、Babel のオプションを webpack.config.js の babel-loader セクションに記述するとエラーが発生するため、.babelrc ファイルに記述する必要があることに注意してください。

この構成では、アプリケーションのエントリポイントとなるソースコードファイルが src/index.js にあり、バンドルされたファイルが bin/app.js に出力されることを前提としています。

バンドラーを実行するための npm スクリプトを設定します。package.json を開き、"scripts" の下に次のエントリを追加します。

json
{
  "name": "my-project",
  "scripts": {
    "start": "webpack --mode development --watch"
  }
}

コマンドラインから次を実行して、バンドラーを実行できます。

bash
npm start

プロダクションビルド ​

ミニファイされたファイルを生成するには、package.json を開き、build という名前の新しい npm スクリプトを追加します。

json
{
  "name": "my-project",
  "scripts": {
    "start": "webpack -d --watch",
    "build": "webpack -p"
  }
}

本番環境でフックを使用して、本番ビルドスクリプトを自動的に実行できます。Heroku の例を次に示します。

json
{
  "name": "my-project",
  "scripts": {
    "start": "webpack -d --watch",
    "build": "webpack -p",
    "heroku-postbuild": "webpack -p"
  }
}

m をグローバルにアクセス可能にする ​

プロジェクト全体から m (Mithril の関数) にグローバルにアクセスできるようにするには、まず webpack.config.js で webpack を次のようにインポートします。

js
const webpack = require('webpack');

次に、Webpack 構成オブジェクトの plugins プロパティに新しいプラグインを作成します。

js
{
  plugins: [
    new webpack.ProvidePlugin({
      m: 'mithril',
    }),
  ];
}

ProvidePlugin の詳細については、Webpack のドキュメントを参照してください。

React との違い ​

Mithril の JSX には、React の JSX と比較して、いくつかの微妙な違いがあります。

属性とスタイルのプロパティの命名規則 ​

React では、data-* および aria-* 属性を除き、HTML 属性名の代わりにキャメルケースの DOM プロパティ名を使用する必要があります。たとえば、class の代わりに className、for の代わりに htmlFor を使用します。一方、Mithril では、小文字の HTML 属性名を使用するのが一般的です。Mithril は、プロパティが存在しない場合に属性の設定にフォールバックするため、HTML とより直感的に整合性が取れます。ほとんどの場合、DOM プロパティと HTML 属性名は同じか、非常に似ています。たとえば、入力要素の value/checked や、HTML 要素の elem.tabIndex プロパティに対する tabindex グローバル属性などです。大文字小文字の違いを超えて異なることはまれです。class 属性の elem.className プロパティや、for 属性の elem.htmlFor プロパティは、数少ない例外です。

同様に、React は常に、elem.style のプロパティを介して DOM で公開されるキャメルケースのスタイルプロパティ名(cssHeight や backgroundColor など)を使用します。Mithril は、キャメルケースとケバブケースの CSS プロパティ名(height や background-color など)の両方をサポートしており、慣例的に後者を優先します。cssHeight、cssFloat、およびベンダープレフィックス付きのプロパティのみが、大文字小文字の違いを超えて異なります。

DOM イベント ​

React では、すべてのイベントハンドラーの先頭の文字を大文字にします。onClick は click イベントをリッスンし、onSubmit は submit イベントをリッスンします。複数の単語が連結されている場合は、さらに変更されます。たとえば、onMouseMove は mousemove イベントをリッスンします。Mithril ではこのケースマッピングは行われず、代わりにネイティブイベントに on を付与するだけです。したがって、onclick および onmousemove のリスナーを追加することで、それぞれ 2 つのイベントをリッスンできます。これは HTML の命名規則とより密接に対応しており、HTML またはバニラ JavaScript の DOM の知識がある場合は、より直感的です。

React は、キャプチャフェーズ中にイベントリスナーをスケジュールすることをサポートしています(デフォルトのバブリングフェーズが 2 回目のパスで内側から外側に向かうのとは対照的に、最初のパスで外側から内側に向かう)。Mithril には現在そのような機能はありませんが、将来的にサポートされる可能性があります。必要な場合は、ライフサイクルフックで独自のリスナーを手動で追加および削除できます。

JSX vs hyperscript ​

JSX と hyperscript は、仮想ノード (vnode) を記述するために使用できる 2 つの異なる構文であり、それぞれに異なる利点と欠点があります。

  • JSX は、HTML/XML の知識があり、その種の構文で DOM 要素を記述する方が快適な場合に、より扱いやすいでしょう。また、句読点が少なく、属性に含まれる視覚的なノイズが少ないため、よりクリーンな印象になり、読みやすいと感じる人も多いでしょう。そしてもちろん、多くの一般的なエディターは、HTML と同じように DOM 要素のオートコンプリートをサポートしています。ただし、使用するには追加のビルドステップが必要であり、エディターのサポートは通常の JS ほど広くなく、コードが冗長になる傾向があります。また、動的なコンテンツを多く扱う場合は、すべてに補間を使用する必要があるため、少し冗長になります。

  • Hyperscript は、HTML や XML をあまり使用しないバックエンド JS の経験がある場合に、より適しているでしょう。JSX よりも冗長性が少なく、より簡潔であり、静的なクラス、ID、およびその他の属性に対して CSS のような糖衣構文を提供します。また、ビルドステップなしで使用できますが、必要に応じて追加できます。また、何も「補間」する必要がないため、動的なコンテンツに直面した場合に、わずかに簡単に操作できます。ただし、簡潔さゆえに読みにくくなる場合があります。特に経験が浅く、フロントエンドの HTML/CSS/XML の知識がない場合は、読みにくくなる可能性があります。また、ID、クラス、属性などの hyperscript セレクターの一部を自動補完するプラグインは、今のところ一般的ではありません。

より複雑なツリーでは、利点と欠点がどのように作用するかを確認できます。たとえば、@dead-claudia による実際のプロジェクトから採用され、明確さと読みやすさのためにいくつかの変更が加えられた、この hyperscript ツリーを検討してください。

javascript
function SummaryView() {
  let tag, posts;

  function init({ attrs }) {
    Model.sendView(attrs.tag != null);
    if (attrs.tag != null) {
      tag = attrs.tag.toLowerCase();
      posts = Model.getTag(tag);
    } else {
      tag = undefined;
      posts = Model.posts;
    }
  }

  function feed(type, href) {
    return m('.feed', [
      type,
      m('a', { href }, m('img.feed-icon[src=./feed-icon-16.gif]')),
    ]);
  }

  return {
    oninit: init,
    // To ensure the tag gets properly diffed on route change.
    onbeforeupdate: init,
    view: () =>
      m('.blog-summary', [
        m('p', 'My ramblings about everything'),

        m('.feeds', [
          feed('Atom', 'blog.atom.xml'),
          feed('RSS', 'blog.rss.xml'),
        ]),

        tag != null
          ? m(TagHeader, { len: posts.length, tag })
          : m('.summary-header', [
              m('.summary-title', 'Posts, sorted by most recent.'),
              m(TagSearch),
            ]),

        m(
          '.blog-list',
          posts.map(post =>
            m(
              m.route.Link,
              {
                class: 'blog-entry',
                href: `/posts/${post.url}`,
              },
              [
                m(
                  '.post-date',
                  post.date.toLocaleDateString('en-US', {
                    year: 'numeric',
                    month: 'long',
                    day: 'numeric',
                  })
                ),

                m('.post-stub', [
                  m('.post-title', post.title),
                  m('.post-preview', post.preview, '...'),
                ]),

                m(TagList, { post, tag }),
              ]
            )
          )
        ),
      ]),
  };
}

JSX を使用した上記のコードとまったく同じものを次に示します。この部分だけを見ても 2 つの構文がどのように異なるか、およびどのような利点と欠点が適用されるかを確認できます。

jsx
function SummaryView() {
  let tag, posts;

  function init({ attrs }) {
    Model.sendView(attrs.tag != null);
    if (attrs.tag != null) {
      tag = attrs.tag.toLowerCase();
      posts = Model.getTag(tag);
    } else {
      tag = undefined;
      posts = Model.posts;
    }
  }

  function feed(type, href) {
    return (
      <div class="feed">
        {type}
        <a href={href}>
          <img class="feed-icon" src="./feed-icon-16.gif" />
        </a>
      </div>
    );
  }

  return {
    oninit: init,
    // To ensure the tag gets properly diffed on route change.
    onbeforeupdate: init,
    view: () => (
      <div class="blog-summary">
        <p>My ramblings about everything</p>

        <div class="feeds">
          {feed('Atom', 'blog.atom.xml')}
          {feed('RSS', 'blog.rss.xml')}
        </div>

        {tag != null ? (
          <TagHeader len={posts.length} tag={tag} />
        ) : (
          <div class="summary-header">
            <div class="summary-title">Posts, sorted by most recent</div>
            <TagSearch />
          </div>
        )}

        <div class="blog-list">
          {posts.map(post => (
            <m.route.Link class="blog-entry" href={`/posts/${post.url}`}>
              <div class="post-date">
                {post.date.toLocaleDateString('en-US', {
                  year: 'numeric',
                  month: 'long',
                  day: 'numeric',
                })}
              </div>

              <div class="post-stub">
                <div class="post-title">{post.title}</div>
                <div class="post-preview">{post.preview}...</div>
              </div>

              <TagList post={post} tag={tag} />
            </m.route.Link>
          ))}
        </div>
      </div>
    ),
  };
}

ヒントとコツ ​

HTML を JSX に変換する ​

Mithril.js では、整形式の HTML は一般に有効な JSX です。通常は、attr=value のように引用符で囲まれていないプロパティ値を attr="value" に変更したり、<input> のような空タグを <input /> に変更したりする程度です。これは、JSX が HTML ではなく XML に準拠しているためです。

hyperscript を使用する場合、HTML を hyperscript 構文に変換して使用する必要があることがよくあります。このプロセスをスピードアップするために、コミュニティが作成した HTML-to-Mithril-template コンバーターを使用して、変換作業の多くを自動化できます。

Pager
前のページシンプルなアプリケーション
次のページレガシーブラウザでの ES6+ の利用

MITライセンス の下で公開されています。

Copyright (c) 2024 Mithril Contributors

https://mithril.js.org/jsx.html

MITライセンス の下で公開されています。

Copyright (c) 2024 Mithril Contributors