Move hook API docs to Rustdoc (#2628)

* Move hook API docs to Rustdoc

* npm update, fix links and doc tests and callback docs

* make doc tests pass

* Update packages/yew/src/functional/hooks/use_ref.rs

* Update packages/yew/src/functional/hooks/use_ref.rs

* Update use_ref.rs
This commit is contained in:
Muhammad Hamza 2022-04-21 15:28:09 +05:00 committed by GitHub
parent cd5b8a520c
commit 12c9ebb0ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 765 additions and 1425 deletions

View File

@ -9,11 +9,7 @@ use std::fmt;
use std::rc::Rc;
/// Universal callback wrapper.
/// <aside class="warning">
/// Use callbacks carefully, because if you call one from the `update` loop
/// of a `Component` (even from JS) it will delay a message until next.
/// Callbacks should be used from JS callbacks or `setTimeout` calls.
/// </aside>
///
/// An `Rc` wrapper is used to make it cloneable.
pub struct Callback<IN, OUT = ()> {
/// A callback which can be called multiple times

View File

@ -3,7 +3,8 @@ use std::rc::Rc;
use crate::callback::Callback;
use crate::functional::{hook, use_memo};
/// Get a immutable reference to a memoized `Callback`.
/// Get a immutable reference to a memoized `Callback`. Its state persists across renders.
/// It will be recreated only if any of the dependencies changes value.
///
/// Memoization means it will only get recreated when provided dependencies update/change.
/// This is useful when passing callbacks to optimized child components that rely on

View File

@ -9,22 +9,57 @@ use crate::functional::{hook, use_component_scope, use_memo, use_state};
/// More information about contexts and how to define and consume them can be found on [Yew Docs](https://yew.rs).
///
/// # Example
/// ```rust
/// # use yew::prelude::*;
/// # use std::rc::Rc;
///
/// # #[derive(Clone, Debug, PartialEq)]
/// # struct ThemeContext {
/// # foreground: String,
/// # background: String,
/// # }
/// #[function_component(ThemedButton)]
/// pub fn themed_button() -> Html {
/// let theme = use_context::<Rc<ThemeContext>>().expect("no ctx found");
/// ```rust
/// use yew::{ContextProvider, function_component, html, use_context, use_state, Html};
///
///
/// /// App theme
/// #[derive(Clone, Debug, PartialEq)]
/// struct Theme {
/// foreground: String,
/// background: String,
/// }
///
/// /// Main component
/// #[function_component]
/// pub fn App() -> Html {
/// let ctx = use_state(|| Theme {
/// foreground: "#000000".to_owned(),
/// background: "#eeeeee".to_owned(),
/// });
///
/// html! {
/// <button style={format!("background: {}; color: {}", theme.background, theme.foreground)}>
/// { "Click me" }
/// // `ctx` is type `Rc<UseStateHandle<Theme>>` while we need `Theme`
/// // so we deref it.
/// // It derefs to `&Theme`, hence the clone
/// <ContextProvider<Theme> context={(*ctx).clone()}>
/// // Every child here and their children will have access to this context.
/// <Toolbar />
/// </ContextProvider<Theme>>
/// }
/// }
///
/// /// The toolbar.
/// /// This component has access to the context
/// #[function_component]
/// pub fn Toolbar() -> Html {
/// html! {
/// <div>
/// <ThemedButton />
/// </div>
/// }
/// }
///
/// /// Button placed in `Toolbar`.
/// /// As this component is a child of `ThemeContextProvider` in the component tree, it also has access to the context.
/// #[function_component]
/// pub fn ThemedButton() -> Html {
/// let theme = use_context::<Theme>().expect("no ctx found");
///
/// html! {
/// <button style={format!("background: {}; color: {};", theme.background, theme.foreground)}>
/// { "Click me!" }
/// </button>
/// }
/// }

View File

@ -108,13 +108,16 @@ where
}
}
/// This hook is used for hooking into the component's lifecycle.
/// `use_effect` is used for hooking into the component's lifecycle and creating side effects.
///
/// The callback is called every time after the component's render has finished.
///
/// # Example
///
/// ```rust
/// # use yew::prelude::*;
/// use yew::prelude::*;
/// # use std::rc::Rc;
/// #
///
/// #[function_component(UseEffect)]
/// fn effect() -> Html {
/// let counter = use_state(|| 0);
@ -151,7 +154,85 @@ where
///
/// Whenever the dependencies are changed, the effect callback is called again.
/// To detect changes, dependencies must implement `PartialEq`.
/// Note that the destructor also runs when dependencies change.
///
/// # Note
/// The destructor also runs when dependencies change.
///
/// # Example
///
/// ```rust
/// use yew::{function_component, html, Html, Properties, use_effect_with_deps};
/// # use gloo::console::log;
///
/// #[derive(Properties, PartialEq)]
/// pub struct Props {
/// pub is_loading: bool,
/// }
///
/// #[function_component]
/// fn HelloWorld(props: &Props) -> Html {
/// let is_loading = props.is_loading.clone();
///
/// use_effect_with_deps(
/// move |_| {
/// log!(" Is loading prop changed!");
/// || ()
/// },
/// is_loading,
/// );
///
/// html! { <>{"Am I loading? - "}{is_loading}</> }
/// }
/// ```
///
/// # Tips
///
/// ## Only on first render
///
/// Provide a empty tuple `()` as dependencies when you need to do something only on the first render
/// of a component.
///
/// ```rust
/// use yew::{function_component, html, Html, use_effect_with_deps};
/// # use gloo::console::log;
///
/// #[function_component]
/// fn HelloWorld() -> Html {
///
/// use_effect_with_deps(
/// move |_| {
/// log!("I got rendered, yay!");
/// || ()
/// },
/// (),
/// );
///
/// html! { "Hello" }
/// }
/// ```
///
/// ## On destructing or last render
///
/// Use [Only on first render](#only-on-first-render) but put the code in the cleanup function.
/// It will only get called when the component is removed from view / gets destroyed.
///
/// ```rust
/// use yew::{function_component, html, Html, use_effect_with_deps};
/// # use gloo::console::log;
///
/// #[function_component]
/// fn HelloWorld() -> Html {
/// use_effect_with_deps(
/// move |_| {
/// || {
/// log!("Noo dont kill me, ahhh!");
/// }
/// },
/// (),
/// );
/// html! { "Hello" }
/// }
/// ```
#[hook]
pub fn use_effect_with_deps<T, F, D>(f: F, deps: T)
where

