Module intuitive::render::hooks

source ·
Expand description

Enables state-like features in functional components.

Hooks

Hooks enable state-like behavior in otherwise functional components. They are heavily inspired by React’s hooks.

The main hooks are:

Using Hooks

Hooks are implemented as traits on the Hooks provider, which has a primitive use_hook hook.

In order to use hooks:

  1. Import the hook’s trait
  2. Call the function on the Hooks provider.
    • This is implictly introduced into scope as hooks when using the #[component(..)] attribute macro. (See the hooks section of the attribute macro’s documentation).

For instance, an example usage of the UseState and UseEffect hooks,

use std::{thread, time::Duration};

use intuitive::{
  component,
  components::{Section, Text},
  element::Any as AnyElement,
  render,
  render::hooks::{UseEffect, UseState},
  style::Color,
};

#[component(Root)]
fn render() -> AnyElement {
  let seconds = hooks.use_state(|| 0);

  // cloned because it's moved into the `use_effect` hook below
  let seconds_clone = seconds.clone();

  hooks.use_effect(|| {
    thread::spawn(move || loop {
      thread::sleep(Duration::from_secs(1));

      seconds_clone.update(|seconds| seconds + 1).unwrap();
    });
  });

  render! {
    Section(title: "Seconds", border: Color::Red) {
      Text(text: format!("This program has run for {} seconds", seconds.get()))
    }
  }
}

Writing Custom Hooks

Custom hooks are, like the built-in hooks, implemented as traits on the Hooks context provider. For example, a possible implementation of the UseEffect hook (without cleanup support, but with dependencies) could be:

pub trait UseEffect {
  fn use_effect<D, F>(&mut self, deps: D, func: F)
  where
    D: 'static + Eq,
    F: FnOnce();
}

impl UseEffect for Hooks {
  fn use_effect<D, F>(&mut self, deps: D, func: F)
  where
    D: 'static + Eq,
    F: FnOnce(),
  {
    self.use_memo(deps, func);
  }
}

Now, when UseEffect is imported, UseEffect::use_effect can be called as a method on Hooks.

Custom hooks can also rely on Hooks::use_hook. This is the “primitive” hook that all other hooks must eventually use in order to hook into the component rendering lifecycle. This is the only hook that is not implemented as a trait, and is therefore always available.

Modules

Structs

Optional function to run as a cleanup for UseEffect or UseEffectWithDeps.
A dynamically-typed hook return value, along with a deinitialization function for unmounting.
A container for a T which causes re-renders when mutated, returned by UseState::use_state.

Traits

A hook to execute a function once within a component.
A hook to execute a function any time its dependencies changes within a component.
A hook to avoid recomputing an expensive function.
A hook to add state to a component.