ratatui/examples/concepts/state/src/bin/stateful-widget.rs
Josh McKinney cfb65e64ba
docs: add examples for handling state (#1849)
Added comprehensive state management examples covering both immutable
and mutable patterns and documentation to help developers choose the
right approach for their applications.
2025-06-26 13:04:42 -07:00

79 lines
2.9 KiB
Rust

//! # StatefulWidget Pattern (Recommended)
//!
//! This example demonstrates the `StatefulWidget` trait, which is the recommended approach for
//! handling mutable state in Ratatui applications. This pattern separates the widget's rendering
//! logic from its state, making it more flexible and reusable.
//!
//! This example runs with the Ratatui library code in the branch that you are currently
//! reading. See the [`latest`] branch for the code which works with the most recent Ratatui
//! release.
//!
//! [`latest`]: https://github.com/ratatui/ratatui/tree/latest
//!
//! ## When to Use This Pattern
//!
//! - Most Ratatui applications (this is the recommended default)
//! - When building reusable widget libraries
//! - When you need clean separation between rendering logic and state
//! - When multiple widgets might share similar state structures
//! - When you want to follow idiomatic Ratatui patterns
//!
//! ## Trade-offs
//!
//! **Pros:**
//! - Clean separation of concerns between widget and state
//! - Reusable - the same widget can work with different state instances
//! - Testable - state and rendering logic can be tested independently
//! - Composable - works well with complex application architectures
//! - Idiomatic - follows Ratatui's recommended patterns
//!
//! **Cons:**
//! - Slightly more verbose than direct mutation patterns
//! - Requires understanding of the `StatefulWidget` trait
//! - State must be managed externally
//!
//! ## Example Usage
//!
//! The widget defines its rendering behavior through `StatefulWidget`, while the state is
//! managed separately. This allows the same widget to be used with different state instances
//! and makes testing easier.
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use ratatui::widgets::{StatefulWidget, Widget};
use ratatui_state_examples::is_exit_key_pressed;
/// Demonstrates the StatefulWidget pattern for mutable state management.
///
/// Creates a counter widget using `StatefulWidget` and runs the application loop,
/// updating the counter on each render cycle until the user exits.
fn main() -> color_eyre::Result<()> {
color_eyre::install()?;
ratatui::run(|terminal| {
let mut counter = 0;
loop {
terminal.draw(|frame| {
frame.render_stateful_widget(CounterWidget, frame.area(), &mut counter)
})?;
if is_exit_key_pressed()? {
break Ok(());
}
}
})
}
/// A counter widget that uses the StatefulWidget pattern for state management.
///
/// Demonstrates the separation of rendering logic from state, making the widget reusable
/// with different state instances and easier to test.
struct CounterWidget;
impl StatefulWidget for CounterWidget {
type State = usize;
fn render(self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
*state += 1;
format!("Counter: {state}").render(area, buf);
}
}