use_websocket
Creating and managing a Websocket connection.
Demo
Usage
Values are (en)decoded via the given codec. You can use any of the codecs, string or binary.
Please check the codec chapter to see what codecs are available and what feature flags they require.
use leptos::prelude::*;
use codee::string::FromToStringCodec;
use leptos_use::{use_websocket, UseWebSocketReturn};
use leptos_use::core::ConnectionReadyState;
#[component]
fn Demo() -> impl IntoView {
let UseWebSocketReturn {
ready_state,
message,
send,
open,
close,
..
} = use_websocket::<String, String, FromToStringCodec>("wss://echo.websocket.events/");
let send_message = move |_| {
send(&"Hello, world!".to_string());
};
let status = move || ready_state.get().to_string();
let connected = move || ready_state.get() == ConnectionReadyState::Open;
let open_connection = move |_| {
open();
};
let close_connection = move |_| {
close();
};
view! {
<div>
<p>"status: " {status}</p>
<button on:click=send_message disabled=move || !connected()>"Send"</button>
<button on:click=open_connection disabled=connected>"Open"</button>
<button on:click=close_connection disabled=move || !connected()>"Close"</button>
<p>"Receive message: " {move || format!("{:?}", message.get())}</p>
</div>
}
}
Here is another example using msgpack
for encoding and decoding. This means that only binary
messages can be sent or received. For this to work you have to enable the msgpack_serde
feature flag.
use leptos::*;
use codee::binary::MsgpackSerdeCodec;
use leptos_use::{use_websocket, UseWebSocketReturn};
use serde::{Deserialize, Serialize};
#[component]
fn Demo() -> impl IntoView {
#[derive(Serialize, Deserialize)]
struct SomeData {
name: String,
count: i32,
}
let UseWebSocketReturn {
message,
send,
..
} = use_websocket::<SomeData, SomeData, MsgpackSerdeCodec>("wss://some.websocket.server/");
let send_data = move || {
send(&SomeData {
name: "John Doe".to_string(),
count: 42,
});
};
view! {}
}
Heartbeats
Heartbeats can be configured by the heartbeat
option. You have to provide a heartbeat
type, that implements the Default
trait and an Encoder
for it. This encoder doesn't have
to be the same as the one used for the other websocket messages.
use leptos::*;
use codee::string::FromToStringCodec;
use leptos_use::{use_websocket_with_options, UseWebSocketOptions, UseWebSocketReturn};
use serde::{Deserialize, Serialize};
#[component]
fn Demo() -> impl IntoView {
#[derive(Default)]
struct Heartbeat;
// Simple example for usage with `FromToStringCodec`
impl std::fmt::Display for Heartbeat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<Heartbeat>")
}
}
let UseWebSocketReturn {
send,
message,
..
} = use_websocket_with_options::<String, String, FromToStringCodec, _, _>(
"wss://echo.websocket.events/",
UseWebSocketOptions::default()
// Enable heartbeats every 10 seconds. In this case we use the same codec as for the
// other messages. But this is not necessary.
.heartbeat::<Heartbeat, FromToStringCodec>(10_000),
);
view! {}
}
Relative Paths
If the provided url
is relative, it will be resolved relative to the current page.
Urls will be resolved like this the following. Please note that the protocol (http vs https) will
be taken into account as well.
Current Page | Relative Url | Resolved Url |
---|---|---|
http://example.com/some/where | /api/ws | ws://example.com/api/ws |
https://example.com/some/where | /api/ws | wss://example.com/api/ws |
https://example.com/some/where | api/ws | wss://example.com/some/where/api/ws |
https://example.com/some/where | //otherdomain.com/api/ws | wss://otherdomain.com/api/ws |
Usage with provide_context
The return value of use_websocket
utilizes several type parameters which can make it
cumbersome to use with provide_context
+ expect_context
.
The following example shows how to avoid type parameters with dynamic dispatch.
This sacrifices a little bit of performance for the sake of ergonomics. However,
compared to network transmission speeds this loss of performance is negligible.
First we define the struct
that is going to be passed around as context.
use leptos::prelude::*;
use std::sync::Arc;
#[derive(Clone)]
pub struct WebsocketContext {
pub message: Signal<Option<String>>,
send: Arc<dyn Fn(&String)>, // use Arc to make it easily cloneable
}
impl WebsocketContext {
pub fn new(message: Signal<Option<String>>, send: Arc<dyn Fn(&String)>) -> Self {
Self {
message,
send,
}
}
// create a method to avoid having to use parantheses around the field
#[inline(always)]
pub fn send(&self, message: &str) {
(self.send)(&message.to_string())
}
}
Now you can provide the context like the following.
use leptos::prelude::*;
use codee::string::FromToStringCodec;
use leptos_use::{use_websocket, UseWebSocketReturn};
use std::sync::Arc;
#[derive(Clone)]
pub struct WebsocketContext {
pub message: Signal<Option<String>>,
send: Arc<dyn Fn(&String) + Send + Sync>,
}
impl WebsocketContext {
pub fn new(message: Signal<Option<String>>, send: Arc<dyn Fn(&String) + Send + Sync>) -> Self {
Self {
message,
send,
}
}
}
#[component]
fn Demo() -> impl IntoView {
let UseWebSocketReturn {
message,
send,
..
} = use_websocket::<String, String, FromToStringCodec>("ws:://some.websocket.io");
provide_context(WebsocketContext::new(message, Arc::new(send.clone())));
view! {}
}
Finally let's use the context:
use leptos::prelude::*;
use leptos_use::{use_websocket, UseWebSocketReturn};
use std::sync::Arc;
#[derive(Clone)]
pub struct WebsocketContext {
pub message: Signal<Option<String>>,
send: Arc<dyn Fn(&String)>,
}
impl WebsocketContext {
#[inline(always)]
pub fn send(&self, message: &str) {
(self.send)(&message.to_string())
}
}
#[component]
fn Demo() -> impl IntoView {
let websocket = expect_context::<WebsocketContext>();
websocket.send("Hello World!");
view! {}
}
Server-Side Rendering
On the server the returned functions amount to no-ops.
Feature
This function is only available if the crate feature
use_websocket
is enabled
Types
struct UseWebSocketOptions
struct DummyEncoder
struct HeartbeatOptions
struct UseWebSocketReturn
enum UseWebSocketError