Rust响应式状态管理库reactive_stores的使用,高效管理应用状态与数据流

use leptos::*;

#[component]
pub fn SimpleCounter(initial_value: i32) -> impl IntoView {
    // 创建一个具有初始值的响应式信号
    let (value, set_value) = signal(initial_value);

    // 为按钮创建事件处理器
    // 注意 `value` 和 `set_value` 是 `Copy` 的,所以很容易将它们移入闭包
    let clear = move |_| set_value(0);
    let decrement = move |_| set_value.update(|value| *value -= 1);
    let increment = move |_| set_value.update(|value| *value += 1);

    // 使用声明式的 `view!` 宏创建用户界面
    view! {
        <div>
            <button on:click=clear>Clear</button>
            <button on:click=decrement>-1</button>
            // 文本节点可以加引号或不加引号
            <span>"Value: " {value} "!"</span>
            <button on:click=increment>+1</button>
        </div>
    }
}

// 我们也支持构建器语法,而不是类似 JSX 的 `view` 宏
#[component]
pub fn SimpleCounterWithBuilder(initial_value: i32) -> impl IntoView {
    use leptos::html::*;

    let (value, set_value) = signal(initial_value);
    let clear = move |_| set_value(0);
    let decrement = move |_| set_value.update(|value| *value -= 1);
    let increment = move |_| set_value.update(|value| *value += 1);

    // 上面的 `view` 宏扩展为这个构建器语法
    div().child((
        button().on(ev::click, clear).child("Clear"),
        button().on(ev::click, decrement).child("-1"),
        span().child(("Value: ", value, "!")),
        button().on(ev::click, increment).child("+1")
    ))
}

// 易于与 Trunk 或简单的 wasm-bindgen 设置一起使用
pub fn main() {
    mount_to_body(|| view! {
        <SimpleCounter initial_value=3 />
    })
}

以下是使用 reactive_stores 进行响应式状态管理的完整示例:

use reactive_stores::*;
use leptos::*;

// 定义一个计数器状态
#[derive(Clone, Default)]
struct CounterState {
    count: i32,
}

// 实现状态操作
impl CounterState {
    fn increment(&mut self) {
        self.count += 1;
    }
    
    fn decrement(&mut self) {
        self.count -= 1;
    }
    
    fn clear(&mut self) {
        self.count = 0;
    }
}

// 创建全局状态存储
#[global_store]
static COUNTER_STORE: Store<CounterState> = Store::new(CounterState::default());

#[component]
pub fn CounterComponent() -> impl IntoView {
    // 订阅状态变化
    let state = use_store(COUNTER_STORE);
    
    // 创建事件处理器
    let increment = move |_| {
        COUNTER_STORE.update(|state| state.increment());
    };
    
    let decrement = move |_| {
        COUNTER_STORE.update(|state| state.decrement());
    };
    
    let clear = move |_| {
        COUNTER_STORE.update(|state| state.clear());
    };

    view! {
        <div>
            <h2>"响应式计数器"</h2>
            <button on:click=decrement>"-"</button>
            <span>"计数: " {move || state.get().count}</span>
            <button on:click=increment>"+"</button>
            <button on:click=clear>"清零"</button>
        </div>
    }
}

// 主应用组件
#[component]
pub fn App() -> impl IntoView {
    view! {
        <div>
            <h1>"Rust 响应式状态管理示例"</h1>
            <CounterComponent />
        </div>
    }
}

pub fn main() {
    mount_to_body(|| view! {
        <App />
    })
}

这个示例展示了如何使用 reactive_stores 库来管理应用状态:

  1. 定义了一个 CounterState 结构体来存储计数状态
  2. 使用 #[global_store] 宏创建全局状态存储
  3. 通过 use_store hook 订阅状态变化
  4. 使用 update 方法来修改状态
  5. 状态变化会自动触发 UI 更新

