mirror of https://github.com/yewstack/yew
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:
parent
cd5b8a520c
commit
12c9ebb0ea
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
/// }
|
||||
/// }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>
|
||||
}
|
||||
}
|
||||
```
|
|
@ -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>
|
||||
}
|
||||
}
|
||||
```
|
|
@ -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" }
|
||||
}
|
||||
```
|
|
@ -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.
|
|
@ -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>
|
||||
}
|
||||
}
|
||||
```
|
|
@ -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>
|
||||
}
|
||||
}
|
||||
```
|
|
@ -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.
|
||||
|
||||
:::
|
|
@ -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`.
|
|
@ -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`.
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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',
|
||||
],
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue