Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions examples/timer_functional/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,11 +162,13 @@ fn App() -> Html {
})
};

let on_cancel = {
Callback::from(move |_: MouseEvent| {
state.dispatch(TimerAction::Cancel);
})
};
let on_cancel = Callback::from({
let (_, dispatcher) = state.into_inner();

move |_: MouseEvent| {
dispatcher.dispatch(TimerAction::Cancel);
}
});

html!(
<>
Expand Down
19 changes: 19 additions & 0 deletions packages/yew/src/functional/hooks/use_reducer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ impl<T> UseReducerHandle<T>
where
T: Reducible,
{
/// Returns the current value of the handle as an `Rc`.
///
/// Unlike [`Deref`], this gives you an owned `Rc<T>` that can be moved
/// into closures or stored without borrowing the handle.
pub fn value_rc(&self) -> Rc<T> {
self.current_state.borrow().clone()
}

/// Dispatch the given action to the reducer.
pub fn dispatch(&self, value: T::Action) {
(self.dispatch)(value)
Expand All @@ -59,6 +67,17 @@ where
dispatch: self.dispatch.clone(),
}
}

/// Destructures the handle into its two parts: the current value as an
/// `Rc<T>`, and the dispatcher for applying actions.
pub fn into_inner(self) -> (Rc<T>, UseReducerDispatcher<T>) {
(
self.current_state.borrow().clone(),
UseReducerDispatcher {
dispatch: self.dispatch,
},
)
}
}

impl<T> Deref for UseReducerHandle<T>
Expand Down
23 changes: 23 additions & 0 deletions packages/yew/src/functional/hooks/use_state.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::fmt;
use std::mem::transmute;
use std::ops::Deref;
use std::rc::Rc;

Expand All @@ -9,6 +10,7 @@ use crate::functional::hook;
use crate::html::IntoPropValue;
use crate::Callback;

#[repr(transparent)]
struct UseStateReducer<T> {
value: T,
}
Expand Down Expand Up @@ -115,6 +117,16 @@ impl<T: fmt::Debug> fmt::Debug for UseStateHandle<T> {
}

impl<T> UseStateHandle<T> {
/// Returns the current value of the handle as an `Rc`.
///
/// Unlike [`Deref`], this gives you an owned `Rc<T>` that can be moved
/// into closures or stored without borrowing the handle.
pub fn value_rc(&self) -> Rc<T> {
// SAFETY: `UseStateReducer<T>` is `repr(transparent)` over `T`, so
// `Rc<UseStateReducer<T>>` and `Rc<T>` have identical layouts.
unsafe { transmute::<Rc<UseStateReducer<T>>, Rc<T>>(self.inner.value_rc()) }
}

/// Replaces the value
pub fn set(&self, value: T) {
self.inner.dispatch(value)
Expand All @@ -126,6 +138,17 @@ impl<T> UseStateHandle<T> {
inner: self.inner.dispatcher(),
}
}

/// Destructures the handle into its two parts: the current value as an
/// `Rc<T>`, and the setter for updating the state.
pub fn into_inner(self) -> (Rc<T>, UseStateSetter<T>) {
let (data, inner) = self.inner.into_inner();
// SAFETY: same repr(transparent) guarantee as `value_rc`.
(
unsafe { transmute::<Rc<UseStateReducer<T>>, Rc<T>>(data) },
UseStateSetter { inner },
)
}
}