响应式状态管理的优势:

  • 细粒度响应性:只有依赖特定状态的组件才会重新渲染
  • 类型安全:Rust 的类型系统确保状态操作的安全性
  • 易于测试:状态逻辑可以与 UI 分离进行单元测试
  • 高性能:最小化的重新渲染开销

1 回复

Rust响应式状态管理库reactive_stores的使用指南

概述

reactive_stores是一个轻量级的Rust响应式状态管理库,专为高效管理应用状态和数据流而设计。它提供了简单直观的API,支持状态订阅、变更通知和自动依赖跟踪,适用于各种规模的Rust应用程序。

核心特性

  • 响应式状态变更通知
  • 自动依赖追踪
  • 零成本抽象
  • 线程安全设计
  • 最小化运行时开销

安装方法

在Cargo.toml中添加依赖:

[dependencies]
reactive_stores = "0.3.0"

基本使用方法

1. 创建状态存储

use reactive_stores::Store;

#[derive(Clone)]
struct AppState {
    count: i32,
    message: String,
}

let mut store = Store::new(AppState {
    count: 0,
    message: "Hello".to_string(),
});

2. 订阅状态变更

// 订阅整个状态
let subscription = store.subscribe(|state: &AppState| {
    println!("Count changed to: {}", state.count);
    println!("Message: {}", state.message);
});

// 订阅特定字段
let count_subscription = store.subscribe_to(|state: &AppState| state.count, |count| {
    println!("Count updated: {}", count);
});

3. 更新状态

// 直接更新
store.update(|state| {
    state.count += 1;
    state.message = "Updated".to_string();
});

// 使用事务批量更新
store.transaction(|state| {
    state.count = 42;
    state.message = "Transaction complete".to_string();
});

4. 读取状态

// 获取当前状态
let current_state = store.get_state();
println!("Current count: {}", current_state.count);

// 使用选择器获取派生状态
let derived = store.select(|state| state.count * 2);
println!("Double count: {}", derived);

高级用法示例

异步状态更新

use reactive_stores::Store;
use tokio::runtime::Runtime;

#[derive(Clone)]
struct AsyncState {
    data: Vec<String>,
    loading: bool,
}

let rt = Runtime::new().unwrap();
let mut store = Store::new(AsyncState {
    data: Vec::new(),
    loading: false,
});

// 异步更新示例
rt.block_on(async {
    store.update(|state| state.loading = true);
    
    // 模拟异步操作
    let new_data = fetch_data().await;
    
    store.update(|state| {
        state.data = new_data;
        state.loading = false;
    });
});

组合多个存储

use reactive_stores::{Store, combine_stores};

#[derive(Clone)]
struct UserState {
    name: String,
    age: i32,
}

#[derive(Clone)]
struct SettingsState {
    theme: String,
    language: String,
}

let user_store = Store::new(UserState {
    name: "Alice".to_string(),
    age: 30,
});

let settings_store = Store::new(SettingsState {
    theme: "dark".to_string(),
    language: "en".to_string(),
});

// 组合存储
let combined = combine_stores!(user_store, settings_store);

combined.subscribe(|(user, settings)| {
    println!("User: {}, Theme: {}", user.name, settings.theme);
});

性能优化提示

  1. 使用选择性订阅:只订阅需要的状态部分以减少不必要的更新
  2. 批量更新:使用transaction进行多个相关状态的批量更新
  3. 派生状态缓存:对计算昂贵的派生状态实现适当的缓存策略
  4. 合理使用Arc:对于大型状态对象,考虑使用Arc来避免克隆开销

错误处理

use reactive_stores::StoreError;

fn safe_update(store: &mut Store<AppState>) -> Result<(), StoreError> {
    store.try_update(|state| {
        if state.count < 0 {
            return Err("Count cannot be negative".into());
        }
        state.count += 1;
        Ok(())
    })
}

完整示例demo

use reactive_stores::{Store, combine_stores};
use std::sync::Arc;
use tokio::runtime::Runtime;

// 定义应用状态结构
#[derive(Clone, Debug)]
struct AppState {
    count: i32,
    message: String,
    user: UserData,
    settings: AppSettings,
}

