Material-UI は React のデザインフレームワークです。HTML 組み込みのタグの代わりに Material-UI の定義するコンポーネントを用いることで簡単にリッチな画面を構成できます。
Material-UI: A popular React UI framework
【React】【Material-UI】テーマ機能で Material-UI コンポーネントのデフォルト値や CSS を定義する – 株式会社シーポイントラボ | 浜松のシステム・RTK-GNSS開発
Material-UI にはテーマ機能というものが存在します。端的に言えばこれは Matarial-UI コンポーネントのデフォルト値を定める機能です。次のコードの様にテーマを定義、読み込んだならば
// theme.js
export const theme = createMuiTheme({
props: {// 各コンポーネントの props についての定義
MuiFormControl: {
variant: 'outlined',// FormControlコンポーネントの variant のデフォルト値を 'outlined' に変更
},
},
});
// app.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import { theme } from './thema';
import { ThemeProvider } from '@material-ui/core/styles';
/**
* ルートコンポーネント
* @constructor
*/
function App() {
return (
<ThemeProvider theme={theme}>
{/* <AppRouter /> ページ本体 */}
</ThemeProvider>
);
}
ReactDOM.render(<App />, document.getElementById('app'));
どこで FormControl コンポーネントが呼ばれようとも、その props の varient の値は ‘outlined’ になります。この”どこ”というのは Material-UI の提供するコンポーネント内部も含まれています。そして Material-UI にはしばしば props をたらい回しにする様な組み込みコンポーネント(主に Textfield が絡んだフォーム関連)があります。例えば TextField API – Material-UI では次の様に記述してあります。
Any other props supplied will be provided to the root element (FormControl).
そして FormControl API – Material-UI では次の様にあります。
Any other props supplied will be provided to the root element (native element).
native element は素の HTML 要素のことでここまで行って終着点です。これをさらに複雑にするのが親コンポーネントの状態によってタグで囲った内部コンポーネントが Material-UI を使うユーザの知らない所で変化する処理です(大体よしなにしてくれるのですが意に反することをされると追いにくさが表に現れて辛くなります)。例えばこれは FormControl コンポーネント以下がわかりやすく次の様になります。
<FormControl variant="outlined">
{/* Select 内で使われる Input コンポーネントは外の outlined を参照して OutlinedInput になる*/}
<Select label="好きな食べ物" name="food">
</Select>
</FormControl>
<FormControl variant="filled">
{/* Select 内で使われる Input コンポーネントは外の filled を参照して FilledInput になる*/}
<Select label="好きな食べ物" name="food">
</Select>
</FormControl>
このたらい回しと変化する内部コンポーネントによってドキュメントや型ファイル上で未定義の props を渡して奥のコンポーネントに props を渡したり、props 内で別コンポーネントの props を定義したりする羽目になりやすいです。テーマを用いることでこの問題を解決しつつドキュメントに反さないままシンプルなコードを保てます。
これは次の様にできます。
/** コンポーネントコード。 props は素の HTML と同等 */
import React from "react";
import FormControl from "@material-ui/core/FormControl";
import InputLabel from "@material-ui/core/InputLabel";
import Select from "@material-ui/core/Select";
import MenuItem from "@material-ui/core/MenuItem";
export default function BasicTextFields() {
return (
<FormControl>
<InputLabel>好きな食べ物</InputLabel>
<Select label="好きな食べ物" name="food">
<MenuItem value="apple">りんご</MenuItem>
<MenuItem value="orange">みかん</MenuItem>
<MenuItem value="grape">ぶどう</MenuItem>
<MenuItem value="banana">バナナ</MenuItem>
</Select>
</FormControl>
);
}
/** テーマコード。 props のデフォルト値を定義 */
export const theme = createMuiTheme({
overrides: {
MuiFormControl: {
root: {
width: "100%"
}
}
},
props: {
MuiFormControl: {
variant: "outlined"
},
MuiInputLabel: {
shrink: true
},
MuiOutlinedInput: {
notched: true
}
}
});
デモが次です。全く同じの props がすかすかのコンポーネントコードを使っていますが片方にはテーマを適用し、もう片方にはテーマを適用していません。