Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Debug NodeRef Warning (#2414) #2467

Merged
merged 6 commits into from
May 6, 2024
Merged
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 54 additions & 38 deletions leptos_dom/src/node_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,48 @@ use crate::{html::ElementDescriptor, HtmlElement};
use leptos_reactive::{create_render_effect, signal_prelude::*};
use std::cell::Cell;

/// Contains a shared reference to a DOM node created while using the `view`
/// macro to create your UI.
///
/// ```
/// # use leptos::{*, logging::log};
/// use leptos::html::Input;
///
/// #[component]
/// pub fn MyComponent() -> impl IntoView {
/// let input_ref = create_node_ref::<Input>();
///
/// let on_click = move |_| {
/// let node =
/// input_ref.get().expect("input_ref should be loaded by now");
/// // `node` is strongly typed
/// // it is dereferenced to an `HtmlInputElement` automatically
/// log!("value is {:?}", node.value())
/// };
///
/// view! {
/// <div>
/// // `node_ref` loads the input
/// <input _ref=input_ref type="text"/>
/// // the button consumes it
/// <button on:click=on_click>"Click me"</button>
/// </div>
/// }
/// }
/// ```
#[repr(transparent)]
pub struct NodeRef<T: ElementDescriptor + 'static>(
RwSignal<Option<HtmlElement<T>>>,
cfg_if::cfg_if!(
if #[cfg(debug_assertions)] {
#[allow(missing_docs)]
gbj marked this conversation as resolved.
Show resolved Hide resolved
pub struct NodeRef<T: ElementDescriptor + 'static> {
element: RwSignal<Option<HtmlElement<T>>>,
defined_at: &'static std::panic::Location<'static>,
}
} else {
/// Contains a shared reference to a DOM node created while using the `view`
/// macro to create your UI.
///
/// ```
/// # use leptos::{*, logging::log};
/// use leptos::html::Input;
///
/// #[component]
/// pub fn MyComponent() -> impl IntoView {
/// let input_ref = create_node_ref::<Input>();
///
/// let on_click = move |_| {
/// let node =
/// input_ref.get().expect("input_ref should be loaded by now");
/// // `node` is strongly typed
/// // it is dereferenced to an `HtmlInputElement` automatically
/// log!("value is {:?}", node.value())
/// };
///
/// view! {
/// <div>
/// // `node_ref` loads the input
/// <input _ref=input_ref type="text"/>
/// // the button consumes it
/// <button on:click=on_click>"Click me"</button>
/// </div>
/// }
/// }
/// ```
#[repr(transparent)]
gbj marked this conversation as resolved.
Show resolved Hide resolved
pub struct NodeRef<T: ElementDescriptor + 'static> {
element: RwSignal<Option<HtmlElement<T>>>,
}
}
);

/// Creates a shared reference to a DOM node created while using the `view`
Expand Down Expand Up @@ -65,9 +75,13 @@ pub struct NodeRef<T: ElementDescriptor + 'static>(
/// }
/// }
/// ```
#[track_caller]
#[inline(always)]
pub fn create_node_ref<T: ElementDescriptor + 'static>() -> NodeRef<T> {
NodeRef(create_rw_signal(None))
NodeRef {
defined_at: std::panic::Location::caller(),
gbj marked this conversation as resolved.
Show resolved Hide resolved
element: create_rw_signal(None),
}
}

impl<T: ElementDescriptor + 'static> NodeRef<T> {
Expand Down Expand Up @@ -120,7 +134,7 @@ impl<T: ElementDescriptor + 'static> NodeRef<T> {
where
T: Clone,
{
self.0.get()
self.element.get()
}

/// Gets the element that is currently stored in the reference.
Expand All @@ -132,7 +146,7 @@ impl<T: ElementDescriptor + 'static> NodeRef<T> {
where
T: Clone,
{
self.0.get_untracked()
self.element.get_untracked()
}

#[doc(hidden)]
Expand All @@ -144,13 +158,15 @@ impl<T: ElementDescriptor + 'static> NodeRef<T> {
where
T: Clone,
{
self.0.update(|current| {
self.element.update(|current| {
if current.is_some() {
crate::debug_warn!(
"You are setting a NodeRef that has already been filled. \
"You are setting the NodeRef defined at {}, which has \
already been filled \
It’s possible this is intentional, but it’s also \
possible that you’re accidentally using the same NodeRef \
for multiple _ref attributes."
for multiple _ref attributes.",
self.defined_at
);
}
*current = Some(node.clone());
Expand Down
Loading