Remove argument from use_hook closure (#496)

Also; update docs for said function
This commit is contained in:
Reinis Mazeiks 2022-07-11 22:50:56 +03:00 committed by GitHub
parent 6ea076fa7f
commit d734dc5b46
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 53 additions and 55 deletions

View file

@ -23,7 +23,7 @@ fn main() {
} }
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
let text = cx.use_hook(|_| vec![String::from("abc=def")]); let text = cx.use_hook(|| vec![String::from("abc=def")]);
let first = text.get_mut(0).unwrap(); let first = text.get_mut(0).unwrap();

View file

@ -658,7 +658,7 @@ impl ScopeState {
/// struct SharedState(&'static str); /// struct SharedState(&'static str);
/// ///
/// static App: Component = |cx| { /// static App: Component = |cx| {
/// cx.use_hook(|_| cx.provide_context(SharedState("world"))); /// cx.use_hook(|| cx.provide_context(SharedState("world")));
/// rsx!(cx, Child {}) /// rsx!(cx, Child {})
/// } /// }
/// ///
@ -684,7 +684,7 @@ impl ScopeState {
/// struct SharedState(&'static str); /// struct SharedState(&'static str);
/// ///
/// static App: Component = |cx| { /// static App: Component = |cx| {
/// cx.use_hook(|_| cx.provide_root_context(SharedState("world"))); /// cx.use_hook(|| cx.provide_root_context(SharedState("world")));
/// rsx!(cx, Child {}) /// rsx!(cx, Child {})
/// } /// }
/// ///
@ -811,33 +811,31 @@ impl ScopeState {
})) }))
} }
/// Store a value between renders /// Store a value between renders. The foundational hook for all other hooks.
/// ///
/// This is *the* foundational hook for all other hooks. /// Accepts an `initializer` closure, which is run on the first use of the hook (typically the initial render). The return value of this closure is stored for the lifetime of the component, and a mutable reference to it is provided on every render as the return value of `use_hook`.
/// ///
/// - Initializer: closure used to create the initial hook state /// When the component is unmounted (removed from the UI), the value is dropped. This means you can return a custom type and provide cleanup code by implementing the [`Drop`] trait
/// - Runner: closure used to output a value every time the hook is used
///
/// To "cleanup" the hook, implement `Drop` on the stored hook value. Whenever the component is dropped, the hook
/// will be dropped as well.
/// ///
/// # Example /// # Example
/// ///
/// ```ignore /// ```
/// // use_ref is the simplest way of storing a value between renders /// use dioxus_core::ScopeState;
/// fn use_ref<T: 'static>(initial_value: impl FnOnce() -> T) -> &RefCell<T> { ///
/// use_hook(|| Rc::new(RefCell::new(initial_value()))) /// // prints a greeting on the initial render
/// pub fn use_hello_world(cx: &ScopeState) {
/// cx.use_hook(|| println!("Hello, world!"));
/// } /// }
/// ``` /// ```
#[allow(clippy::mut_from_ref)] #[allow(clippy::mut_from_ref)]
pub fn use_hook<State: 'static>(&self, initializer: impl FnOnce(usize) -> State) -> &mut State { pub fn use_hook<State: 'static>(&self, initializer: impl FnOnce() -> State) -> &mut State {
let mut vals = self.hook_vals.borrow_mut(); let mut vals = self.hook_vals.borrow_mut();
let hook_len = vals.len(); let hook_len = vals.len();
let cur_idx = self.hook_idx.get(); let cur_idx = self.hook_idx.get();
if cur_idx >= hook_len { if cur_idx >= hook_len {
vals.push(self.hook_arena.alloc(initializer(hook_len))); vals.push(self.hook_arena.alloc(initializer()));
} }
vals vals

View file

@ -10,7 +10,7 @@ pub type ProxyType = EventLoopProxy<UserWindowEvent>;
/// Get an imperative handle to the current window /// Get an imperative handle to the current window
pub fn use_window(cx: &ScopeState) -> &DesktopContext { pub fn use_window(cx: &ScopeState) -> &DesktopContext {
cx.use_hook(|_| cx.consume_context::<DesktopContext>()) cx.use_hook(|| cx.consume_context::<DesktopContext>())
.as_ref() .as_ref()
.unwrap() .unwrap()
} }
@ -232,5 +232,5 @@ pub(super) fn handler(
pub fn use_eval<S: std::string::ToString>(cx: &ScopeState) -> &dyn Fn(S) { pub fn use_eval<S: std::string::ToString>(cx: &ScopeState) -> &dyn Fn(S) {
let desktop = use_window(cx).clone(); let desktop = use_window(cx).clone();
cx.use_hook(|_| move |script| desktop.eval(script)) cx.use_hook(|| move |script| desktop.eval(script))
} }

View file

@ -8,7 +8,7 @@ fn test_borrowed_state() {
} }
fn Parent(cx: Scope) -> Element { fn Parent(cx: Scope) -> Element {
let value = cx.use_hook(|_| String::new()); let value = cx.use_hook(|| String::new());
cx.render(rsx! { cx.render(rsx! {
div { div {

View file

@ -20,7 +20,7 @@ fn new_dom<P: 'static + Send>(app: Component<P>, props: P) -> VirtualDom {
#[test] #[test]
fn test_early_abort() { fn test_early_abort() {
const app: Component = |cx| { const app: Component = |cx| {
let val = cx.use_hook(|_| 0); let val = cx.use_hook(|| 0);
*val += 1; *val += 1;

View file

@ -34,7 +34,7 @@ fn manual_diffing() {
#[test] #[test]
fn events_generate() { fn events_generate() {
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
let count = cx.use_hook(|_| 0); let count = cx.use_hook(|| 0);
let inner = match *count { let inner = match *count {
0 => { 0 => {
@ -77,7 +77,7 @@ fn events_generate() {
#[test] #[test]
fn components_generate() { fn components_generate() {
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
let render_phase = cx.use_hook(|_| 0); let render_phase = cx.use_hook(|| 0);
*render_phase += 1; *render_phase += 1;
cx.render(match *render_phase { cx.render(match *render_phase {
@ -171,7 +171,7 @@ fn components_generate() {
#[test] #[test]
fn component_swap() { fn component_swap() {
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
let render_phase = cx.use_hook(|_| 0); let render_phase = cx.use_hook(|| 0);
*render_phase += 1; *render_phase += 1;
cx.render(match *render_phase { cx.render(match *render_phase {

View file

@ -22,7 +22,7 @@ fn new_dom<P: 'static + Send>(app: Component<P>, props: P) -> VirtualDom {
#[test] #[test]
fn test_memory_leak() { fn test_memory_leak() {
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
let val = cx.use_hook(|_| 0); let val = cx.use_hook(|| 0);
*val += 1; *val += 1;
@ -30,7 +30,7 @@ fn test_memory_leak() {
return None; return None;
} }
let name = cx.use_hook(|_| String::from("asd")); let name = cx.use_hook(|| String::from("asd"));
cx.render(rsx!( cx.render(rsx!(
div { "Hello, world!" } div { "Hello, world!" }
@ -79,7 +79,7 @@ fn test_memory_leak() {
#[test] #[test]
fn memo_works_properly() { fn memo_works_properly() {
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
let val = cx.use_hook(|_| 0); let val = cx.use_hook(|| 0);
*val += 1; *val += 1;
@ -87,7 +87,7 @@ fn memo_works_properly() {
return None; return None;
} }
let name = cx.use_hook(|_| String::from("asd")); let name = cx.use_hook(|| String::from("asd"));
cx.render(rsx!( cx.render(rsx!(
div { "Hello, world! {name}" } div { "Hello, world! {name}" }
@ -192,7 +192,7 @@ fn free_works_on_root_hooks() {
} }
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
let name = cx.use_hook(|_| Droppable(String::from("asd"))); let name = cx.use_hook(|| Droppable(String::from("asd")));
rsx!(cx, div { "{name.0}" }) rsx!(cx, div { "{name.0}" })
} }
@ -204,7 +204,7 @@ fn free_works_on_root_hooks() {
fn old_props_arent_stale() { fn old_props_arent_stale() {
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
dbg!("rendering parent"); dbg!("rendering parent");
let cnt = cx.use_hook(|_| 0); let cnt = cx.use_hook(|| 0);
*cnt += 1; *cnt += 1;
if *cnt == 1 { if *cnt == 1 {

View file

@ -36,7 +36,7 @@ fn swap_test() {
struct MySharedState(&'static str); struct MySharedState(&'static str);
fn app(cx: Scope) -> Element { fn app(cx: Scope) -> Element {
let val = cx.use_hook(|_| 0); let val = cx.use_hook(|| 0);
*val += 1; *val += 1;
cx.provide_context(Rc::new(MySharedState("world!"))); cx.provide_context(Rc::new(MySharedState("world!")));

View file

@ -16,7 +16,7 @@ use std::{
pub fn use_atom_ref<T: 'static>(cx: &ScopeState, atom: AtomRef<T>) -> &UseAtomRef<T> { pub fn use_atom_ref<T: 'static>(cx: &ScopeState, atom: AtomRef<T>) -> &UseAtomRef<T> {
let root = use_atom_root(cx); let root = use_atom_root(cx);
&cx.use_hook(|_| { &cx.use_hook(|| {
root.initialize(atom); root.initialize(atom);
( (
UseAtomRef { UseAtomRef {

View file

@ -4,7 +4,7 @@ use std::rc::Rc;
// Returns the atom root, initiaizing it at the root of the app if it does not exist. // Returns the atom root, initiaizing it at the root of the app if it does not exist.
pub fn use_atom_root(cx: &ScopeState) -> &Rc<AtomRoot> { pub fn use_atom_root(cx: &ScopeState) -> &Rc<AtomRoot> {
cx.use_hook(|_| match cx.consume_context::<Rc<AtomRoot>>() { cx.use_hook(|| match cx.consume_context::<Rc<AtomRoot>>() {
Some(root) => root, Some(root) => root,
None => cx.provide_root_context(Rc::new(AtomRoot::new(cx.schedule_update_any()))), None => cx.provide_root_context(Rc::new(AtomRoot::new(cx.schedule_update_any()))),
}) })

View file

@ -4,7 +4,7 @@ use std::rc::Rc;
// Initializes the atom root and retuns it; // Initializes the atom root and retuns it;
pub fn use_init_atom_root(cx: &ScopeState) -> &Rc<AtomRoot> { pub fn use_init_atom_root(cx: &ScopeState) -> &Rc<AtomRoot> {
cx.use_hook(|_| match cx.consume_context::<Rc<AtomRoot>>() { cx.use_hook(|| match cx.consume_context::<Rc<AtomRoot>>() {
Some(ctx) => ctx, Some(ctx) => ctx,
None => cx.provide_context(Rc::new(AtomRoot::new(cx.schedule_update_any()))), None => cx.provide_context(Rc::new(AtomRoot::new(cx.schedule_update_any()))),
}) })

View file

@ -22,7 +22,7 @@ pub fn use_read_rc<V: 'static>(cx: &ScopeState, f: impl Readable<V>) -> &Rc<V> {
} }
} }
let inner = cx.use_hook(|_| UseReadInner { let inner = cx.use_hook(|| UseReadInner {
value: None, value: None,
root: root.clone(), root: root.clone(),
scope_id: cx.scope_id(), scope_id: cx.scope_id(),

View file

@ -4,7 +4,7 @@ use std::rc::Rc;
pub fn use_set<T: 'static>(cx: &ScopeState, f: impl Writable<T>) -> &Rc<dyn Fn(T)> { pub fn use_set<T: 'static>(cx: &ScopeState, f: impl Writable<T>) -> &Rc<dyn Fn(T)> {
let root = use_atom_root(cx); let root = use_atom_root(cx);
cx.use_hook(|_| { cx.use_hook(|| {
let id = f.unique_id(); let id = f.unique_id();
let root = root.clone(); let root = root.clone();
root.initialize(f); root.initialize(f);

View file

@ -33,7 +33,7 @@ use std::{
pub fn use_atom_state<T: 'static>(cx: &ScopeState, f: impl Writable<T>) -> &AtomState<T> { pub fn use_atom_state<T: 'static>(cx: &ScopeState, f: impl Writable<T>) -> &AtomState<T> {
let root = crate::use_atom_root(cx); let root = crate::use_atom_root(cx);
let inner = cx.use_hook(|_| AtomState { let inner = cx.use_hook(|| AtomState {
value: None, value: None,
root: root.clone(), root: root.clone(),
scope_id: cx.scope_id(), scope_id: cx.scope_id(),

View file

@ -61,7 +61,7 @@ impl<T> ProvidedStateInner<T> {
/// ///
/// ///
pub fn use_context<T: 'static>(cx: &ScopeState) -> Option<UseSharedState<T>> { pub fn use_context<T: 'static>(cx: &ScopeState) -> Option<UseSharedState<T>> {
let state = cx.use_hook(|_| { let state = cx.use_hook(|| {
let scope_id = cx.scope_id(); let scope_id = cx.scope_id();
let root = cx.consume_context::<ProvidedState<T>>(); let root = cx.consume_context::<ProvidedState<T>>();
@ -173,7 +173,7 @@ where
/// ///
/// ///
pub fn use_context_provider<T: 'static>(cx: &ScopeState, f: impl FnOnce() -> T) { pub fn use_context_provider<T: 'static>(cx: &ScopeState, f: impl FnOnce() -> T) {
cx.use_hook(|_| { cx.use_hook(|| {
let state: ProvidedState<T> = Rc::new(RefCell::new(ProvidedStateInner { let state: ProvidedState<T> = Rc::new(RefCell::new(ProvidedStateInner {
value: Rc::new(RefCell::new(f())), value: Rc::new(RefCell::new(f())),
notify_any: cx.schedule_update_any(), notify_any: cx.schedule_update_any(),

View file

@ -65,7 +65,7 @@ where
G: FnOnce(UnboundedReceiver<M>) -> F, G: FnOnce(UnboundedReceiver<M>) -> F,
F: Future<Output = ()> + 'static, F: Future<Output = ()> + 'static,
{ {
cx.use_hook(|_| { cx.use_hook(|| {
let (tx, rx) = futures_channel::mpsc::unbounded(); let (tx, rx) = futures_channel::mpsc::unbounded();
let task = cx.push_future(init(rx)); let task = cx.push_future(init(rx));
cx.provide_context(CoroutineHandle { tx, task }) cx.provide_context(CoroutineHandle { tx, task })
@ -76,7 +76,7 @@ where
/// ///
/// See the docs for [`use_coroutine`] for more details. /// See the docs for [`use_coroutine`] for more details.
pub fn use_coroutine_handle<M: 'static>(cx: &ScopeState) -> Option<&CoroutineHandle<M>> { pub fn use_coroutine_handle<M: 'static>(cx: &ScopeState) -> Option<&CoroutineHandle<M>> {
cx.use_hook(|_| cx.consume_context::<CoroutineHandle<M>>()) cx.use_hook(|| cx.consume_context::<CoroutineHandle<M>>())
.as_ref() .as_ref()
} }

View file

@ -34,7 +34,7 @@ where
dependencies: Vec<Box<dyn Any>>, dependencies: Vec<Box<dyn Any>>,
} }
let state = cx.use_hook(move |_| UseEffect { let state = cx.use_hook(move || UseEffect {
needs_regen: true, needs_regen: true,
task: Cell::new(None), task: Cell::new(None),
dependencies: Vec::new(), dependencies: Vec::new(),

View file

@ -25,7 +25,7 @@ where
F: Future<Output = T> + 'static, F: Future<Output = T> + 'static,
D: UseFutureDep, D: UseFutureDep,
{ {
let state = cx.use_hook(move |_| UseFuture { let state = cx.use_hook(move || UseFuture {
update: cx.schedule_update(), update: cx.schedule_update(),
needs_regen: Cell::new(true), needs_regen: Cell::new(true),
slot: Rc::new(Cell::new(None)), slot: Rc::new(Cell::new(None)),

View file

@ -14,7 +14,7 @@ use std::{
}; };
pub fn use_model<'a, T: 'static>(cx: &'a ScopeState, f: impl FnOnce() -> T) -> UseModel<'a, T> { pub fn use_model<'a, T: 'static>(cx: &'a ScopeState, f: impl FnOnce() -> T) -> UseModel<'a, T> {
let inner = cx.use_hook(|_| UseModelInner { let inner = cx.use_hook(|| UseModelInner {
update_scheduled: Cell::new(false), update_scheduled: Cell::new(false),
update_callback: cx.schedule_update(), update_callback: cx.schedule_update(),
value: RefCell::new(f()), value: RefCell::new(f()),
@ -78,7 +78,7 @@ pub fn use_model_coroutine<'a, T, F: Future<Output = ()> + 'static>(
_model: UseModel<T>, _model: UseModel<T>,
_f: impl FnOnce(AppModels) -> F, _f: impl FnOnce(AppModels) -> F,
) -> UseModelCoroutine { ) -> UseModelCoroutine {
cx.use_hook(|_| UseModelTaskInner { cx.use_hook(|| UseModelTaskInner {
task: Default::default(), task: Default::default(),
}); });
todo!() todo!()

View file

@ -111,7 +111,7 @@ use std::{
/// }) /// })
/// ``` /// ```
pub fn use_ref<T: 'static>(cx: &ScopeState, initialize_refcell: impl FnOnce() -> T) -> &UseRef<T> { pub fn use_ref<T: 'static>(cx: &ScopeState, initialize_refcell: impl FnOnce() -> T) -> &UseRef<T> {
let hook = cx.use_hook(|_| UseRef { let hook = cx.use_hook(|| UseRef {
update: cx.schedule_update(), update: cx.schedule_update(),
value: Rc::new(RefCell::new(initialize_refcell())), value: Rc::new(RefCell::new(initialize_refcell())),
dirty: Rc::new(Cell::new(false)), dirty: Rc::new(Cell::new(false)),

View file

@ -34,7 +34,7 @@ pub fn use_state<T: 'static>(
cx: &ScopeState, cx: &ScopeState,
initial_state_fn: impl FnOnce() -> T, initial_state_fn: impl FnOnce() -> T,
) -> &UseState<T> { ) -> &UseState<T> {
let hook = cx.use_hook(move |_| { let hook = cx.use_hook(move || {
let current_val = Rc::new(initial_state_fn()); let current_val = Rc::new(initial_state_fn());
let update_callback = cx.schedule_update(); let update_callback = cx.schedule_update();
let slot = Rc::new(RefCell::new(current_val.clone())); let slot = Rc::new(RefCell::new(current_val.clone()));

View file

@ -7,7 +7,7 @@ pub fn use_suspense<R: 'static, F: Future<Output = R> + 'static>(
create_future: impl FnOnce() -> F, create_future: impl FnOnce() -> F,
render: impl FnOnce(&R) -> Element, render: impl FnOnce(&R) -> Element,
) -> Element { ) -> Element {
let sus = cx.use_hook(|_| { let sus = cx.use_hook(|| {
let fut = create_future(); let fut = create_future();
let wip_value: Rc<Cell<Option<R>>> = Default::default(); let wip_value: Rc<Cell<Option<R>>> = Default::default();

View file

@ -77,7 +77,7 @@ pub struct LinkProps<'a> {
/// } /// }
/// ``` /// ```
pub fn Link<'a>(cx: Scope<'a, LinkProps<'a>>) -> Element { pub fn Link<'a>(cx: Scope<'a, LinkProps<'a>>) -> Element {
let svc = cx.use_hook(|_| cx.consume_context::<Arc<RouterCore>>()); let svc = cx.use_hook(|| cx.consume_context::<Arc<RouterCore>>());
let LinkProps { let LinkProps {
to, to,

View file

@ -34,7 +34,7 @@ pub struct RedirectProps<'a> {
pub fn Redirect<'a>(cx: Scope<'a, RedirectProps<'a>>) -> Element { pub fn Redirect<'a>(cx: Scope<'a, RedirectProps<'a>>) -> Element {
let router = use_router(&cx); let router = use_router(&cx);
let immediate_redirect = cx.use_hook(|_| { let immediate_redirect = cx.use_hook(|| {
if let Some(from) = cx.props.from { if let Some(from) = cx.props.from {
router.register_total_route(from.to_string(), cx.scope_id()); router.register_total_route(from.to_string(), cx.scope_id());
false false

View file

@ -28,10 +28,10 @@ pub struct RouteProps<'a> {
/// ``` /// ```
pub fn Route<'a>(cx: Scope<'a, RouteProps<'a>>) -> Element { pub fn Route<'a>(cx: Scope<'a, RouteProps<'a>>) -> Element {
let router_root = cx let router_root = cx
.use_hook(|_| cx.consume_context::<Arc<RouterCore>>()) .use_hook(|| cx.consume_context::<Arc<RouterCore>>())
.as_ref()?; .as_ref()?;
cx.use_hook(|_| { cx.use_hook(|| {
// create a bigger, better, longer route if one above us exists // create a bigger, better, longer route if one above us exists
let total_route = match cx.consume_context::<RouteContext>() { let total_route = match cx.consume_context::<RouteContext>() {
Some(ctx) => ctx.total_route, Some(ctx) => ctx.total_route,

View file

@ -37,7 +37,7 @@ pub struct RouterProps<'a> {
/// Will fallback to HashRouter is BrowserRouter is not available, or through configuration. /// Will fallback to HashRouter is BrowserRouter is not available, or through configuration.
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn Router<'a>(cx: Scope<'a, RouterProps<'a>>) -> Element { pub fn Router<'a>(cx: Scope<'a, RouterProps<'a>>) -> Element {
let svc = cx.use_hook(|_| { let svc = cx.use_hook(|| {
cx.provide_context(RouterCore::new( cx.provide_context(RouterCore::new(
&cx, &cx,
RouterCfg { RouterCfg {

View file

@ -7,7 +7,7 @@ use url::Url;
/// context of a [`Router`]. If this function is called outside of a `Router` /// context of a [`Router`]. If this function is called outside of a `Router`
/// component it will panic. /// component it will panic.
pub fn use_route(cx: &ScopeState) -> &UseRoute { pub fn use_route(cx: &ScopeState) -> &UseRoute {
let handle = cx.use_hook(|_| { let handle = cx.use_hook(|| {
let router = cx let router = cx
.consume_context::<RouterService>() .consume_context::<RouterService>()
.expect("Cannot call use_route outside the scope of a Router component"); .expect("Cannot call use_route outside the scope of a Router component");

View file

@ -3,7 +3,7 @@ use dioxus::core::ScopeState;
/// This hook provides access to the `RouterService` for the app. /// This hook provides access to the `RouterService` for the app.
pub fn use_router(cx: &ScopeState) -> &RouterService { pub fn use_router(cx: &ScopeState) -> &RouterService {
cx.use_hook(|_| { cx.use_hook(|| {
cx.consume_context::<RouterService>() cx.consume_context::<RouterService>()
.expect("Cannot call use_route outside the scope of a Router component") .expect("Cannot call use_route outside the scope of a Router component")
}) })

View file

@ -16,7 +16,7 @@ use dioxus_core::*;
/// The closure will panic if the provided script is not valid JavaScript code /// The closure will panic if the provided script is not valid JavaScript code
/// or if it returns an uncaught error. /// or if it returns an uncaught error.
pub fn use_eval<S: std::string::ToString>(cx: &ScopeState) -> &dyn Fn(S) { pub fn use_eval<S: std::string::ToString>(cx: &ScopeState) -> &dyn Fn(S) {
cx.use_hook(|_| { cx.use_hook(|| {
|script: S| { |script: S| {
js_sys::Function::new_no_args(&script.to_string()) js_sys::Function::new_no_args(&script.to_string())
.call0(&wasm_bindgen::JsValue::NULL) .call0(&wasm_bindgen::JsValue::NULL)