|
@@ -2,6 +2,8 @@
|
|
|
|
|
|
Hooks are a great way to encapsulate business logic. If none of the existing hooks work for your problem, you can write your own.
|
|
Hooks are a great way to encapsulate business logic. If none of the existing hooks work for your problem, you can write your own.
|
|
|
|
|
|
|
|
+When writing your hook, you can make a function that accepts `cx: &ScopeState` as a parameter to accept a scope with any Props.
|
|
|
|
+
|
|
## Composing Hooks
|
|
## Composing Hooks
|
|
|
|
|
|
To avoid repetition, you can encapsulate business logic based on existing hooks to create a new hook.
|
|
To avoid repetition, you can encapsulate business logic based on existing hooks to create a new hook.
|
|
@@ -12,6 +14,12 @@ For example, if many components need to access an `AppSettings` struct, you can
|
|
{{#include ../../../examples/hooks_composed.rs:wrap_context}}
|
|
{{#include ../../../examples/hooks_composed.rs:wrap_context}}
|
|
```
|
|
```
|
|
|
|
|
|
|
|
+Or if you want to wrap a hook that persists reloads with the storage API, you can build on top of the use_ref hook to work with mutable state:
|
|
|
|
+
|
|
|
|
+```rust
|
|
|
|
+{{#include ../../../examples/hooks_composed.rs:use_storage}}
|
|
|
|
+```
|
|
|
|
+
|
|
## Custom Hook Logic
|
|
## Custom Hook Logic
|
|
|
|
|
|
You can use [`cx.use_hook`](https://docs.rs/dioxus/latest/dioxus/prelude/struct.ScopeState.html#method.use_hook) to build your own hooks. In fact, this is what all the standard hooks are built on!
|
|
You can use [`cx.use_hook`](https://docs.rs/dioxus/latest/dioxus/prelude/struct.ScopeState.html#method.use_hook) to build your own hooks. In fact, this is what all the standard hooks are built on!
|
|
@@ -23,4 +31,61 @@ You can use [`cx.use_hook`](https://docs.rs/dioxus/latest/dioxus/prelude/struct.
|
|
Inside the initialization closure, you will typically make calls to other `cx` methods. For example:
|
|
Inside the initialization closure, you will typically make calls to other `cx` methods. For example:
|
|
|
|
|
|
- The `use_state` hook tracks state in the hook value, and uses [`cx.schedule_update`](https://docs.rs/dioxus/latest/dioxus/prelude/struct.ScopeState.html#method.schedule_update) to make Dioxus re-render the component whenever it changes.
|
|
- The `use_state` hook tracks state in the hook value, and uses [`cx.schedule_update`](https://docs.rs/dioxus/latest/dioxus/prelude/struct.ScopeState.html#method.schedule_update) to make Dioxus re-render the component whenever it changes.
|
|
|
|
+
|
|
|
|
+Here is a simplified implementation of the `use_state` hook:
|
|
|
|
+
|
|
|
|
+```rust
|
|
|
|
+{{#include ../../../examples/hooks_custom_logic.rs:use_state}}
|
|
|
|
+```
|
|
|
|
+
|
|
- The `use_context` hook calls [`cx.consume_context`](https://docs.rs/dioxus/latest/dioxus/prelude/struct.ScopeState.html#method.consume_context) (which would be expensive to call on every render) to get some context from the scope
|
|
- The `use_context` hook calls [`cx.consume_context`](https://docs.rs/dioxus/latest/dioxus/prelude/struct.ScopeState.html#method.consume_context) (which would be expensive to call on every render) to get some context from the scope
|
|
|
|
+
|
|
|
|
+Here is an implementation of the `use_context` and `use_context_provider` hooks:
|
|
|
|
+
|
|
|
|
+```rust
|
|
|
|
+{{#include ../../../examples/hooks_custom_logic.rs:use_context}}
|
|
|
|
+```
|
|
|
|
+
|
|
|
|
+## Hook Anti-Patterns
|
|
|
|
+
|
|
|
|
+When writing a custom hook, you should avoid the following anti-patterns:
|
|
|
|
+
|
|
|
|
+- !Clone Hooks: To allow hooks to be used within async blocks, the hooks must be Clone. To make a hook clone, you can wrap data in Rc or Arc and avoid lifetimes in hooks.
|
|
|
|
+
|
|
|
|
+This version of use_state may seem more efficient, but it is not cloneable:
|
|
|
|
+
|
|
|
|
+```rust
|
|
|
|
+{{#include ../../../examples/hooks_anti_patterns.rs:non_clone_state}}
|
|
|
|
+```
|
|
|
|
+
|
|
|
|
+If we try to use this hook in an async block, we will get a compile error:
|
|
|
|
+
|
|
|
|
+```rust
|
|
|
|
+fn FutureComponent(cx: &ScopeState) -> Element {
|
|
|
|
+ let my_state = my_use_state(cx, || 0);
|
|
|
|
+ cx.spawn({
|
|
|
|
+ to_owned![my_state];
|
|
|
|
+ async move {
|
|
|
|
+ my_state.set(1);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ todo!()
|
|
|
|
+}
|
|
|
|
+```
|
|
|
|
+
|
|
|
|
+But with the original version, we can use it in an async block:
|
|
|
|
+
|
|
|
|
+```rust
|
|
|
|
+fn FutureComponent(cx: &ScopeState) -> Element {
|
|
|
|
+ let my_state = use_state(cx, || 0);
|
|
|
|
+ cx.spawn({
|
|
|
|
+ to_owned![my_state];
|
|
|
|
+ async move {
|
|
|
|
+ my_state.set(1);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ todo!()
|
|
|
|
+}
|
|
|
|
+```
|