# Tasks and Observables
*Handle asynchronous operations and reactive data streams with Tasks and Observables for responsive [application](./10_Apps.md) behavior.*
Ivy provides powerful abstractions for working with asynchronous operations and reactive data streams. **Tasks** handle one-time asynchronous operations, while **Observables** manage continuous data streams that automatically update the UI when data changes.
## Basic Task Usage
Tasks represent asynchronous operations that complete once and return a result. Ivy provides `TaskView<T>` to automatically handle loading states and display results. See [UseState](../../03_Hooks/02_Core/03_UseState.md) and [UseEffect](../../03_Hooks/02_Core/04_UseEffect.md) for reactive state patterns.
```csharp
public class TaskExample : ViewBase
{
public override object? Build()
{
var task = Task.Run(async () =>
{
await Task.Delay(2000);
return "Task completed successfully!";
});
return new TaskView<string>(task);
}
}
```
## Basic Observable Usage
Ivy's `ObservableView<T>` automatically subscribes and updates the UI as new values arrive. This example uses [UseRef](../../03_Hooks/02_Core/08_UseRef.md) to hold the observable and [UseState](../../03_Hooks/02_Core/03_UseState.md) to control it.
```csharp
public class TimeBasedObservableExample : ViewBase
{
public override object? Build()
{
var isActive = UseState<bool>(false);
var timeObservable = UseRef(() =>
Observable.Interval(TimeSpan.FromMilliseconds(500))
.Where(_ => isActive.Value)
.Select(_ => DateTime.Now.ToString("HH:mm:ss.fff"))
).Value;
return Layout.Vertical(
Layout.Horizontal(
new Button("Start", _ => isActive.Value = true),
new Button("Stop", _ => isActive.Value = false)
),
Text.Block("Time Updates:"),
new ObservableView<string>(timeObservable)
);
}
}
```
### Observable with State Management
This example demonstrates how to properly manage [state](../../03_Hooks/02_Core/03_UseState.md) with observables by controlling when subscriptions are active. It shows a timer-based counter that only increments when a state flag is active, with proper UI updates and subscription cleanup.
```csharp
public class StateManagementExample : ViewBase
{
public override object? Build()
{
var counter = UseState<int>(0);
var isRunning = UseState<bool>(false);
var timerObservable = UseRef(() =>
Observable.Interval(TimeSpan.FromSeconds(1))
).Value;
UseEffect(() =>
{
var subscription = timerObservable.Subscribe(_ =>
{
if (isRunning.Value)
{
counter.Set(prev => prev + 1);
}
});
return subscription;
});
return Layout.Vertical(
Layout.Horizontal(
new Button("Start", _ => isRunning.Value = true),
new Button("Stop", _ => isRunning.Value = false),
new Button("Reset", _ => counter.Value = 0)
),
Text.Block($"Counter: {counter.Value}"),
Text.Block($"Status: {(isRunning.Value ? "Running" : "Stopped")}")
);
}
}
```
### Observable with Throttling
This example demonstrates how to use observables for search functionality with [performance optimizations](../../03_Hooks/02_Core/05_UseMemo.md). It shows throttled updates to prevent excessive filtering while typing, and proper [state management](../../03_Hooks/02_Core/03_UseState.md) to avoid duplicate data.
```csharp
public class ObservableSearchExample : ViewBase
{
public override object? Build()
{
var inputText = UseState<string>("");
var originalItems = UseState<string[]>(new[] { "Apple", "Banana", "Cherry", "Date", "Elderberry", "Fig", "Grape", "Honeydew" });
var filteredItems = UseState<string[]>(Array.Empty<string>());
UseEffect(() => {
filteredItems.Set(originalItems.Value);
}, []);
var searchObservable = UseRef(() =>
Observable.Interval(TimeSpan.FromMilliseconds(300))
.Select(_ => inputText.Value)
.DistinctUntilChanged()
).Value;
UseEffect(() =>
{
return searchObservable.Subscribe(searchTerm =>
{
if (string.IsNullOrWhiteSpace(searchTerm))
{
filteredItems.Set(originalItems.Value);
}
else
{
var filtered = originalItems.Value
.Where(item => item.Contains(searchTerm, StringComparison.OrdinalIgnoreCase))
.ToArray();
filteredItems.Set(filtered);
}
});
});
return Layout.Vertical(
Text.Block("Observable Search: "),
Layout.Horizontal(
new TextInput(inputText, placeholder: "Type to filter (throttled)..."),
new Button("Clear", _ => inputText.Set(""))
),
Text.Block($"Found {filteredItems.Value.Length} of {originalItems.Value.Length} items"),
Layout.Vertical(
filteredItems.Value.Select(item =>
Text.Block(item)
)
)
);
}
}
```
### Observable Transformations
This example demonstrates interactive data transformation with immediate feedback. It demonstrates filtering, projection, and limiting operations to create processed transformed results.
```csharp
public class TransformationExample : ViewBase
{
public override object? Build()
{
var generatedData = UseState<int[]>(Array.Empty<int>());
var lastTransformed = UseState<int[]>(Array.Empty<int>());
void GenerateNewData(Event<Button> _)
{
var random = new Random();
var newData = Enumerable.Range(1, 10)
.Select(_ => random.Next(1, 21))
.ToArray();
generatedData.Set(newData);
var immediateResult = newData
.Where(num => num % 2 == 0)
.Select(num => num * 2)
.Take(5)
.ToArray();
lastTransformed.Set(immediateResult);
}
return Layout.Vertical(
new Button("Generate New Data", GenerateNewData),
Text.Block("Generated data: " + string.Join(", ", generatedData.Value)),
Text.Block("Last Generated Result: " + string.Join(", ", lastTransformed.Value))
);
}
}
```