fixed use_event_listener removing of listener with non default options

This commit is contained in:
Maccesch 2023-07-29 15:12:09 +01:00
parent 413a6f933e
commit fa47bab2cd
3 changed files with 162 additions and 158 deletions

View file

@ -28,6 +28,7 @@ wasm-bindgen-futures = "0.4"
[dependencies.web-sys] [dependencies.web-sys]
version = "0.3" version = "0.3"
features = [ features = [
"AddEventListenerOptions",
"BinaryType", "BinaryType",
"CssStyleDeclaration", "CssStyleDeclaration",
"CloseEvent", "CloseEvent",
@ -38,6 +39,9 @@ features = [
"DataTransfer", "DataTransfer",
"DragEvent", "DragEvent",
"Element", "Element",
"EventListener",
"EventListenerOptions",
"EventTarget",
"File", "File",
"FileList", "FileList",
"HtmlElement", "HtmlElement",

View file

@ -112,11 +112,13 @@ where
let cleanup_fn = { let cleanup_fn = {
let closure_js = closure_js.clone(); let closure_js = closure_js.clone();
let options = options.clone();
move |element: &web_sys::EventTarget| { move |element: &web_sys::EventTarget| {
let _ = element.remove_event_listener_with_callback( let _ = element.remove_event_listener_with_callback_and_event_listener_options(
&event_name, &event_name,
closure_js.as_ref().unchecked_ref(), closure_js.as_ref().unchecked_ref(),
options.unchecked_ref(),
); );
} }
}; };
@ -125,8 +127,7 @@ where
let signal = (target).into(); let signal = (target).into();
let prev_element: Rc<RefCell<Option<web_sys::EventTarget>>> = let prev_element = Rc::new(RefCell::new(None::<web_sys::EventTarget>));
Rc::new(RefCell::new(signal.get_untracked().map(|e| e.into())));
let cleanup_prev_element = { let cleanup_prev_element = {
let prev_element = prev_element.clone(); let prev_element = prev_element.clone();

View file

@ -24,7 +24,8 @@ use crate::utils::CloneableFnWithArg;
/// ///
/// ``` /// ```
/// # use leptos::*; /// # use leptos::*;
/// # use leptos_use::{use_websocket, UseWebsocketReturn}; /// # use leptos_use::{use_websocket, UseWebsocketReturn};
/// # use leptos_use::core::ConnectionReadyState;
/// # /// #
/// # #[component] /// # #[component]
/// # fn Demo() -> impl IntoView { /// # fn Demo() -> impl IntoView {
@ -37,16 +38,14 @@ use crate::utils::CloneableFnWithArg;
/// open, /// open,
/// close, /// close,
/// .. /// ..
/// } = use_websocket("wss://echo.websocket.events/".to_string()); /// } = use_websocket("wss://echo.websocket.events/");
/// ///
/// let send_message = move |_| { /// let send_message = move |_| {
/// let m = "Hello, world!".to_string(); /// send("Hello, world!".to_string());
/// send(m.clone());
/// }; /// };
/// ///
/// let send_byte_message = move |_| { /// let send_byte_message = move |_| {
/// let m = b"Hello, world!\r\n".to_vec(); /// send_bytes(b"Hello, world!\r\n".to_vec());
/// send_bytes(m.clone());
/// }; /// };
/// ///
/// let status = move || ready_state.get().to_string(); /// let status = move || ready_state.get().to_string();
@ -118,167 +117,167 @@ pub fn use_websocket_with_options(
let connect_ref: StoredValue<Option<Rc<dyn Fn()>>> = store_value(None); let connect_ref: StoredValue<Option<Rc<dyn Fn()>>> = store_value(None);
// cfg_if! { if #[cfg(not(feature = "ssr"))] { cfg_if! { if #[cfg(not(feature = "ssr"))] {
let on_open_ref = store_value(options.on_open); let on_open_ref = store_value(options.on_open);
let on_message_ref = store_value(options.on_message); let on_message_ref = store_value(options.on_message);
let on_message_bytes_ref = store_value(options.on_message_bytes); let on_message_bytes_ref = store_value(options.on_message_bytes);
let on_error_ref = store_value(options.on_error); let on_error_ref = store_value(options.on_error);
let on_close_ref = store_value(options.on_close); let on_close_ref = store_value(options.on_close);
let reconnect_interval = options.reconnect_interval; let reconnect_interval = options.reconnect_interval;
let protocols = options.protocols; let protocols = options.protocols;
let reconnect_ref: StoredValue<Option<Rc<dyn Fn()>>> = store_value(None); let reconnect_ref: StoredValue<Option<Rc<dyn Fn()>>> = store_value(None);
reconnect_ref.set_value({ reconnect_ref.set_value({
let ws = ws_ref.get_value(); let ws = ws_ref.get_value();
Some(Rc::new(move || { Some(Rc::new(move || {
if reconnect_times_ref.get_value() < reconnect_limit if reconnect_times_ref.get_value() < reconnect_limit
&& ws && ws
.clone() .clone()
.map_or(false, |ws: WebSocket| ws.ready_state() != WebSocket::OPEN) .map_or(false, |ws: WebSocket| ws.ready_state() != WebSocket::OPEN)
{ {
reconnect_timer_ref.set_value( reconnect_timer_ref.set_value(
set_timeout_with_handle( set_timeout_with_handle(
move || { move || {
if let Some(connect) = connect_ref.get_value() { if let Some(connect) = connect_ref.get_value() {
connect(); connect();
reconnect_times_ref.update_value(|current| *current += 1); reconnect_times_ref.update_value(|current| *current += 1);
} }
}, },
Duration::from_millis(reconnect_interval), Duration::from_millis(reconnect_interval),
) )
.ok(), .ok(),
);
}
}))
});
connect_ref.set_value({
let ws = ws_ref.get_value();
let url = url;
Some(Rc::new(move || {
reconnect_timer_ref.set_value(None);
if let Some(web_socket) = &ws {
let _ = web_socket.close();
}
let web_socket = {
protocols.as_ref().map_or_else(
|| WebSocket::new(&url).unwrap_throw(),
|protocols| {
let array = protocols
.iter()
.map(|p| JsValue::from(p.clone()))
.collect::<Array>();
WebSocket::new_with_str_sequence(&url, &JsValue::from(&array))
.unwrap_throw()
},
)
};
web_socket.set_binary_type(BinaryType::Arraybuffer);
set_ready_state.set(ConnectionReadyState::Connecting);
// onopen handler
{
let onopen_closure = Closure::wrap(Box::new(move |e: Event| {
if unmounted_ref.get_value() {
return;
}
let callback = on_open_ref.get_value();
callback(e);
set_ready_state.set(ConnectionReadyState::Open);
}) as Box<dyn FnMut(Event)>);
web_socket.set_onopen(Some(onopen_closure.as_ref().unchecked_ref()));
// Forget the closure to keep it alive
onopen_closure.forget();
}
// onmessage handler
{
let onmessage_closure = Closure::wrap(Box::new(move |e: MessageEvent| {
if unmounted_ref.get_value() {
return;
}
e.data().dyn_into::<js_sys::ArrayBuffer>().map_or_else(
|_| {
e.data().dyn_into::<js_sys::JsString>().map_or_else(
|_| {
unreachable!("message event, received Unknown: {:?}", e.data());
},
|txt| {
let txt = String::from(&txt);
let callback = on_message_ref.get_value();
callback(txt.clone());
set_message.set(Some(txt));
},
);
},
|array_buffer| {
let array = js_sys::Uint8Array::new(&array_buffer);
let array = array.to_vec();
let callback = on_message_bytes_ref.get_value();
callback(array.clone());
set_message_bytes.set(Some(array));
},
); );
}) }
as Box<dyn FnMut(MessageEvent)>); }))
web_socket.set_onmessage(Some(onmessage_closure.as_ref().unchecked_ref())); });
onmessage_closure.forget();
}
// onerror handler connect_ref.set_value({
{ let ws = ws_ref.get_value();
let onerror_closure = Closure::wrap(Box::new(move |e: Event| { let url = url;
if unmounted_ref.get_value() {
return;
}
if let Some(reconnect) = &reconnect_ref.get_value() { Some(Rc::new(move || {
reconnect(); reconnect_timer_ref.set_value(None);
}
let callback = on_error_ref.get_value(); if let Some(web_socket) = &ws {
callback(e); let _ = web_socket.close();
}
set_ready_state.set(ConnectionReadyState::Closed); let web_socket = {
}) as Box<dyn FnMut(Event)>); protocols.as_ref().map_or_else(
web_socket.set_onerror(Some(onerror_closure.as_ref().unchecked_ref())); || WebSocket::new(&url).unwrap_throw(),
onerror_closure.forget(); |protocols| {
} let array = protocols
.iter()
.map(|p| JsValue::from(p.clone()))
.collect::<Array>();
WebSocket::new_with_str_sequence(&url, &JsValue::from(&array))
.unwrap_throw()
},
)
};
web_socket.set_binary_type(BinaryType::Arraybuffer);
set_ready_state.set(ConnectionReadyState::Connecting);
// onclose handler // onopen handler
{ {
let onclose_closure = Closure::wrap(Box::new(move |e: CloseEvent| { let onopen_closure = Closure::wrap(Box::new(move |e: Event| {
if unmounted_ref.get_value() { if unmounted_ref.get_value() {
return; return;
} }
if let Some(reconnect) = &reconnect_ref.get_value() { let callback = on_open_ref.get_value();
reconnect(); callback(e);
}
let callback = on_close_ref.get_value(); set_ready_state.set(ConnectionReadyState::Open);
callback(e); }) as Box<dyn FnMut(Event)>);
web_socket.set_onopen(Some(onopen_closure.as_ref().unchecked_ref()));
// Forget the closure to keep it alive
onopen_closure.forget();
}
set_ready_state.set(ConnectionReadyState::Closed); // onmessage handler
}) {
as Box<dyn FnMut(CloseEvent)>); let onmessage_closure = Closure::wrap(Box::new(move |e: MessageEvent| {
web_socket.set_onclose(Some(onclose_closure.as_ref().unchecked_ref())); if unmounted_ref.get_value() {
onclose_closure.forget(); return;
} }
ws_ref.set_value(Some(web_socket)); e.data().dyn_into::<js_sys::ArrayBuffer>().map_or_else(
})) |_| {
}); e.data().dyn_into::<js_sys::JsString>().map_or_else(
// }} |_| {
unreachable!("message event, received Unknown: {:?}", e.data());
},
|txt| {
let txt = String::from(&txt);
let callback = on_message_ref.get_value();
callback(txt.clone());
set_message.set(Some(txt));
},
);
},
|array_buffer| {
let array = js_sys::Uint8Array::new(&array_buffer);
let array = array.to_vec();
let callback = on_message_bytes_ref.get_value();
callback(array.clone());
set_message_bytes.set(Some(array));
},
);
})
as Box<dyn FnMut(MessageEvent)>);
web_socket.set_onmessage(Some(onmessage_closure.as_ref().unchecked_ref()));
onmessage_closure.forget();
}
// onerror handler
{
let onerror_closure = Closure::wrap(Box::new(move |e: Event| {
if unmounted_ref.get_value() {
return;
}
if let Some(reconnect) = &reconnect_ref.get_value() {
reconnect();
}
let callback = on_error_ref.get_value();
callback(e);
set_ready_state.set(ConnectionReadyState::Closed);
}) as Box<dyn FnMut(Event)>);
web_socket.set_onerror(Some(onerror_closure.as_ref().unchecked_ref()));
onerror_closure.forget();
}
// onclose handler
{
let onclose_closure = Closure::wrap(Box::new(move |e: CloseEvent| {
if unmounted_ref.get_value() {
return;
}
if let Some(reconnect) = &reconnect_ref.get_value() {
reconnect();
}
let callback = on_close_ref.get_value();
callback(e);
set_ready_state.set(ConnectionReadyState::Closed);
})
as Box<dyn FnMut(CloseEvent)>);
web_socket.set_onclose(Some(onclose_closure.as_ref().unchecked_ref()));
onclose_closure.forget();
}
ws_ref.set_value(Some(web_socket));
}))
});
}}
// Send text (String) // Send text (String)
let send = { let send = {