🔗 3. ミックスイン
Bad
// overlay_controller.js
import { Controller } from "stimulus";
export default class extends Controller {
showOverlay(e) {
// ...
}
hideOverlay(e) {
// ...
}
}
// dropdown_controller.js
import OverlayController from "./overlay_controller";
export default class extends OverlayController {
//...
}
// flyout_controller.js
import OverlayController from "./overlay_controller";
export default class extends OverlayController {
//...
}
Good
// mixins/useOverlay.js
export const useOverlay = controller => {
Object.assign(controller, {
showOverlay(e) {
// ...
},
hideOverlay(e) {
// ...
}
});
};
// dropdown_controller.js
import { useOverlay } from "./mixins/useOverlay";
export default class extends Controller {
connect() {
useOverlay(this);
}
//...
}
// flyout_controller.js
import { useOverlay } from "./mixins/useOverlay";
export default class extends Controller {
connect() {
useOverlay(this);
}
//...
}
そうする理由
Stimulusのコントローラは、ミックスインとして使うことが想定されています。つまり、1個のDOM要素に複数のコントローラを適用して振る舞いをミックスするということです。しかし、振る舞いをコントローラレベルで共有するのが望ましいこともあります。この場合、継承は必ずしも解決策にはなりません。
たとえば、異なる2つの親から動作を継承する必要があることがわかったとしても、JavaScriptでは不可能です。多くの場合、コントローラ間で利用できる振る舞いを単純な方法でミックスするのが望ましい方法です。
もし、継承とミックスインのどちらが正しいパターンなのかわからない場合は、以下を自分自身に問いかけてみてください。
- コントローラがターゲットに対して"is-a"関係の場合 => 継承を使う
- コントローラがターゲットに対して"acts-as-a"関係の場合 => ミックスインを使う
注意
ミックスインが正しい選択ではない可能性もあります。コンポジションの方がニーズに合うこともあります。
今モデリングしているものがトレイト("acts-as-a")かコラボレーター("has a")であれば、コンポジションを使いましょう。つまり、コラボレーターを別のJavaScriptモジュールまたはクラスとしてモデル化し、connect
メソッドでそれをインスタンス化するということです。
概要
原著者の許諾を得て翻訳・公開いたします。