View File

@ -31,12 +31,22 @@ impl UseForceUpdate {
/// This hook is used to manually force a function component to re-render.
///
/// # Note
///
/// Often, using this hook means that you're doing something wrong.
/// Try to use more specialized hooks, such as [`use_state`] and [`use_reducer`].
/// This hook should only be used when your component depends on external state where you
/// can't subscribe to changes, or as a low-level primitive to enable such a subscription-based
/// approach.
///
/// For example, a large externally managed cache, such as a app-wide cache for GraphQL data
/// # Use-case
///
/// Use this hook when wrapping an API that doesn't expose precise subscription events for fetched data.
/// You could then, at some point, invalidate your local cache of the fetched data and trigger a re-render
/// to let the normal render flow of components tell you again which data to fetch, and repopulate the
/// cache accordingly.
///
/// A large externally managed cache, such as a app-wide cache for GraphQL data
/// should not rerender every component whenever new data arrives, but only those where a query
/// changed.
///
@ -45,11 +55,11 @@ impl UseForceUpdate {
/// # Example
///
/// This example implements a silly, manually updated display of the current time. The component
/// is rerendered every time the button is clicked. You should usually use a timeout and `use_state`
/// is re-rendered every time the button is clicked. You should usually use a timeout and `use_state`
/// to automatically trigger a re-render every second without having to use this hook.
///
/// ```rust
/// # use yew::prelude::*;
/// use yew::prelude::*;
///
/// #[function_component]
/// fn ManuallyUpdatedDate() -> Html {

View File

@ -42,11 +42,14 @@ where
///
/// Memoization means it will only get recalculated when provided dependencies update/change.
///
/// It can be useful for keeping things in scope for the lifetime of the component,
/// so long as you don't store a clone of the resulting `Rc` anywhere that outlives the component.
///
/// # Example
///
/// ```rust
/// # use yew::prelude::*;
/// #
/// use yew::prelude::*;
///
/// #[derive(PartialEq, Properties)]
/// pub struct Props {
/// pub step: usize,

View File

@ -222,6 +222,13 @@ where
/// The state is expected to implement the [`Reducible`] trait which provides an `Action` type and a reducer
/// function.
///
/// The state object returned by the initial state function is required to
/// implement a `Reducible` trait which defines the associated `Action` type and a
/// reducer function.
///
/// This hook will always trigger a re-render upon receiving an action. See
/// [`use_reducer_eq`] if you want the component to only re-render when the state changes.
///
/// # Example
/// ```rust
/// # use yew::prelude::*;
@ -284,6 +291,21 @@ where
/// }
/// }
/// ```
///
/// # Tip
///
/// The dispatch function is guaranteed to be the same across the entire
/// component lifecycle. You can safely omit the `UseReducerHandle` from the
/// dependents of `use_effect_with_deps` if you only intend to dispatch
/// values from within the hooks.
///
/// # Caution
///
/// The value held in the handle will reflect the value of at the time the
/// handle is returned by the `use_reducer`. It is possible that the handle does
/// not dereference to an up to date value if you are moving it into a
/// `use_effect_with_deps` hook. You can register the
/// state to the dependents so the hook can be updated when the value changes.
#[hook]
pub fn use_reducer<T, F>(init_fn: F) -> UseReducerHandle<T>
where

View File

@ -24,12 +24,12 @@ impl<T: 'static, F: FnOnce() -> T> Hook for UseMutRef<F> {
///
/// # Example
/// ```rust
/// # use yew::prelude::*;
/// # use web_sys::HtmlInputElement;
/// # use std::rc::Rc;
/// # use std::cell::RefCell;
/// # use std::ops::{Deref, DerefMut};
/// #
/// use yew::prelude::*;
/// use web_sys::HtmlInputElement;
/// use std::rc::Rc;
/// use std::cell::RefCell;
/// use std::ops::{Deref, DerefMut};
///
/// #[function_component(UseRef)]
/// fn ref_hook() -> Html {
/// let message = use_state(|| "".to_string());
@ -72,16 +72,15 @@ where
/// This hook is used for obtaining a [`NodeRef`].
/// It persists across renders.
///
/// It is important to note that you do not get notified of state changes.
/// The `ref` attribute can be used to attach the [`NodeRef`] to an HTML element. In callbacks,
/// you can then get the DOM `Element` that the `ref` is attached to.
///
/// # Example
///
/// ```rust
/// # use wasm_bindgen::{prelude::Closure, JsCast};
/// # use yew::{
/// # function_component, html, use_effect_with_deps, use_node_ref,
/// # Html,
/// # };
/// # use web_sys::{Event, HtmlElement};
/// use wasm_bindgen::{prelude::Closure, JsCast};
/// use yew::{function_component, html, use_effect_with_deps, use_node_ref, Html};
/// use web_sys::{Event, HtmlElement};
///
/// #[function_component(UseNodeRef)]
/// pub fn node_ref_hook() -> Html {
@ -124,8 +123,13 @@ where
/// </div>
/// }
/// }
///
/// ```
///
/// # Tip
///
/// When conditionally rendering elements you can use `NodeRef` in conjunction with `use_effect_with_deps`
/// to perform actions each time an element is rendered and just before the component where the hook is used in is going to be removed from the
/// DOM.
#[hook]
pub fn use_node_ref() -> NodeRef {
(*use_state(NodeRef::default)).clone()

View File

@ -27,11 +27,16 @@ where
/// This hook is used to manage state in a function component.
///
/// This hook will always trigger a re-render upon receiving a new state. See [`use_state_eq`]
/// if you want the component to only re-render when the new state compares unequal
/// to the existing one.
///
/// # Example
///
/// ```rust
/// # use yew::prelude::*;
/// use yew::prelude::*;
/// # use std::rc::Rc;
/// #
///
/// #[function_component(UseState)]
/// fn state() -> Html {
/// let counter = use_state(|| 0);
@ -52,6 +57,21 @@ where
/// }
/// }
/// ```
///
/// # Caution
///
/// The value held in the handle will reflect the value of at the time the
/// handle is returned by the `use_reducer`. It is possible that the handle does
/// not dereference to an up to date value if you are moving it into a
/// `use_effect_with_deps` hook. You can register the
/// state to the dependents so the hook can be updated when the value changes.
///
/// # Tip
///
/// The setter function is guaranteed to be the same across the entire
/// component lifecycle. You can safely omit the `UseStateHandle` from the
/// dependents of `use_effect_with_deps` if you only intend to set
/// values from within the hook.
#[hook]
pub fn use_state<T, F>(init_fn: F) -> UseStateHandle<T>
where

View File

@ -134,7 +134,7 @@ fn App() -> Html {
#### Function components
`use_context` hook is used to consume contexts in function components.
See [docs for use_context](function-components/hooks/use-context.mdx) to learn more.
See [docs for use_context](https://yew-rs-api.web.app/next/yew/functional/fn.use_context.html) to learn more.
#### Struct components
@ -164,7 +164,7 @@ You should refactor the `Layout` component to take children as props and display
Because of Rust's ownership rules, a context cannot have a method that takes `&mut self` that can be called by children.
In order to mutate a context's value, we must combine it with a reducer. This is done by using the
[`use_reducer`](./function-components/hooks/use-reducer.mdx) hook.
[`use_reducer`](https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer.html) hook.
The [contexts example](https://github.com/yewstack/yew/tree/master/examples/contexts) demonstrates mutable contexts
with the help of contexts

View File

@ -25,18 +25,20 @@ These rules are enforced by either compile time or run-time errors.
Yew comes with the following predefined Hooks:
- [`use_state`](./use-state.mdx)
- [`use_state_eq`](./use-state.mdx#use_state_eq)
- [`use_memo`](./use-memo.mdx)
- [`use_callback`](./use-callback.mdx)
- [`use_mut_ref`](./use-mut-ref.mdx)
- [`use_node_ref`](./use-node-ref.mdx)
- [`use_reducer`](./use-reducer.mdx)
- [`use_reducer_eq`](./use-reducer.mdx#use_reducer_eq)
- [`use_effect`](./use-effect.mdx)
- [`use_effect_with_deps`](./use-effect.mdx#use_effect_with_deps)
- [`use_context`](./use-context.mdx)
- [`use_force_update`](./use-force-update.mdx)
- `use_state`
- `use_state_eq`
- `use_memo`
- `use_callback`
- `use_mut_ref`
- `use_node_ref`
- `use_reducer`
- `use_reducer_eq`
- `use_effect`
- `use_effect_with_deps`
- `use_context`
- `use_force_update`
The documentation for these hooks can be found in the [Yew API docs](https://yew-rs-api.web.app/next/yew/functional/)
### Custom Hooks

View File

@ -1,67 +0,0 @@
---
title: 'use_callback'
---
`use_callback` is used for obtaining an immutable reference to a memoized `Callback`.
Its state persists across renders.
It will be recreated only if any of the dependencies changes value.
`use_callback` can be useful when passing callbacks to optimized child components that rely on
PartialEq to prevent unnecessary renders.
```rust
use yew::prelude::*;
#[derive(Properties, PartialEq)]
pub struct Props {
pub callback: Callback<String, String>,
}
#[function_component(MyComponent)]
fn my_component(props: &Props) -> Html {
let greeting = props.callback.emit("Yew".to_string());
html! {
<>{ &greeting }</>
}
}
#[function_component(UseCallback)]
fn callback() -> Html {
let counter = use_state(|| 0);
let onclick = {
let counter = counter.clone();
Callback::from(move |_| counter.set(*counter + 1))
};
// This callback depends on (), so it's created only once, then MyComponent
// will be rendered only once even when you click the button mutiple times.
let callback = use_callback(
move |name, _| format!("Hello, {}!", name),
()
);
// It can also be used for events, this callback depends on `counter`.
let oncallback = {
let counter = counter.clone();
use_callback(
move |_e, counter| {
let _ = **counter;
},
counter
)
};
html! {
<div>
<button {onclick}>{ "Increment value" }</button>
<button onclick={oncallback}>{ "Callback" }</button>
<p>
<b>{ "Current value: " }</b>
{ *counter }
</p>
<MyComponent {callback} />
</div>
}
}
```

View File

@ -1,63 +0,0 @@
---
title: 'use_context'
---
`use_context` is used for consuming [contexts](../../contexts.mdx) in function components.
## Example
```rust
use yew::{ContextProvider, function_component, html, use_context, use_state, Html};
/// App theme
#[derive(Clone, Debug, PartialEq)]
struct Theme {
foreground: String,
background: String,
}
/// Main component
#[function_component]
pub fn App() -> Html {
let ctx = use_state(|| Theme {
foreground: "#000000".to_owned(),
background: "#eeeeee".to_owned(),
});
html! {
// `ctx` is type `Rc<UseStateHandle<Theme>>` while we need `Theme`
// so we deref it.
// It derefs to `&Theme`, hence the clone
<ContextProvider<Theme> context={(*ctx).clone()}>
// Every child here and their children will have access to this context.
<Toolbar />
</ContextProvider<Theme>>
}
}
/// The toolbar.
/// This component has access to the context
#[function_component]
pub fn Toolbar() -> Html {
html! {
<div>
<ThemedButton />
</div>
}
}
/// Button placed in `Toolbar`.
/// As this component is a child of `ThemeContextProvider` in the component tree, it also has access to the context.
#[function_component]
pub fn ThemedButton() -> Html {
//highlight-next-line
let theme = use_context::<Theme>().expect("no ctx found");
html! {
<button style={format!("background: {}; color: {};", theme.background, theme.foreground)}>
{ "Click me!" }
</button>
}
}
```

View File

@ -1,126 +0,0 @@
---
title: 'use_effect'
---
`use_effect` is used for hooking into the component's lifecycle and creating side-effects.
It takes a function which is called every time after the component's render has finished.
The input function has to return a closure - a cleanup function, which is called right
before starting a new render or when the component unmounts.
## Example
```rust
use yew::{Callback, function_component, html, use_effect, use_state, Html};
#[function_component]
fn EffectExample() -> Html {
let counter = use_state(|| 0);
{
let counter = counter.clone();
use_effect(move || {
// Make a call to DOM API after component is rendered
gloo::utils::document().set_title(&format!("You clicked {} times", *counter));
// Perform the cleanup
|| gloo::utils::document().set_title("You clicked 0 times")
});
}
let onclick = {
let counter = counter.clone();
Callback::from(move |_| counter.set(*counter + 1))
};
html! {
<button {onclick}>{ format!("Increment to {}", *counter) }</button>
}
}
```
## `use_effect_with_deps`
`use_effect_with_deps` is a more enhanced version of [`use_effect`](#use_effect).
It takes a second argument - dependencies. The effect is only executed - and the
old effect cleaned up - when the dependencies change compared to the previous call.
:::note
`dependencies` must implement `PartialEq`.
:::
```rust
use yew::{function_component, html, Html, Properties, use_effect_with_deps};
#[derive(Properties, PartialEq)]
pub struct Props {
pub is_loading: bool,
}
#[function_component]
fn HelloWorld(props: &Props) -> Html {
let is_loading = props.is_loading.clone();
use_effect_with_deps(
move |_| {
web_sys::console::log_1(&" Is loading prop changed!".into());
|| ()
},
// highlight-next-line
is_loading,
);
html! { <>{"Am I loading? - "}{is_loading}</> }
}
```
## Tips
### Only on first render {#only-on-first-render}
Provide a empty tuple `()` as dependencies when you need to do something only on the first render
of a component.
```rust
use yew::{function_component, html, Html, use_effect_with_deps};
#[function_component]
fn HelloWorld() -> Html {
use_effect_with_deps(
move |_| {
web_sys::console::log_1(&"I got rendered, yay!".into());
|| ()
},
// highlight-next-line
(),
);
html! { "Hello" }
}
```
### On destructing or last render
Use [Only on first render](#only-on-first-render) but put the code in the cleanup function.
It will only get called when the component is removed from view / gets destroyed.
```rust
use yew::{function_component, html, Html, use_effect_with_deps};
#[function_component]
fn HelloWorld() -> Html {
use_effect_with_deps(
move |_| {
|| {
web_sys::console::log_1(&"Noo dont kill me, ahhh!".into());
}
},
(),
);
html! { "Hello" }
}
```

View File

@ -1,17 +0,0 @@
---
title: 'use_force_update'
---
`use_force_update` is a low-level hook specialized to triggering a re-render of a function component.
Usually, this re-render is triggered automatically by the hook holding your data, for example when
changing the data in a handle returned from [`use_state`](./use-state).
:::caution
Often, using this hook means you are doing something wrong and should use one of the other hooks,
for example [`use_reducer`](./use-reducer) is another great way to track changing data.
:::
Use this hook when wrapping an API that doesn't expose precise subscription events for fetched data.
You could then, at some point, invalidate your local cache of the fetched data and trigger a re-render
to let the normal render flow of components tell you again which data to fetch, and repopulate the
cache accordingly.

View File

@ -1,34 +0,0 @@
---
title: 'use_memo'
---
`use_memo` is used for obtaining an immutable reference to a memoized value.
Its state persists across renders.
Its value will be recalculated only if any of the dependencies changes value.
`use_memo` can be useful for keeping things in scope for the lifetime of the component, so long as
you don't store a clone of the resulting `Rc` anywhere that outlives the component.
```rust
use yew::{function_component, html, use_memo, use_state, Callback, Html, Properties};
#[derive(PartialEq, Properties)]
pub struct Props {
pub step: usize,
}
#[function_component(UseMemo)]
fn ref_hook(props: &Props) -> Html {
// Will only get recalculated if `props.step` value changes
let message = use_memo(
|step| format!("{}. Do Some Expensive Calculation", step),
props.step
);
html! {
<div>
<span>{ (*message).clone() }</span>
</div>
}
}
```

View File

@ -1,55 +0,0 @@
---
title: 'use_mut_ref'
---
`use_mut_ref` is used for obtaining a mutable reference to a value.
Its state persists across renders.
It is important to note that you do not get notified of state changes.
If you need the component to be re-rendered on state change, consider using [`use_state`](./use-state).
## Example
Here you can see we count `message_count` as that number is not used in `Html` and thus does not need to cause a rerender.
```rust
use web_sys::HtmlInputElement;
use yew::{
events::Event,
function_component, html, use_mut_ref, use_state,
Callback, TargetCast,
Html,
};
#[function_component]
fn MutRefExample() -> Html {
let message = use_state(|| "".to_string());
let message_count = use_mut_ref(|| 0);
let onclick = Callback::from(move |_| {
let window = gloo::utils::window();
if *message_count.borrow_mut() > 3 {
window.alert_with_message("Message limit reached").unwrap();
} else {
*message_count.borrow_mut() += 1;
window.alert_with_message("Message sent").unwrap();
}
});
let onchange = {
let message = message.clone();
Callback::from(move |e: Event| {
let input: HtmlInputElement = e.target_unchecked_into();
message.set(input.value());
})
};
html! {
<div>
<input {onchange} value={(*message).clone()} />
<button {onclick}>{ "Send" }</button>
</div>
}
}
```

View File

@ -1,54 +0,0 @@
---
title: 'use_node_ref'
---
`use_node_ref` is used for maintaining a reference to a DOM element represented as a
[`NodeRef`](../node-refs.mdx). It also persists across renders.
The `ref` attribute can be used to attach the `NodeRef` to an HTML element. In callbacks,
you can then get the DOM `Element` that the ref is attached to.
## Example
```rust
use web_sys::HtmlInputElement;
use yew::{
function_component, functional::*, html,
NodeRef, Html
};
#[function_component(UseRef)]
pub fn ref_hook() -> Html {
// highlight-next-line
let input_ref = use_node_ref();
let value = use_state(|| 25_f64);
let onclick = {
let input_ref = input_ref.clone();
let value = value.clone();
move |_| {
// highlight-start
if let Some(input) = input_ref.cast::<HtmlInputElement>() {
value.set(*value + input.value_as_number());
}
// highlight-end
}
};
html! {
<div>
// highlight-next-line
<input ref={input_ref} type="number" />
<button {onclick}>{ format!("Add input to {}", *value) }</button>
</div>
}
}
```
:::tip Advanced tip
When conditionally rendering elements you can use `NodeRef` in conjunction with `use_effect_with_deps`
to perform actions each time an element is rendered and just before its going to be removed from the
DOM.
:::

View File

@ -1,109 +0,0 @@
---
title: 'use_reducer'
---
`use_reducer` is an alternative to [`use_state`](./use-state). It is used to handle more complex component's state.
It accepts an initializer function and returns a `UseReducerHandle` that dereferences to the state,
and a dispatch function.
The dispatch function takes one argument of type `Action`. When called, the action and current value
are passed to the reducer function which computes a new state that is returned,
and the component is re-rendered.
:::tip Advanced tip
The dispatch function is guaranteed to be the same across the entire
component lifecycle. You can safely omit the `UseReducerHandle` from the
dependents of `use_effect_with_deps` if you only intend to dispatch
values from within the hooks.
:::
The state object returned by the initial state function is required to
implement a `Reducible` trait which defines the associated `Action` type and a
reducer function.
This hook will always trigger a re-render upon receiving an action. See
[`use_reducer_eq`](#use_reducer_eq) if you want the component to only
re-render when the state changes.
## Example
```rust
use yew::prelude::*;
use std::rc::Rc;
/// reducer's Action
enum CounterAction {
Double,
Square,
}
/// reducer's State
struct CounterState {
counter: i32,
}
impl Default for CounterState {
fn default() -> Self {
Self { counter: 1 }
}
}
impl Reducible for CounterState {
/// Reducer Action Type
type Action = CounterAction;
/// Reducer Function
fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {
let next_ctr = match action {
CounterAction::Double => self.counter * 2,
CounterAction::Square => self.counter.pow(2)
};
Self { counter: next_ctr }.into()
}
}
#[function_component]
fn ReducerExample() -> Html {
// The use_reducer hook takes an initialization function which will be called only once.
let counter = use_reducer(CounterState::default);
let double_onclick = {
let counter = counter.clone();
Callback::from(move |_| counter.dispatch(CounterAction::Double))
};
let square_onclick = {
let counter = counter.clone();
Callback::from(move |_| counter.dispatch(CounterAction::Square))
};
html! {
<>
<div id="result">{ counter.counter }</div>
<button onclick={double_onclick}>{ "Double" }</button>
<button onclick={square_onclick}>{ "Square" }</button>
</>
}
}
```
:::caution
The value held in the handle will reflect the value of at the time the
handle is returned by the `use_reducer`. It is possible that the handle does
not dereference to an up to date value if you are moving it into a
`use_effect_with_deps` hook. You can register the
state to the dependents so the hook can be updated when the value changes.
:::
## `use_reducer_eq`
This hook has the same effect as `use_reducer` but will only trigger a
re-render when the reducer function produces a value that `prev_state != next_state`.
This hook requires the state object to implement `PartialEq` in addition
to the `Reducible` trait required by `use_reducer`.

View File

@ -1,67 +0,0 @@
---
title: 'use_state'
---
`use_state` is used to manage state in a function component.
It returns a `UseStateHandle` object which `Deref`s to the currently stored value
and provides a `set` method to update the value.
The hook takes a function as input which determines the initial value.
:::tip Advanced tip
The setter function is guaranteed to be the same across the entire
component lifecycle. You can safely omit the `UseStateHandle` from the
dependents of `use_effect_with_deps` if you only intend to set
values from within the hook.
:::
This hook will always trigger a re-render upon receiving a new state. See
[`use_state_eq`](#use_state_eq) if you want the component to only
re-render when the new state compares unequal to the existing one.
## Example
```rust
use std::ops::Deref;
use yew::{Callback, function_component, html, use_state, Html};
#[function_component]
fn StateExample() -> Html {
let name_handle = use_state(|| String::from("Bob"));
let name = name_handle.deref().clone();
let onclick = {
let name = name.clone();
Callback::from(move |_| name_handle.set(format!("{}y Jr.", name)))
};
html! {
<div>
<button {onclick}>{ "Update name" }</button>
<p>
<b>{ "My name is: " }</b>
{ name }
</p>
</div>
}
}
```
:::caution
The value held in the handle will reflect the value at the time the
handle is returned by the `use_state`. It is possible that the handle
does not dereference to an up to date value if you are moving it into a
`use_effect_with_deps` hook. You can register the
state to the dependents so the hook can be updated when the value changes.
:::
## `use_state_eq`
This hook has the same effect as `use_state` but will only trigger a
re-render when the setter receives a value that `prev_state != next_state`.
This hook requires the state object to implement `PartialEq`.

View File

@ -15,6 +15,7 @@ Do not manually modify the DOM tree that is rendered by Yew. Treat the `NodeRef`
access, if you are unsure.
:::
## Example
## Further Reading
See [use_node_ref hook](./hooks/use-node-ref)
- [use_node_ref hook](https://yew-rs-api.web.app/next/yew/functional/fn.use_node_ref.html)
- [`node_refs` example](https://github.com/yewstack/yew/tree/master/examples/node_refs)

View File

@ -6,13 +6,21 @@ title: 'State'
This table can be used as a guide when deciding what state storing type fits best for your use case:
| Hook | Type | Rerender when? | Scope |
| ---------------------------------------------------- | -------------------------- | ---------------------------- | ------------------- |
| [use_state](./hooks/use-state) | `T` | got set | component instance |
| [use_state_eq](./hooks/use-state#use_state_eq) | `T: PartialEq` | got set with diff. value | component instance |
| [use_reducer](./hooks/use-reducer) | `T: Reducible` | got reduced | component instance |
| [use_reducer_eq](./hooks/use-reducer#use_reducer_eq) | `T: Reducible + PartialEq` | got reduced with diff. value | component instance |
| [use_memo](./hooks/use-memo) | `Deps -> T` | dependencies changed | component instance |
| [use_callback](./hooks/use-callback) | `Deps -> Callback<E>` | dependencies changed | component instance |
| [use_mut_ref](./hooks/use-mut-ref) | `T` | - | component instance |
| a static global variable | `T` | - | global, used by all |
| Hook | Type | Rerender when? | Scope |
| ------------------------ | -------------------------- | ---------------------------- | ------------------- |
| [use_state] | `T` | got set | component instance |
| [use_state_eq] | `T: PartialEq` | got set with diff. value | component instance |
| [use_reducer] | `T: Reducible` | got reduced | component instance |
| [use_reducer_eq] | `T: Reducible + PartialEq` | got reduced with diff. value | component instance |
| [use_memo] | `Deps -> T` | dependencies changed | component instance |
| [use_callback] | `Deps -> Callback<E>` | dependencies changed | component instance |
| [use_mut_ref] | `T` | - | component instance |
| a static global variable | `T` | - | global, used by all |
[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
[use_reducer_eq]: https://yew-rs-api.web.app/next/yew/functional/fn.use_reducer_eq.html
[use_memo]: https://yew-rs-api.web.app/next/yew/functional/fn.use_memo.html
[use_callback]: https://yew-rs-api.web.app/next/yew/functional/fn.use_callback.html
[use_mut_ref]: https://yew-rs-api.web.app/next/yew/functional/fn.use_mut_ref.html

1266
website/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -67,15 +67,6 @@ module.exports = {
id: 'concepts/function-components/hooks/introduction',
},
items: [
'concepts/function-components/hooks/use-state',
'concepts/function-components/hooks/use-reducer',
'concepts/function-components/hooks/use-mut-ref',
'concepts/function-components/hooks/use-node-ref',
'concepts/function-components/hooks/use-effect',
'concepts/function-components/hooks/use-memo',
'concepts/function-components/hooks/use-callback',
'concepts/function-components/hooks/use-context',
'concepts/function-components/hooks/use-force-update',
'concepts/function-components/hooks/custom-hooks',
],
},