dioxus-provider 0.2.0

Data fetching and caching library for Dioxus applications with intelligent caching strategies and global providers.
Documentation
# Migration Guide: v0.0.x → v0.1.0

This guide will help you migrate your code from dioxus-provider v0.0.x to v0.1.0.

## Overview

Version 0.1.0 introduces several improvements and minor breaking changes focused on:
- Simplified initialization
- Unified cache APIs
- Consistent state types
- Better error handling
- Improved module organization

All deprecated APIs remain available but will show compiler warnings encouraging migration.

## Breaking Changes

### 1. Global Initialization (Recommended Update)

The initialization system has been consolidated for better developer experience.

**Before:**
```rust
use dioxus_provider::global::init_global_providers;
use dioxus_provider::injection::init_dependency_injection;

fn main() {
    init_global_providers();
    init_dependency_injection();  // If using DI
    dioxus::launch(app);
}
```

**After:**
```rust
use dioxus_provider;

fn main() {
    // Single init handles both providers and dependency injection
    dioxus_provider::init();
    dioxus::launch(app);
}
```

**Alternative (granular control):**
```rust
use dioxus_provider::ProviderConfig;

fn main() {
    // Only initialize providers (no DI)
    ProviderConfig::new().init();
    
    // Or with dependency injection
    ProviderConfig::new()
        .with_dependency_injection()
        .init();
        
    dioxus::launch(app);
}
```

### 2. Removed Functions

The following deprecated functions have been removed:

- `get_global_cache_panic()` → Use `get_global_cache()?` with error handling
- `get_global_refresh_registry_panic()` → Use `get_global_refresh_registry()?`

**Before:**
```rust
let cache = get_global_cache_panic();
```

**After:**
```rust
let cache = get_global_cache().expect("Providers not initialized");
// Or handle the error properly
let cache = get_global_cache()?;
```

## API Improvements (Non-Breaking)

### 3. Unified Cache API

The cache now provides a unified `get_with_options()` method for more flexible retrieval.

**Before:**
```rust
// Old separate methods
let data = cache.get_with_expiration::<MyType>("key", Some(Duration::from_secs(60)));
let (data, is_stale) = cache.get_with_staleness::<MyType>("key", stale_time, expiration);
```

**After:**
```rust
use dioxus_provider::cache::CacheGetOptions;

// Unified options API
let options = CacheGetOptions::new()
    .with_expiration(Duration::from_secs(300))
    .with_stale_time(Duration::from_secs(60));
    
let result = cache.get_with_options::<MyType>("key", options);
if let Some(result) = result {
    println!("Data: {:?}, Stale: {}", result.data, result.is_stale);
}

// Simple get still works for common cases
let data = cache.get::<MyType>("key");
```

### 4. AsyncState Trait

Both `ProviderState` and `MutationState` now implement a unified `AsyncState` trait.

**Before:**
```rust
// Duplicate helper methods on each type
match &*mutation_state.read() {
    MutationState::Loading => { /* ... */ },
    MutationState::Success(data) => { /* ... */ },
    // ...
}
```

**After:**
```rust
use dioxus_provider::prelude::AsyncState;

// Same API for both provider and mutation states
if state.read().is_loading() {
    // Works for both ProviderState and MutationState
}

let data = state.read().data();  // Unified method
```

### 5. Enhanced MutationContext

New helper methods make working with mutations easier:

```rust
use dioxus_provider::prelude::*;

#[mutation(invalidates = [fetch_items])]
async fn add_item(
    item: String,
    ctx: MutationContext<Vec<String>, String>,
) -> Result<Vec<String>, String> {
    // NEW: map_or_else provides a default
    Ok(ctx.map_or_else(
        || vec![item.clone()],  // Default if no cache
        |items| items.push(item.clone())
    ))
}

#[mutation(invalidates = [fetch_counter])]
async fn increment(
    ctx: MutationContext<i32, String>,
) -> Result<i32, String> {
    // NEW: update_in_place is more explicit
    ctx.update_in_place(|count| *count += 1)
        .ok_or_else(|| "No counter available".to_string())
}

// NEW: Helper methods
ctx.has_data();   // Check if cache has data
ctx.has_error();  // Check if cache has error
```

## Module Organization Changes

The internal module structure has been reorganized for clarity:

- `src/hooks/main.rs``src/hooks/provider.rs` (internal change, no API impact)
- Helper modules moved to `src/hooks/internal/` (internal change, no API impact)

These changes don't affect public APIs.

## Feature Flags

### New: `tracing` Feature (Enabled by Default)

Logging is now optional via the `tracing` feature flag, which is enabled by default:

```toml
# Default: tracing enabled with emojis
[dependencies]
dioxus-provider = "0.1"

# Disable all logging (smaller binary, better performance)
[dependencies]
dioxus-provider = { version = "0.1", default-features = false }

# Enable tracing with plain text (no emojis)  
[dependencies]
dioxus-provider = { version = "0.1", features = ["plain-logs"] }
```

**Benefits:**
- **Performance**: Disabling tracing can improve performance in production
- **Binary Size**: Reduces binary size by removing tracing dependencies
- **Flexibility**: Choose emoji-decorated or plain text logging

## Deprecation Timeline

- **v0.1.0**: Old APIs deprecated with warnings
- **v0.2.0** (planned): Deprecated APIs will be removed

## Quick Migration Checklist

- [ ] Replace `init_global_providers()` and `init_dependency_injection()` with `dioxus_provider::init()`
- [ ] Remove calls to removed `get_global_cache_panic()` and similar functions
- [ ] Optional Update cache operations to use `get_with_options()` for better clarity
- [ ] Optional Add `AsyncState` trait usage for cleaner state checking
- [ ] Optional Use new `MutationContext` helper methods for cleaner mutation code
- [ ] Run `cargo check` and fix any deprecation warnings
- [ ] Test your application to ensure everything works correctly

## Need Help?

- Check the [examples]./examples/ for updated usage patterns
- Review the API documentation for detailed information
- Open an issue on GitHub if you encounter migration problems

## Example: Full Migration

**Before (v0.0.x):**
```rust
use dioxus::prelude::*;
use dioxus_provider::{
    global::init_global_providers,
    injection::init_dependency_injection,
    prelude::*,
};

fn main() {
    init_global_providers();
    init_dependency_injection();
    dioxus::launch(App);
}

#[component]
fn App() -> Element {
    let user = use_provider(fetch_user(), (1,));
    
    match &*user.read() {
        ProviderState::Loading { .. } => rsx! { "Loading..." },
        ProviderState::Success(data) => rsx! { "{data}" },
        ProviderState::Error(e) => rsx! { "Error: {e}" },
    }
}
```

**After (v0.1.0):**
```rust
use dioxus::prelude::*;
use dioxus_provider::prelude::*;

fn main() {
    // Simplified initialization
    dioxus_provider::init();
    dioxus::launch(App);
}

#[component]
fn App() -> Element {
    let user = use_provider(fetch_user(), (1,));
    
    // Same pattern matching works, or use new helpers
    if user.read().is_loading() {
        return rsx! { "Loading..." };
    }
    
    match user.read().data() {
        Some(data) => rsx! { "{data}" },
        None => rsx! { "Error or loading" },
    }
}
```