Skip to content

Commit 686f08e

Browse files
feat(yew): Add useful methods value_rc and into_inner to UseStateHandle & UseReducerHandle (#3422)
* added (UseReducerHandle/UseStateHandle)::(value_rc/into_inner) * add docs * Updated timer_functional example to showcase into_inner().
1 parent ac73817 commit 686f08e

8 files changed

Lines changed: 282 additions & 5 deletions

File tree

  • examples/timer_functional/src
  • packages/yew
  • website
    • docs/concepts/function-components
    • i18n
      • ja/docusaurus-plugin-content-docs/current/concepts/function-components
      • zh-Hans/docusaurus-plugin-content-docs/current/concepts/function-components
      • zh-Hant/docusaurus-plugin-content-docs/current/concepts/function-components

examples/timer_functional/src/main.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,13 @@ fn App() -> Html {
162162
})
163163
};
164164

165-
let on_cancel = {
166-
Callback::from(move |_: MouseEvent| {
167-
state.dispatch(TimerAction::Cancel);
168-
})
169-
};
165+
let on_cancel = Callback::from({
166+
let (_, dispatcher) = state.into_inner();
167+
168+
move |_: MouseEvent| {
169+
dispatcher.dispatch(TimerAction::Cancel);
170+
}
171+
});
170172

171173
html!(
172174
<>

packages/yew/src/functional/hooks/use_reducer.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,14 @@ impl<T> UseReducerHandle<T>
4848
where
4949
T: Reducible,
5050
{
51+
/// Returns the current value of the handle as an `Rc`.
52+
///
53+
/// Unlike [`Deref`], this gives you an owned `Rc<T>` that can be moved
54+
/// into closures or stored without borrowing the handle.
55+
pub fn value_rc(&self) -> Rc<T> {
56+
self.current_state.borrow().clone()
57+
}
58+
5159
/// Dispatch the given action to the reducer.
5260
pub fn dispatch(&self, value: T::Action) {
5361
(self.dispatch)(value)
@@ -59,6 +67,17 @@ where
5967
dispatch: self.dispatch.clone(),
6068
}
6169
}
70+
71+
/// Destructures the handle into its two parts: the current value as an
72+
/// `Rc<T>`, and the dispatcher for applying actions.
73+
pub fn into_inner(self) -> (Rc<T>, UseReducerDispatcher<T>) {
74+
(
75+
self.current_state.borrow().clone(),
76+
UseReducerDispatcher {
77+
dispatch: self.dispatch,
78+
},
79+
)
80+
}
6281
}
6382

6483
impl<T> Deref for UseReducerHandle<T>

packages/yew/src/functional/hooks/use_state.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::fmt;
2+
use std::mem::transmute;
23
use std::ops::Deref;
34
use std::rc::Rc;
45

@@ -9,6 +10,7 @@ use crate::functional::hook;
910
use crate::html::IntoPropValue;
1011
use crate::Callback;
1112

13+
#[repr(transparent)]
1214
struct UseStateReducer<T> {
1315
value: T,
1416
}
@@ -115,6 +117,16 @@ impl<T: fmt::Debug> fmt::Debug for UseStateHandle<T> {
115117
}
116118

