Skip to content

Component Architecture

TUIを整理するためのよりオブジェクト指向のアプローチに興味がある場合は、 Component ベースのアプローチを使用できます。

野生のいくつかのプロジェクトはこのアプローチを使用しています

また、この Component ベースのアプローチの例がある component テンプレートもあります。

前のセクションでは、すでに TEA をカバーしています。 Component アーキテクチャは、オブジェクト指向のtrait ベースのアプローチをわずかに必要とします。

各コンポーネントは、独自の状態、イベントハンドラー、およびレンダリングロジックをカプセル化します。

  1. コンポーネントの初期化 ( init ) - これは、コンポーネントが必要な初期状態またはリソースを設定できる場所です。これは、イベントの処理やレンダリングとは別のプロセスです。

  2. イベントハンドリング ( handle_eventshandle_key_eventshandle_mouse_events ) - 各コンポーネントには独自のイベントハンドラーがあります。これにより、各コンポーネントは興味のあるイベントのみを扱うイベント処理に対するより細かいアプローチが可能になります。これは、アプリケーション全体のメッセージを処理するELMの単一の更新関数とは対照的です。

  3. StateUpdate ( update ) - コンポーネントは独自のローカル状態を持ち、アクションに応じて更新できます。この状態は、エルムのグローバルモデルとは異なるコンポーネントに対して非公開です。

  4. レンダリング ( render ) - 各コンポーネントは、独自のレンダリングロジックを定義します。レンダリングのコンテキストを考えると、それ自体を描く方法を知っています。これは、ELMのビュー関数に似ていますが、コンポーネントごとにコンポーネントベースです。

使用する可能性のある Component trait 実装の例は次のとおりです。

use color_eyre::eyre::Result;
use ratatui::crossterm::event::{KeyEvent, MouseEvent};
use ratatui::layout::Rect;
use crate::{action::Action, event::Event, terminal::Frame};
pub trait Component {
fn init(&mut self) -> Result<()> {
Ok(())
}
fn handle_events(&mut self, event: Option<Event>) -> Action {
match event {
Some(Event::Quit) => Action::Quit,
Some(Event::Tick) => Action::Tick,
Some(Event::Key(key_event)) => self.handle_key_events(key_event),
Some(Event::Mouse(mouse_event)) => self.handle_mouse_events(mouse_event),
Some(Event::Resize(x, y)) => Action::Resize(x, y),
Some(_) => Action::Noop,
None => Action::Noop,
}
}
fn handle_key_events(&mut self, key: KeyEvent) -> Action {
Action::Noop
}
fn handle_mouse_events(&mut self, mouse: MouseEvent) -> Action {
Action::Noop
}
fn update(&mut self, action: Action) -> Action {
Action::Noop
}
fn render(&mut self, f: &mut Frame, rect: Rect);
}

このアプローチの利点の1つは、 handle_eventsupdaterender をコンポーネントレベルで共同配置することです。