Child Components

Asteracea components can be used inside other templates using asterisk syntax:

#![allow(unused)]
fn main() {
//TODO: Hide this initially.
use std::marker::PhantomData;

asteracea::component! {
  Inner()()

  "Inner body."
}

mod module {
  asteracea::component! {
    pub(crate) Module()()

    "Module body."
  }
}

asteracea::component! {
  Generic<T>(
    //TODO: Hide this initially and show an ellipsis comment.
    // Generic parameters must be used in an instance field.
    // We can pretend this is the case using a constructor parameter capture.
    // `PhantomData` is a type that provides fake storage semantics.
    priv _phantom: PhantomData<T> = PhantomData::default(),
  )()

  "Generic body."
}

asteracea::component! {
  Outer()()

  [
    <*Inner> "\n"
    <*module::Module> "\n"
    <*Generic::<()>> // Mind the turbofish! ::<> 🐟💨
  ]
}
}
Inner body.
Module body.
Generic body.

Explicit closing is supported:

#![allow(unused)]
fn main() {
//TODO: Hide repetition.
use std::marker::PhantomData;

asteracea::component! {
  Inner()()

  "Inner body."
}

mod module {
  asteracea::component! {
    pub(crate) Module()()

    "Module body."
  }
}

asteracea::component! {
  Generic<T>(
    // Generic parameters must be used in an instance field.
    // We can pretend this is the case using a constructor parameter capture.
    // `PhantomData` is a type that provides fake storage semantics.
    priv _phantom: PhantomData<T> = PhantomData::default(),
  )()

  "Generic body."
}

asteracea::component! {
  Outer()()

  [
    <*Inner /Inner> "\n"
    <*module::Module /Module> "\n"
    <*Generic::<()> /Generic> // 🪣
  ]
}
}
Inner body.
Module body.
Generic body.

Using a component multiple times results in distinct instances:

#![allow(unused)]
fn main() {
asteracea::component! {
  Inner()()
  "Inner body."
}

asteracea::component! {
  Outer()()
  [
    <*Inner>
    <*Inner>
  ]
}
}
Inner body.Inner body.

Child Component Instancing

Note: Rust is good at erasing empty instances!

If your reused component is stateless, please restate the component's type name instead of using instancing. This will keep your code clearer and less interdependent.

For more information, see The Rustonomicon on Zero Sized Types (ZSTs).

Instead of instantiating and storing a child component multiple times, you can instance it by giving it a name and referencing it elsewhere through a Rust block:

#![allow(unused)]
fn main() {
//TODO: Hide this initially.
asteracea::component! {
  Inner()()
  "Inner body."
}

asteracea::component! {
  Outer()()
  [
    <*Inner priv inner> // Alternatively: `pub` or `pub(…)`
    <*{self.inner_pinned()}>
  ]
}
}
Inner body.Inner body.

The component's .render(…) method is called for each of these appearances, but ::new(…) is called only once.

Component instancing is especially useful when rendering alternates, since the child instance is available everywhere in the parent component's body (regardless which .render(…) path is taken).