Entity management and state handling in GPUI. Use when working with entities, managing component state, coordinating between components, handling async operations with state updates, or implementing reactive patterns. Entities provide safe concurrent access to application state.
An Entity<T> is a handle to state of type T, providing safe access and updates.
Key Methods:
entity.read(cx) → &T - Read-only accessentity.read_with(cx, |state, cx| ...) → R - Read with closureentity.update(cx, |state, cx| ...) → R - Mutable updateentity.downgrade() → WeakEntity<T> - Create weak referenceentity.entity_id() → EntityId - Unique identifierEntity Types:
Entity<T>: Strong reference (increases ref count)WeakEntity<T>: Weak reference (doesn't prevent cleanup, returns Result)// Create entity
let counter = cx.new(|cx| Counter { count: 0 });
// Read state
let count = counter.read(cx).count;
// Update state
counter.update(cx, |state, cx| {
state.count += 1;
cx.notify(); // Trigger re-render
});
// Weak reference (for closures/callbacks)
let weak = counter.downgrade();
let _ = weak.update(cx, |state, cx| {
state.count += 1;
cx.notify();
});
struct MyComponent {
shared_state: Entity<SharedData>,
}
impl MyComponent {
fn new(cx: &mut App) -> Entity<Self> {
let shared = cx.new(|_| SharedData::default());
cx.new(|cx| Self {
shared_state: shared,
})
}
fn update_shared(&mut self, cx: &mut Context<Self>) {
self.shared_state.update(cx, |state, cx| {
state.value = 42;
cx.notify();
});
}
}
impl MyComponent {
fn fetch_data(&mut self, cx: &mut Context<Self>) {
let weak_self = cx.entity().downgrade();
cx.spawn(async move |cx| {
let data = fetch_from_api().await;
// Update entity safely
let _ = weak_self.update(cx, |state, cx| {
state.data = Some(data);
cx.notify();
});
}).detach();
}
}
// ✅ Good: Weak reference prevents retain cycles
let weak = cx.entity().downgrade();
callback(move || {
let _ = weak.update(cx, |state, cx| cx.notify());
});
// ❌ Bad: Strong reference may cause memory leak
let strong = cx.entity();
callback(move || {
strong.update(cx, |state, cx| cx.notify());
});
// ✅ Good: Use inner cx from closure
entity.update(cx, |state, inner_cx| {
inner_cx.notify(); // Correct
});
// ❌ Bad: Use outer cx (multiple borrow error)
entity.update(cx, |state, inner_cx| {
cx.notify(); // Wrong!
});
// ✅ Good: Sequential updates
entity1.update(cx, |state, cx| { /* ... */ });
entity2.update(cx, |state, cx| { /* ... */ });
// ❌ Bad: Nested updates (may panic)
entity1.update(cx, |_, cx| {
entity2.update(cx, |_, cx| { /* ... */ });
});
Patterns: See patterns.md
Best Practices: See best-practices.md
Advanced Patterns: See advanced.md