1 个不稳定版本
0.1.0 | 2022 年 1 月 31 日 |
---|
#13 in #Redux
56 每月下载量
66KB
1.5K SLoC
Yewdux
为 Yew 应用程序提供简单的状态管理。
安装
将 Yewdux 添加到项目的 Cargo.toml
[dependencies]
yewdux = "0.7"
用法
Dispatch
是 Yewdux 的主要接口。它允许对全局应用程序状态进行共享可变访问,该状态存储在称为 Store
的专用代理容器中。
写入共享状态
创建一个 dispatch 很简单,只需给它一个存储类型。
use yewdux::prelude::*;
#[derive(Clone, Default)]
struct MyState {
count: usize,
}
let dispatch = Dispatch::<BasicStore<MyState>>::new();
注意我们上面使用的是 BasicStore
,这是 Yewdux 提供的默认存储类型之一。 也可以定义自己的存储类型。
通过 reduce
修改状态。这里我们立即发送一个消息以将计数增加 1。
dispatch.reduce(|state| state.count += 1);
我们还可以创建执行相同操作的回调。此按钮每次点击都会发送消息。
let onclick = dispatch.reduce_callback(|state| state.count += 1);
html! {
<button {onclick}>{"+1"}</button>
}
如果需要回调参数,可以使用 *_with 变体来访问。以下创建了一个新的回调,然后立即调用它,将计数增加 5。
let cb = dispatch.reduce_callback_with(|state, incr: usize| state.count += incr);
cb.emit(5);
读取共享状态
要读取状态,我们需要一个接收它的桥梁。状态在创建桥梁时接收一次,在状态更改后每次都接收。
use std::rc::Rc;
use yew::prelude::*;
use yewdux::prelude::*;
...
struct MyComponent {
dispatch: Dispatch<BasicStore<MyState>>,
state: Option<Rc<MyState>>,
}
enum Msg {
State(Rc<MyState>),
}
impl Component for MyComponent {
type Properties = ();
type Message = Msg;
fn create(ctx: &Context<Self>) -> Self {
// Create a bridge to receive new state. Changes are handled in `update`.
let dispatch = Dispatch::bridge_state(ctx.link().callback(Msg::State));
Self {
dispatch,
state: Default::default()
}
}
fn update(&self, ctx: &Context<Self>, msg: Msg) -> bool {
match msg {
// Receive new state
Msg::State(state) => {
self.state = Some(state);
true
}
}
}
...
}
减少样板代码
为每个组件设置桥梁可能会很繁琐。提供了一种解决方案来自动处理此问题: WithDispatch
和 DispatchProps
。
只需将 DispatchProps
属性提供给您的组件,并用 WithDispatch
组件包装器包装它。
重要:必须同时使用 WithDispatch
和 DispatchProps
,否则您的应用程序将崩溃。
struct MyComponent;
impl Component for MyComponent {
type Properties = DispatchProps<BasicStore<MyState>>;
...
}
html! {
<WithDispatch<MyComponent> />
}
现在,您的组件将自动接收状态更新的更新。它的属性也像常规的 Dispatch
一样表现,唯一的区别是添加了一个获取状态的方法。
fn view(&self, ctx: &Context<Self>) -> Html {
let onclick = ctx.props().reduce_callback(|s| s.count + 1);
let count = ctx.props().state().count;
html! {
<>
<p>{"Count is "}{ count }</p>
<button {onclick}>{"+1"}</button>
</>
}
}
你注意到我们不必以这种方式处理 Option
吗?组件包装器会在首次接收状态时延迟渲染,使其使用起来更加人性化。
提示:为了节省一点输入,可以使用类型别名
type MyComponent = WithDispatch<MyComponentBase>;
struct MyComponentBase;
impl Component for MyComponentBase { .. }
html! {
<MyComponent />
}
需要自定义属性吗?
WithDispatch
包装器可以与任何具有实现 WithDispatchProps
属性的组件一起使用。只需为您自己的属性实现它即可!这将来可能是一个宏。
#[derive(Properties, Clone, PartialEq)]
struct Props {
dispatch: DispatchProps<BasicStore<MyState>>,
...
}
impl WithDispatchProps for Props {
type Store = BasicStore<MyState>;
fn dispatch(&self) -> &DispatchProps<Self::Store> {
&self.dispatch
}
}
持久性
Yewdux 支持状态持久性,因此您的应用重新加载时不会丢失状态。这要求您的状态还必须实现 Serialize
、Deserialize
和 Persistent
。
use serde::{Serialize, Deserialize};
use yewdux::prelude::*;
#[derive(Clone, Default, Serialize, Deserialize)]
struct MyState { ... };
impl Persistent for MyState {
fn area() -> Area {
Area::Session // Default is Area::Local
}
}
struct MyComponent {
dispatch: Dispatch<PersistentStore<State>>,
}
持久存储在启动时检查之前保存的状态,如果没有找到则使用默认值。状态在每次更改时都会保存。
函数式
Yewdux 支持函数式!
将其添加到您的项目中
[dependencies]
yewdux-functional = { git = "https://github.com/intendednull/yewdux.git" }
并享受简洁的好处
use yew::{prelude::*, functional::*};
use yewdux::prelude::*;
use yewdux_functional::*;
#[derive(function_component(MyComponent))]
fn my_component() -> Html {
let store = use_store::<BasicStore<MyState>>();
let onclick = store.dispatch().reduce_callback(|s| s.count += 1);
let count = store.state().map(|s| s.count).unwrap_or_default();
html! {
<>
<p>{"Count is "}{ count }</p>
<button {onclick}>{"+1"}</button>
</>
}
}
示例
完整的示例可以在 这里 找到。
要运行示例,您需要安装 trunk,然后运行(将 [example] 替换为您想要的示例名称)
trunk serve examples/[example]/index.html --open
依赖项
~12MB
~226K SLoC