#store #yew #state-management #state

yewv

为Yew提供的一款快速状态管理模块

6个版本

0.2.3 2022年4月14日
0.2.2 2022年4月10日
0.1.1 2022年3月30日

#458 in GUI

MIT 协议

32KB
366

yewv Rust

将性能和简洁性作为首要任务的Yew快速状态管理模块。

这是为谁准备的?

如果您想在Yew函数组件中使用store,这个库就是为您准备的。

安装

将以下依赖项添加到您的 Cargo.toml

[dependencies]
yewv = "0.2"

使用方法

在使用此库时需要遵守以下事项

  1. 仅适用于Yew函数组件。
  2. Store和service上下文必须使用ContextProvider在父组件或根组件中注册。
  3. Store和service需要使用在子组件中,使用use_store/use_service
  4. map_ref & watch_ref不同,map & watch是钩子,因此受到某些规则的约束
    • 应仅在内部调用Yew函数组件。
    • 不应在循环、条件或回调内部调用。

带有store的简单应用

// main.rs
use yew::prelude::*;
use yewv::*;

struct AppState {
    count: i32,
}

#[function_component(App)]
fn app() -> Html {
    let store = StoreContext::new(AppState { count: 0 });
    html! {
        <ContextProvider<StoreContext<AppState>> context={store}>
            <Counter />
            <Counter />
        </ContextProvider<StoreContext<AppState>>>
    }
}

#[function_component(Counter)]
fn counter() -> Html {
    let store = use_store::<AppState>();
    let count = store.map_ref(|state| &state.count);
    let onclick = {
        let store = store.clone();
        move |_| {
            let state = store.state();
            store.set_state(AppState {
                count: state.count + 1,
            });
        }
    };
    html! {
        <button {onclick}>{format!("{} +", count)}</button>
    }
}

fn main() {
    yew::start_app::<App>();
}

带有store和服务的简单应用

// main.rs
use yew::prelude::*;
use yewv::*;

struct AppState {
    count: i32,
}

struct AppService {
    store: StoreContext<AppState>,
}

impl AppService {
    fn increment_count(&self) {
        let state = self.store.state();
        self.store.set_state(AppState {
            count: state.count + 1,
        });
    }
}

#[function_component(App)]
fn app() -> Html {
    let store = StoreContext::new(AppState { count: 0 });
    let service = ServiceContext::new(AppService {
        store: store.clone(),
    });
    html! {
        <ContextProvider<StoreContext<AppState>> context={store}>
        <ContextProvider<ServiceContext<AppService>> context={service}>
            <Counter />
            <Counter />
        </ContextProvider<ServiceContext<AppService>>>
        </ContextProvider<StoreContext<AppState>>>
    }
}

#[function_component(Counter)]
fn counter() -> Html {
    let service = use_service::<AppService>();
    let store = use_store::<AppState>();

    let count = store.map_ref(|state| &state.count);
    let onclick = move |_| service.increment_count();

    html! {
        <button {onclick}>{format!("{} +", count)}</button>
    }
}

fn main() {
    yew::start_app::<App>();
}

map与map_ref

如果您只想引用store拥有的值,应使用map_ref。与map不同,map_ref不获取引用值的所有权。通常在可能的情况下,使用map_ref比使用map更好。然而,并非总是可以使用map_ref。例如,如果您想访问的值不是存储状态拥有的,则需要使用map

let length = store.map(|state| state.some_vector.len());

为什么这么快?

自定义钩子

存储使用高度优化的自定义钩子,以提高性能和内存效率。

仅在需要时渲染

使用mapmap_refwatchwatch_ref对存储进行的订阅,只有在观察到的值已更改时才会触发组件的渲染。

引用 VS 所有权

不是通过组件传播应用程序状态的克隆/复制,而是使用引用。

良好实践

仅引用所需的

在观察存储中的值时,请确保您没有获取超过必要的部分。例如,如果您只对向量中的一个值感兴趣,就没有必要引用整个向量。

let first = store.map_ref(|state| &state.some_vector[0]);
let last = store.map_ref(|state| state.some_vector.iter().last().expect("to have a value"));

大型应用程序中存储的隔离

当且仅当合理时,尝试将您的单体存储拆分为多个。这样做将提高整个应用程序的性能。

版权信息

依赖关系

~12MB
~218K SLoC