impl<T> Deref for UseStateHandle<T> {
Expand Down
3 changes: 3 additions & 0 deletions packages/yew/tests/use_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

mod common;

use std::rc::Rc;

use common::obtain_result;
use wasm_bindgen_test::*;
use yew::prelude::*;
Expand All @@ -14,6 +16,7 @@ async fn use_state_works() {
#[component(UseComponent)]
fn use_state_comp() -> Html {
let counter = use_state(|| 0);
assert_eq!(*counter.value_rc(), *counter);
if *counter < 5 {
counter.set(*counter + 1)
}
Expand Down
59 changes: 59 additions & 0 deletions website/docs/concepts/function-components/state.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,65 @@ This table can be used as a guide when deciding what state-storing type fits bes
| [use_mut_ref] | `T` | - | component instance |
| a static global variable | `T` | - | global, used by all |

## Accessing handle internals

Both `UseStateHandle` and `UseReducerHandle` provide methods to access their internal parts directly.

### `value_rc()`

Returns the current value wrapped in an `Rc<T>`. Unlike dereferencing the handle (which gives a `&T`
tied to the handle's lifetime), `value_rc()` gives you an owned `Rc<T>` that can be moved into
closures or stored independently.

```rust
# use std::rc::Rc;
# use yew::prelude::*;
# #[component]
# fn Comp() -> Html {
let counter = use_state(|| 0);
let rc_value: Rc<i32> = counter.value_rc();
# html! {}
# }
```

### `into_inner()`

Consumes the handle and returns its two parts: the current value as `Rc<T>` and the
setter/dispatcher. This is useful when you want to separate reading from writing without cloning
the full handle.

For `UseReducerHandle`, the return type is `(Rc<T>, UseReducerDispatcher<T>)`:

```rust
# use std::rc::Rc;
# use yew::prelude::*;
# #[derive(Default, PartialEq)]
# struct CounterState { counter: i32 }
# impl Reducible for CounterState {
# type Action = ();
# fn reduce(self: Rc<Self>, _: ()) -> Rc<Self> { self }
# }
# #[component]
# fn Comp() -> Html {
let state = use_reducer(CounterState::default);
let (value, dispatcher) = state.into_inner();
# html! {}
# }
```

For `UseStateHandle`, the return type is `(Rc<T>, UseStateSetter<T>)`:

```rust
# use std::rc::Rc;
# use yew::prelude::*;
# #[component]
# fn Comp() -> Html {
let state = use_state(|| 0);
let (value, setter) = state.into_inner();
# html! {}
# }
```

[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html
[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html
[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,63 @@ title: '状態'
| [use_mut_ref] | `T` | - | コンポーネントインスタンス内 |
| グローバル静的定数 | `T` | - | グローバル、どこでも使用可能 |

## ハンドルの内部へのアクセス

`UseStateHandle` と `UseReducerHandle` の両方に、内部パーツに直接アクセスするためのメソッドが用意されています。

### `value_rc()`

現在の値を `Rc<T>` で返します。ハンドルの参照外し(ハンドルのライフタイムに束縛された `&T` を返す)とは
異なり、`value_rc()` はクロージャに移動させたり、独立して保持できる所有された `Rc<T>` を返します。

```rust
# use std::rc::Rc;
# use yew::prelude::*;
# #[component]
# fn Comp() -> Html {
let counter = use_state(|| 0);
let rc_value: Rc<i32> = counter.value_rc();
# html! {}
# }
```

### `into_inner()`

ハンドルを消費し、現在の値(`Rc<T>`)とセッター/ディスパッチャーの2つの部分を返します。
ハンドル全体をクローンせずに、読み取りと書き込みを分離したい場合に便利です。

`UseReducerHandle` の場合、返り値の型は `(Rc<T>, UseReducerDispatcher<T>)` です:

```rust
# use std::rc::Rc;
# use yew::prelude::*;
# #[derive(Default, PartialEq)]
# struct CounterState { counter: i32 }
# impl Reducible for CounterState {
# type Action = ();
# fn reduce(self: Rc<Self>, _: ()) -> Rc<Self> { self }
# }
# #[component]
# fn Comp() -> Html {
let state = use_reducer(CounterState::default);
let (value, dispatcher) = state.into_inner();
# html! {}
# }
```

`UseStateHandle` の場合、返り値の型は `(Rc<T>, UseStateSetter<T>)` です:

```rust
# use std::rc::Rc;
# use yew::prelude::*;
# #[component]
# fn Comp() -> Html {
let state = use_state(|| 0);
let (value, setter) = state.into_inner();
# html! {}
# }
```

[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html
[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html
[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,63 @@ title: '状态'
| [use_mut_ref] | `T` | - | 组件内部实例 |
| 全局静态常量 | `T` | - | 全局,任何位置都可以使用 |

## 访问句柄内部

`UseStateHandle` 和 `UseReducerHandle` 都提供了直接访问其内部组成部分的方法。

### `value_rc()`

以 `Rc<T>` 的形式返回当前值。与对句柄解引用(返回绑定到句柄生命周期的 `&T`)不同,
`value_rc()` 返回一个拥有所有权的 `Rc<T>`,可以移动到闭包中或独立存储���

```rust
# use std::rc::Rc;
# use yew::prelude::*;
# #[component]
# fn Comp() -> Html {
let counter = use_state(|| 0);
let rc_value: Rc<i32> = counter.value_rc();
# html! {}
# }
```

### `into_inner()`

消耗句柄并返回其两个组成部分:当前值(`Rc<T>`)和 setter/dispatcher。
当你想要在不克隆整个句柄的情况下将读取与写入分离时,这非常有用。

对于 `UseReducerHandle`,返回类型为 `(Rc<T>, UseReducerDispatcher<T>)`:

```rust
# use std::rc::Rc;
# use yew::prelude::*;
# #[derive(Default, PartialEq)]
# struct CounterState { counter: i32 }
# impl Reducible for CounterState {
# type Action = ();
# fn reduce(self: Rc<Self>, _: ()) -> Rc<Self> { self }
# }
# #[component]
# fn Comp() -> Html {
let state = use_reducer(CounterState::default);
let (value, dispatcher) = state.into_inner();
# html! {}
# }
```

对于 `UseStateHandle`,返回类型为 `(Rc<T>, UseStateSetter<T>)`���

```rust
# use std::rc::Rc;
# use yew::prelude::*;
# #[component]
# fn Comp() -> Html {
let state = use_state(|| 0);
let (value, setter) = state.into_inner();
# html! {}
# }
```

[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html
[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html
[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,63 @@ title: '狀態'
| [use_mut_ref] | `T` | - | 組件內部實例 |
| 全域靜態常數 | `T` | - | 全域,任何位置都可以使用 |

## 存取句柄內部

`UseStateHandle` 和 `UseReducerHandle` 都提供了直接存取其內部組成部分的方法。

### `value_rc()`

以 `Rc<T>` 的形式回傳當前值。與對句柄解參考(回傳繫結到句柄生命週期的 `&T`)不同,
`value_rc()` 回傳一個擁有所有權的 `Rc<T>`,可以移動到閉包中或獨立儲存。

```rust
# use std::rc::Rc;
# use yew::prelude::*;
# #[component]
# fn Comp() -> Html {
let counter = use_state(|| 0);
let rc_value: Rc<i32> = counter.value_rc();
# html! {}
# }
```

### `into_inner()`

消耗句柄並回傳其兩個組成部分:當前值(`Rc<T>`)和 setter/dispatcher。
當你想要在不克隆整個句柄的情況下將讀取與寫入分離時,這非常有用。

對於 `UseReducerHandle`,回傳類型為 `(Rc<T>, UseReducerDispatcher<T>)`:

```rust
# use std::rc::Rc;
# use yew::prelude::*;
# #[derive(Default, PartialEq)]
# struct CounterState { counter: i32 }
# impl Reducible for CounterState {
# type Action = ();
# fn reduce(self: Rc<Self>, _: ()) -> Rc<Self> { self }
# }
# #[component]
# fn Comp() -> Html {
let state = use_reducer(CounterState::default);
let (value, dispatcher) = state.into_inner();
# html! {}
# }
```

對於 `UseStateHandle`,回傳類型為 `(Rc<T>, UseStateSetter<T>)`:

```rust
# use std::rc::Rc;
# use yew::prelude::*;
# #[component]
# fn Comp() -> Html {
let state = use_state(|| 0);
let (value, setter) = state.into_inner();
# html! {}
# }
```

[use_state]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state.html
[use_state_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_state_eq.html
[use_reducer]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html
Expand Down
Loading