Documentation Index Fetch the complete documentation index at: https://mintlify.com/DioxusLabs/dioxus/llms.txt
Use this file to discover all available pages before exploring further.
Hooks are special functions that let you use state and other Dioxus features in components. They follow specific rules to ensure consistent behavior.
What Are Hooks?
Hooks are functions that:
Start with use_ prefix
Must be called in the same order every render
Can only be called from component functions or other hooks
Manage component lifecycle, state, and side effects
use dioxus :: prelude ::* ;
#[component]
fn MyComponent () -> Element {
// Hooks are called at the top of the component
let mut count = use_signal ( || 0 );
let doubled = use_memo ( move || count () * 2 );
rsx! {
p { "Count: {count}, Doubled: {doubled}" }
}
}
Rules of Hooks
Hooks must be called in the same order on every render. Breaking this rule will cause panics.
Rule 1: Call Hooks at the Top Level
Don’t call hooks inside loops, conditions, or nested functions:
// ❌ Don't do this
fn BadComponent () -> Element {
let condition = true ;
if condition {
let state = use_signal ( || 0 ); // Wrong! Conditional hook
}
rsx! { div {} }
}
// ✅ Do this instead
fn GoodComponent () -> Element {
let mut state = use_signal ( || 0 );
if state () > 0 {
// Use the state value, not create hooks
}
rsx! { div {} }
}
Rule 2: Only Call Hooks from Components or Hooks
// ❌ Don't call hooks from regular functions
fn regular_function () {
let state = use_signal ( || 0 ); // Wrong!
}
// ✅ Call hooks from components
#[component]
fn MyComponent () -> Element {
let state = use_signal ( || 0 );
rsx! { div {} }
}
// ✅ Or from custom hooks
fn use_counter ( initial : i32 ) -> Signal < i32 > {
use_signal ( move || initial )
}
Why These Rules?
Dioxus stores hook state in a list by order of calls. If the order changes, state gets mismatched:
fn Component () -> Element {
let number = use_signal ( || 1 ); // Hook 1
let string = use_signal ( || "a" ); // Hook 2
let bool = use_signal ( || true ); // Hook 3
// Internally stored as: [1, "a", true]
// Next render expects the same order!
rsx! { div {} }
}
Built-in Hooks
State Hooks
use_signal
Create reactive state:
let mut count = use_signal ( || 0 );
// Read
let value = count ();
// Write
count += 1 ;
count . set ( 42 );
count . with_mut ( | c | * c = 100 );
See use_signal source
use_signal_sync
Create thread-safe state:
let mut count = use_signal_sync ( || 0 );
// Can be used across threads
use_future ( move || async move {
tokio :: spawn ( async move {
* count . write () += 1 ;
}) . await ;
});
Computed State Hooks
use_memo
Compute derived values:
let mut count = use_signal ( || 0 );
let doubled = use_memo ( move || count () * 2 );
// doubled updates automatically when count changes
rsx! {
"Count: {count}, Doubled: {doubled}"
}
use_resource
Fetch async data:
let mut user_id = use_signal ( || 1 );
let user = use_resource ( move || async move {
fetch_user ( user_id ()) . await
});
rsx! {
match user () {
Some ( Ok ( user )) => rsx! { p { "User: {user.name}" } },
Some ( Err ( e )) => rsx! { p { "Error: {e}" } },
None => rsx! { p { "Loading..." } },
}
}
Effect Hooks
use_effect
Run side effects:
let mut count = use_signal ( || 0 );
// Runs on mount and when count changes
use_effect ( move || {
println! ( "Count is now: {}" , count ());
});
See use_effect source
use_future
Run async tasks:
let mut data = use_signal ( || None );
use_future ( move || async move {
let result = fetch_data () . await ;
data . set ( Some ( result ));
});
Context Hooks
use_context
Access shared state:
// Provider
fn App () -> Element {
use_context_provider ( || Signal :: new ( 0 ));
rsx! { Child {} }
}
// Consumer
fn Child () -> Element {
let count : Signal < i32 > = use_context ();
rsx! { "Count: {count}" }
}
use_context_provider
Provide context to descendants:
fn App () -> Element {
use_context_provider ( || AppState {
user : Signal :: new ( None ),
theme : Signal :: new ( Theme :: Light ),
});
rsx! { /* children can access AppState */ }
}
Async Hooks
use_coroutine
Create a coroutine with a channel:
let submit = use_coroutine ( | mut rx | async move {
while let Some ( data ) = rx . next () . await {
// Process data
save_to_server ( data ) . await ;
}
});
rsx! {
button {
onclick : move | _ | submit . send ( form_data . clone ()),
"Submit"
}
}
Lifecycle Hooks
use_drop
Run cleanup on component unmount:
use_drop ( move || {
println! ( "Component unmounting!" );
// Cleanup resources
});
Creating Custom Hooks
Custom hooks let you extract reusable logic:
// Custom hook for form input
fn use_input ( initial : & str ) -> ( Signal < String >, impl Fn () -> String ) {
let mut value = use_signal ( || initial . to_string ());
let get_value = move || value ();
( value , get_value )
}
// Usage
fn LoginForm () -> Element {
let ( mut username , get_username ) = use_input ( "" );
let ( mut password , get_password ) = use_input ( "" );
rsx! {
input {
value : "{username}" ,
oninput : move | e | username . set ( e . value ()),
}
input {
r#type : "password" ,
value : "{password}" ,
oninput : move | e | password . set ( e . value ()),
}
button {
onclick : move | _ | {
login ( get_username (), get_password ());
},
"Login"
}
}
}
Hook Composition
Compose multiple hooks:
fn use_counter ( initial : i32 , step : i32 ) -> Signal < i32 > {
let mut count = use_signal ( move || initial );
use_effect ( move || {
println! ( "Counter: {}" , count ());
});
count
}
fn use_toggle () -> ( Signal < bool >, impl Fn ()) {
let mut state = use_signal ( || false );
let toggle = move || state . toggle ();
( state , toggle )
}
Common Patterns
fn use_debounced_value < T : Clone + ' static >(
value : T ,
delay_ms : u64 ,
) -> Signal < T > {
let mut debounced = use_signal ( || value . clone ());
use_effect ( move || {
let value = value . clone ();
spawn ( async move {
async_std :: task :: sleep (
std :: time :: Duration :: from_millis ( delay_ms )
) . await ;
debounced . set ( value );
});
});
debounced
}
Previous Value
fn use_previous < T : Clone + ' static >( value : T ) -> Signal < Option < T >> {
let mut previous = use_signal ( || None );
use_effect ( move || {
previous . set ( Some ( value . clone ()));
});
previous
}
Local Storage
fn use_local_storage (
key : & ' static str ,
initial : String ,
) -> Signal < String > {
let mut value = use_signal ( move || {
// Load from localStorage
load_from_storage ( key ) . unwrap_or ( initial . clone ())
});
use_effect ( move || {
// Save to localStorage when value changes
save_to_storage ( key , & value ());
});
value
}
Hook Dependencies
Use use_reactive! for explicit dependencies:
#[component]
fn UserProfile ( user_id : i32 ) -> Element {
let user = use_resource (
use_reactive! ( | user_id | async move {
fetch_user ( user_id ) . await
})
);
rsx! { /* render user */ }
}
Best Practices
Follow Hook Rules Always call hooks in the same order - no conditions, loops, or early returns before hooks.
Name with use_ Prefix Custom hooks must start with use_ to clearly indicate they follow hook rules.
Extract Reusable Logic Create custom hooks when you find yourself duplicating stateful logic.
Keep Effects Focused Each use_effect should do one thing. Split complex effects into multiple hooks.
Comparison with React Hooks
React Dioxus useStateuse_signaluseEffectuse_effectuseMemouse_memouseCallbackuse_callbackuseContextuse_contextuseReducerCustom pattern with signals useRefuse_signal (signals are Copy)
See Also