117119
impl<T> UseStateHandle<T> {
120+
/// Returns the current value of the handle as an `Rc`.
121+
///
122+
/// Unlike [`Deref`], this gives you an owned `Rc<T>` that can be moved
123+
/// into closures or stored without borrowing the handle.
124+
pub fn value_rc(&self) -> Rc<T> {
125+
// SAFETY: `UseStateReducer<T>` is `repr(transparent)` over `T`, so
126+
// `Rc<UseStateReducer<T>>` and `Rc<T>` have identical layouts.
127+
unsafe { transmute::<Rc<UseStateReducer<T>>, Rc<T>>(self.inner.value_rc()) }
128+
}
129+
118130
/// Replaces the value
119131
pub fn set(&self, value: T) {
120132
self.inner.dispatch(value)
@@ -126,6 +138,17 @@ impl<T> UseStateHandle<T> {
126138
inner: self.inner.dispatcher(),
127139
}
128140
}
141+
142+
/// Destructures the handle into its two parts: the current value as an
143+
/// `Rc<T>`, and the setter for updating the state.
144+
pub fn into_inner(self) -> (Rc<T>, UseStateSetter<T>) {
145+
let (data, inner) = self.inner.into_inner();
146+
// SAFETY: same repr(transparent) guarantee as `value_rc`.
147+
(
148+
unsafe { transmute::<Rc<UseStateReducer<T>>, Rc<T>>(data) },
149+
UseStateSetter { inner },
150+
)
151+
}
129152
}
130153

131154
impl<T> Deref for UseStateHandle<T> {

packages/yew/tests/use_state.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
mod common;
44

5+
use std::rc::Rc;
6+
57
use common::obtain_result;
68
use wasm_bindgen_test::*;
79
use yew::prelude::*;
@@ -14,6 +16,7 @@ async fn use_state_works() {
1416
#[component(UseComponent)]
1517
fn use_state_comp() -> Html {
1618
let counter = use_state(|| 0);
19+
assert_eq!(*counter.value_rc(), *counter);
1720
if *counter < 5 {
1821
counter.set(*counter + 1)
1922
}

website/docs/concepts/function-components/state.mdx

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,65 @@ This table can be used as a guide when deciding what state-storing type fits bes
1717
| [use_mut_ref] | `T` | - | component instance |
1818
| a static global variable | `T` | - | global, used by all |
1919

20+
## Accessing handle internals
21+
22+
Both `UseStateHandle` and `UseReducerHandle` provide methods to access their internal parts directly.
23+
24+
### `value_rc()`
25+
26+
Returns the current value wrapped in an `Rc<T>`. Unlike dereferencing the handle (which gives a `&T`
27+
tied to the handle's lifetime), `value_rc()` gives you an owned `Rc<T>` that can be moved into
28+
closures or stored independently.
29+
30+
```rust
31+
# use std::rc::Rc;
32+
# use yew::prelude::*;
33+
# #[component]
34+
# fn Comp() -> Html {
35+
let counter = use_state(|| 0);
36+
let rc_value: Rc<i32> = counter.value_rc();
37+
# html! {}
38+
# }
39+
```
40+
41+
### `into_inner()`
42+
43+
Consumes the handle and returns its two parts: the current value as `Rc<T>` and the
44+
setter/dispatcher. This is useful when you want to separate reading from writing without cloning
45+
the full handle.
46+
47+
For `UseReducerHandle`, the return type is `(Rc<T>, UseReducerDispatcher<T>)`:
48+
49+
```rust
50+
# use std::rc::Rc;
51+
# use yew::prelude::*;
52+
# #[derive(Default, PartialEq)]
53+
# struct CounterState { counter: i32 }
54+
# impl Reducible for CounterState {
55+
# type Action = ();
56+
# fn reduce(self: Rc<Self>, _: ()) -> Rc<Self> { self }
57+
# }
58+
# #[component]
59+
# fn Comp() -> Html {
60+
let state = use_reducer(CounterState::default);
61+
let (value, dispatcher) = state.into_inner();
62+
# html! {}
63+
# }
64+
```
65+
66+
For `UseStateHandle`, the return type is `(Rc<T>, UseStateSetter<T>)`:
67+
68+
```rust
69+
# use std::rc::Rc;
70+
# use yew::prelude::*;
71+
# #[component]
72+
# fn Comp() -> Html {
73+
let state = use_state(|| 0);
74+
let (value, setter) = state.into_inner();
75+
# html! {}
76+
# }
77+
```
78+
2079
[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html
2180
[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html
2281
[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html

website/i18n/ja/docusaurus-plugin-content-docs/current/concepts/function-components/state.mdx

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,63 @@ title: '状態'
1717
| [use_mut_ref] | `T` | - | コンポーネントインスタンス内 |
1818
| グローバル静的定数 | `T` | - | グローバル、どこでも使用可能 |
1919

20+
## ハンドルの内部へのアクセス
21+
22+
`UseStateHandle``UseReducerHandle` の両方に、内部パーツに直接アクセスするためのメソッドが用意されています。
23+
24+
### `value_rc()`
25+
26+
現在の値を `Rc<T>` で返します。ハンドルの参照外し(ハンドルのライフタイムに束縛された `&T` を返す)とは
27+
異なり、`value_rc()` はクロージャに移動させたり、独立して保持できる所有された `Rc<T>` を返します。
28+
29+
```rust
30+
# use std::rc::Rc;
31+
# use yew::prelude::*;
32+
# #[component]
33+
# fn Comp() -> Html {
34+
let counter = use_state(|| 0);
35+
let rc_value: Rc<i32> = counter.value_rc();
36+
# html! {}
37+
# }
38+
```
39+
40+
### `into_inner()`
41+
42+
ハンドルを消費し、現在の値(`Rc<T>`)とセッター/ディスパッチャーの2つの部分を返します。
43+
ハンドル全体をクローンせずに、読み取りと書き込みを分離したい場合に便利です。
44+
45+
`UseReducerHandle` の場合、返り値の型は `(Rc<T>, UseReducerDispatcher<T>)` です:
46+
47+
```rust
48+
# use std::rc::Rc;
49+
# use yew::prelude::*;
50+
# #[derive(Default, PartialEq)]
51+
# struct CounterState { counter: i32 }
52+
# impl Reducible for CounterState {
53+
# type Action = ();
54+
# fn reduce(self: Rc<Self>, _: ()) -> Rc<Self> { self }
55+
# }
56+
# #[component]
57+
# fn Comp() -> Html {
58+
let state = use_reducer(CounterState::default);
59+
let (value, dispatcher) = state.into_inner();
60+
# html! {}
61+
# }
62+
```
63+
64+
`UseStateHandle` の場合、返り値の型は `(Rc<T>, UseStateSetter<T>)` です:
65+
66+
```rust
67+
# use std::rc::Rc;
68+
# use yew::prelude::*;
69+
# #[component]
70+
# fn Comp() -> Html {
71+
let state = use_state(|| 0);
72+
let (value, setter) = state.into_inner();
73+
# html! {}
74+
# }
75+
```
76+
2077
[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html
2178
[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html
2279
[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html

website/i18n/zh-Hans/docusaurus-plugin-content-docs/current/concepts/function-components/state.mdx

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,63 @@ title: '状态'
1717
| [use_mut_ref] | `T` | - | 组件内部实例 |
1818
| 全局静态常量 | `T` | - | 全局,任何位置都可以使用 |
1919

20+
## 访问句柄内部
21+
22+
`UseStateHandle``UseReducerHandle` 都提供了直接访问其内部组成部分的方法。
23+
24+
### `value_rc()`
25+
26+
`Rc<T>` 的形式返回当前值。与对句柄解引用(返回绑定到句柄生命周期的 `&T`)不同,
27+
`value_rc()` 返回一个拥有所有权的 `Rc<T>`,可以移动到闭包中或独立存储���
28+
29+
```rust
30+
# use std::rc::Rc;
31+
# use yew::prelude::*;
32+
# #[component]
33+
# fn Comp() -> Html {
34+
let counter = use_state(|| 0);
35+
let rc_value: Rc<i32> = counter.value_rc();
36+
# html! {}
37+
# }
38+
```
39+
40+
### `into_inner()`
41+
42+
消耗句柄并返回其两个组成部分:当前值(`Rc<T>`)和 setter/dispatcher。
43+
当你想要在不克隆整个句柄的情况下将读取与写入分离时,这非常有用。
44+
45+
对于 `UseReducerHandle`,返回类型为 `(Rc<T>, UseReducerDispatcher<T>)`
46+
47+
```rust
48+
# use std::rc::Rc;
49+
# use yew::prelude::*;
50+
# #[derive(Default, PartialEq)]
51+
# struct CounterState { counter: i32 }
52+
# impl Reducible for CounterState {
53+
# type Action = ();
54+
# fn reduce(self: Rc<Self>, _: ()) -> Rc<Self> { self }
55+
# }
56+
# #[component]
57+
# fn Comp() -> Html {
58+
let state = use_reducer(CounterState::default);
59+
let (value, dispatcher) = state.into_inner();
60+
# html! {}
61+
# }
62+
```
63+
64+
对于 `UseStateHandle`,返回类型为 `(Rc<T>, UseStateSetter<T>)`���
65+
66+
```rust
67+
# use std::rc::Rc;
68+
# use yew::prelude::*;
69+
# #[component]
70+
# fn Comp() -> Html {
71+
let state = use_state(|| 0);
72+
let (value, setter) = state.into_inner();
73+
# html! {}
74+
# }
75+
```
76+
2077
[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html
2178
[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html
2279
[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html

website/i18n/zh-Hant/docusaurus-plugin-content-docs/current/concepts/function-components/state.mdx

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,63 @@ title: '狀態'
1717
| [use_mut_ref] | `T` | - | 組件內部實例 |
1818
| 全域靜態常數 | `T` | - | 全域,任何位置都可以使用 |
1919

20+
## 存取句柄內部
21+
22+
`UseStateHandle``UseReducerHandle` 都提供了直接存取其內部組成部分的方法。
23+
24+
### `value_rc()`
25+
26+
`Rc<T>` 的形式回傳當前值。與對句柄解參考(回傳繫結到句柄生命週期的 `&T`)不同,
27+
`value_rc()` 回傳一個擁有所有權的 `Rc<T>`,可以移動到閉包中或獨立儲存。
28+
29+
```rust
30+
# use std::rc::Rc;
31+
# use yew::prelude::*;
32+
# #[component]
33+
# fn Comp() -> Html {
34+
let counter = use_state(|| 0);
35+
let rc_value: Rc<i32> = counter.value_rc();
36+
# html! {}
37+
# }
38+
```
39+
40+
### `into_inner()`
41+
42+
消耗句柄並回傳其兩個組成部分:當前值(`Rc<T>`)和 setter/dispatcher。
43+
當你想要在不克隆整個句柄的情況下將讀取與寫入分離時,這非常有用。
44+
45+
對於 `UseReducerHandle`,回傳類型為 `(Rc<T>, UseReducerDispatcher<T>)`
46+
47+
```rust
48+
# use std::rc::Rc;
49+
# use yew::prelude::*;
50+
# #[derive(Default, PartialEq)]
51+
# struct CounterState { counter: i32 }
52+
# impl Reducible for CounterState {
53+
# type Action = ();
54+
# fn reduce(self: Rc<Self>, _: ()) -> Rc<Self> { self }
55+
# }
56+
# #[component]
57+
# fn Comp() -> Html {
58+
let state = use_reducer(CounterState::default);
59+
let (value, dispatcher) = state.into_inner();
60+
# html! {}
61+
# }
62+
```
63+
64+
對於 `UseStateHandle`,回傳類型為 `(Rc<T>, UseStateSetter<T>)`
65+
66+
```rust
67+
# use std::rc::Rc;
68+
# use yew::prelude::*;
69+
# #[component]
70+
# fn Comp() -> Html {
71+
let state = use_state(|| 0);
72+
let (value, setter) = state.into_inner();
73+
# html! {}
74+
# }
75+
```
76+
2077
[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html
2178
[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html
2279
[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html

0 commit comments

Comments
 (0)