react/use_ref/
use_ref.rs

1use std::{cell::RefCell, rc::Rc};
2
3use crate::{IntoRc, IntoRefValue, ReadRef, WriteRef};
4
5pub fn use_ref<T: 'static + ?Sized>(initial_value: Rc<T>) -> MutableRefRc<T> {
6    let rc = crate::use_ref_cell(initial_value);
7    MutableRefRc(rc)
8}
9
10pub fn use_ref_with<T: 'static + ?Sized, F: FnOnce() -> Rc<T>>(
11    get_initial_value: F,
12) -> MutableRefRc<T> {
13    let ref_cell = super::use_ref_cell_with::<Rc<T>, _>(move || get_initial_value().into_rc());
14    MutableRefRc(ref_cell)
15}
16
17/// `value` will be the initial value.
18/// And in each render, if `value` changes,
19/// the [`MutableRefRc`] will be set as it.
20///
21/// ```no_run
22/// # use std::rc::Rc;
23/// # fn get_value() -> Rc<i32> { Rc::new(0) }
24/// let value: Rc<i32> = get_value();
25/// react::use_ref_set_as(value);
26/// ```
27///
28/// The above rust code is equivalent to js code:
29///
30/// ```js
31/// const value = getValue();
32/// const refValue = React.useRef(value);
33/// if (refValue.current != value) {
34///     refValue.current = value;
35/// }
36/// ```
37pub fn use_ref_set_as<T: 'static + ?Sized>(value: Rc<T>) -> MutableRefRc<T> {
38    let ref_value = use_ref(Rc::clone(&value));
39    if !Rc::ptr_eq(&*ref_value.0 .0.borrow(), &value) {
40        ref_value.set_current(value)
41    }
42    ref_value
43}
44
45pub struct MutableRefRc<T: ?Sized>(super::ReadRefRc<RefCell<Rc<T>>>);
46
47impl<T: ?Sized + std::fmt::Debug> std::fmt::Debug for MutableRefRc<T> {
48    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49        let v = self.0 .0.borrow();
50        let v = &**v;
51        f.debug_tuple("MutableRefRc").field(&v).finish()
52    }
53}
54
55impl<T: ?Sized> PartialEq for MutableRefRc<T> {
56    fn eq(&self, other: &Self) -> bool {
57        self.0 == other.0
58    }
59}
60
61impl<T: ?Sized> Eq for MutableRefRc<T> {}
62
63impl<T: ?Sized> Clone for MutableRefRc<T> {
64    fn clone(&self) -> Self {
65        Self(self.0.clone())
66    }
67}
68
69impl<T: ?Sized> ReadRef<Rc<T>> for MutableRefRc<T> {
70    #[inline]
71    fn current(&self) -> Rc<T> {
72        let a = self.0 .0.borrow();
73        Rc::clone(&*a)
74    }
75}
76
77impl<T: ?Sized, S: IntoRefValue<Rc<T>>> WriteRef<S> for MutableRefRc<T> {
78    #[inline]
79    fn set_current(&self, v: S) {
80        let v: Rc<T> = v.into_ref_value();
81        let mut a = self.0 .0.borrow_mut();
82        *a = v;
83    }
84}
85
86impl<T> crate::SafeIntoJsRuntime for MutableRefRc<T>
87where
88    dyn Fn(T): wasm_bindgen::closure::WasmClosure,
89    T: 'static,
90{
91    fn safe_into_js_runtime(self) -> crate::PassedToJsRuntime {
92        crate::AnyFn::new(move |v| self.set_current(v)).safe_into_js_runtime()
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use std::rc::Rc;
99
100    use super::super::WriteRef;
101    use super::MutableRefRc;
102
103    #[test]
104    fn auto_impl_write_ref() {
105        let _func_rc: fn(&MutableRefRc<i32>, v: Rc<i32>) =
106            <MutableRefRc<i32> as WriteRef<Rc<i32>>>::set_current;
107        let _func: fn(&MutableRefRc<i32>, v: i32) =
108            <MutableRefRc<i32> as WriteRef<i32>>::set_current;
109    }
110}