#[derive(Clone, Debug)]
struct UserData {
    name: String,
    age: i32,
    is_authenticated: bool,
}

#[derive(Clone, Debug)]
struct AppSettings {
    theme: String,
    language: String,
    notifications_enabled: bool,
}

// 模拟异步数据获取
async fn fetch_user_data() -> UserData {
    tokio::time::sleep(std::time::Duration::from_millis(100)).await;
    UserData {
        name: "John Doe".to_string(),
        age: 28,
        is_authenticated: true,
    }
}

async fn fetch_app_settings() -> AppSettings {
    tokio::time::sleep(std::time::Duration::from_millis(50)).await;
    AppSettings {
        theme: "dark".to_string(),
        language: "en".to_string(),
        notifications_enabled: true,
    }
}

#[tokio::main]
async fn main() {
    // 创建主状态存储
    let mut app_store = Store::new(AppState {
        count: 0,
        message: "Initializing...".to_string(),
        user: UserData {
            name: "Guest".to_string(),
            age: 0,
            is_authenticated: false,
        },
        settings: AppSettings {
            theme: "light".to_string(),
            language: "en".to_string(),
            notifications_enabled: false,
        },
    });

    // 订阅计数变化
    let count_subscription = app_store.subscribe_to(
        |state: &AppState| state.count,
        |count| {
            println!("[订阅通知] 计数已更新: {}", count);
        },
    );

    // 订阅用户认证状态
    let auth_subscription = app_store.subscribe_to(
        |state: &AppState| state.user.is_authenticated,
        |is_authenticated| {
            println!("[订阅通知] 用户认证状态: {}", is_authenticated);
        },
    );

    // 批量更新示例
    println!("开始批量状态更新...");
    app_store.transaction(|state| {
        state.count = 10;
        state.message = "Transaction in progress".to_string();
        state.settings.theme = "blue".to_string();
    });

    // 异步状态更新
    println!("开始异步数据加载...");
    app_store.update(|state| {
        state.message = "Loading user data...".to_string();
    });

    // 模拟异步操作
    let user_data = fetch_user_data().await;
    let app_settings = fetch_app_settings().await;

    app_store.update(|state| {
        state.user = user_data;
        state.settings = app_settings;
        state.message = "Data loaded successfully".to_string();
    });

    // 读取当前状态
    let current_state = app_store.get_state();
    println!("当前状态: {:?}", current_state);

    // 使用选择器获取派生状态
    let user_info = app_store.select(|state| {
        format!("{} ({}岁) - {}", state.user.name, state.user.age, if state.user.is_authenticated { "已认证" } else { "未认证" })
    });
    println!("用户信息: {}", user_info);

    // 错误处理示例
    match app_store.try_update(|state| {
        if state.count < 0 {
            return Err("计数不能为负数".into());
        }
        state.count += 5;
        Ok(())
    }) {
        Ok(_) => println!("状态更新成功"),
        Err(e) => println!("状态更新失败: {}", e),
    }

    // 组合存储示例
    let user_store = Store::new(UserData {
        name: "Alice".to_string(),
        age: 30,
        is_authenticated: true,
    });

    let settings_store = Store::new(AppSettings {
        theme: "dark".to_string(),
        language: "zh".to_string(),
        notifications_enabled: true,
    });

    let combined_store = combine_stores!(user_store, settings_store);

    combined_store.subscribe(|(user, settings)| {
        println!("组合存储更新 - 用户: {}, 主题: {}", user.name, settings.theme);
    });

    // 保持订阅活跃一段时间
    tokio::time::sleep(std::time::Duration::from_secs(1)).await;

    // 清理订阅
    drop(count_subscription);
    drop(auth_subscription);

    println!("示例执行完成");
}

这个完整的示例演示了reactive_stores库的主要功能,包括状态创建、订阅、更新、异步操作、错误处理和存储组合。示例展示了如何在实际应用中使用这个库来管理复杂的应用状态。

回到顶部