v0.5.0-rc1
Pre-releaseI'm planning on releasing 0.5.0 proper toward the end of this week. However, we've continued having some really good new features and some changes, so I want to give it some additional time for testing rather than rushing and breaking things.
For overall 0.5.0 changes, see here.
New Features in this Release
attr: on components, and spreading attributes
Makes it much easier to pass some set of attributes to be given to a component (with attr: passed into a #[prop(attrs)] prop), and then to spread them onto an element with {..attrs} syntax.
#[component]
pub fn App() -> impl IntoView {
    view! {
        <Input attr:value="hello" attr:label="foo" />
        <Input attr:type="number" attr:value="0" />
    }
}
#[component]
pub fn Input(
    #[prop(attrs)] attrs: Vec<(&'static str, Attribute)>,
) -> impl IntoView {
    view! {
        <input {..attrs} />
        <pre>{format!("{attrs2:#?}")}</pre>
    }
}Generics on components in view
Newly added support for syntax that identifies a generic type for a component in the view
#[component]
pub fn GenericComponent<S>(#[prop(optional)] ty: PhantomData<S>) -> impl IntoView {
    std::any::type_name::<S>()
}
#[component]
pub fn App() -> impl IntoView {
    view! {
        <GenericComponent<String>/>
        <GenericComponent<usize>/>
        <GenericComponent<i32>/>
    }
}Callback types
These make it easier to add things like optional callback functions to components.
#[component]
pub fn App() -> impl IntoView {
    view! {
        <ShowOptFall when=|| { 5 < 3 } fallback=|_| view! { <p>"YES"</p> }>
            <p>"NO"</p>
        </ShowOptFall>
        <ShowOptFall when=|| { 5 < 3 }>
            <p>"NO"</p>
        </ShowOptFall>
        <ShowOptFall when=||{ 5 > 3 }>
            <p>"YES"</p>
        </ShowOptFall>
    }
}
#[component]
pub fn ShowOptFall<W>(
    /// The components Show wraps
    children: Box<dyn Fn() -> Fragment>,
    /// A closure that returns a bool that determines whether this thing runs
    when: W,
    /// A closure that returns what gets rendered if the when statement is false
    #[prop(optional, into)]
    fallback: Option<ViewCallback<()>>,
) -> impl IntoView
where
    W: Fn() -> bool + 'static,
{
    let memoized_when = create_memo(move |_| when());
    move || match memoized_when.get() {
        true => children().into_view(),
        false => match fallback.as_ref() {
            Some(fallback) => fallback.call(()).into_view(),
            None => ().into_view(),
        },
    }
}with!() and update!() macros
Nested .withI() calls are a pain. Now you can do
let (first, _) = create_signal("Bob".to_string());
let (middle, _) = create_signal("J.".to_string());
let (last, _) = create_signal("Smith".to_string());
let name = move || with!(|first, middle, last| format!("{first} {middle} {last}"));instead of
let name = move || {
	first.with(|first| {
		middle.with(|middle| last.with(|last| format!("{first} {middle} {last}")))
	})
};Rustier interfaces for signal types
This framework's origins as a Rust port of SolidJS mean we've inherited some functional-JS-isms. Combined with the need to pass cx everywhere prior to 0.5 this has tended to mean we've gone with create_ and so on rather than Rusty ::new(). This simply adds a few Rustier constructors like
let count = RwSignal::new(0);
let double_count = Memo::new(move |_| count() * 2);Breaking Changes
- Renaming .derived_signal()and.mapped_signal_setter()to the more idiomatic.into_signal()and.into_signal_setter()
- Memoizing whether Suspenseis ready yet or not in order to avoid over-re-rendering. Shouldn't break your app, but if something weird happens let me know.
- Changes timing of create_effectso that it runs a tick after it is created, which solves a number of timing issues with effects that had previously led tocreate_effect(move || request_animation_frame(move || /* */))
What's Changed
- doc(examples): add fantoccini to test-runner-report (#1615) by @agilarity in #1616
- docs: Derived signals - Clarified derived signals by @martinfrances107 in #1614
- doc(book,deployment): update reference to binary in dockerfile by @SadraMoh in #1617
- docs: fix typo by @dpytaylo in #1618
- docs: remove extra space by @Lawqup in #1622
- docs(book): fix wrong variable name by @Gaareth in #1623
- feat: Callback proposal by @rambip in #1596
- Configuration for Hot-Reloading Websocket Protocol and enable ENV PROD selection by @Indrazar in #1613
- feat: implement simple spread attributes by @mrvillage in #1619
- fix: memoize Suspense readiness to avoid rerendering children/fallback by @gbj in #1642
- feat: add component generics by @mrvillage in #1636
- hide get_propertyby @jquesada2016 in #1638
- Into thing boxed by @jquesada2016 in #1639
- docs: cleanup by @Banzobotic in #1626
- fix: versioned resources never decrement Suspense (closes #1640) by @gbj in #1641
- Rename into signal traits by @jquesada2016 in #1637
- feat: start adding some Rustier interfaces for reactive types by @gbj in #1579
- test(error_boundary): add e2e testing by @agilarity in #1651
- fix: custom events on components by @liquidnya in #1648
- fix: compare path components to detect active link in router by @flo-at in #1656
- Tailwind example update by @SleeplessOne1917 in #1625
- refactor(examples): extract client process tasks (#1665) by @agilarity in #1666
- change: move logging macros into a loggingmodule to avoid name conflicts withlogandtracingby @gbj in #1658
- Router version bump by @martinfrances107 in #1673
- Chore: Bump to actions/checkout@v4 by @martinfrances107 in #1672
- Rcbacked- ChildrenFnby @Baptistemontan in #1669
- Remove (most) syn 1 dependencies by @blorbb in #1670
- chore: Removed resolver link warning. by @martinfrances107 in #1677
- examples: add note about potential for memory leaks with nested signals by @gbj in #1675
- feat: islands by @gbj in #1660
- Docs: a bunch of small improvements by @gbj in #1681
- Chore: Remove ambiguity surrounding version numbers. by @martinfrances107 in #1685
- fix: restore deleted extract_with_statefunction by @gbj in #1683
- fix: broken mount_to_bodyin CSR mode by @gbj in #1688
- Chore: cleared "cargo doc" issue. by @martinfrances107 in #1687
- Update interlude_projecting_children.md by @mjarvis9541 in #1690
- feat: Add dynamically resolved attributes by @mrvillage in #1628
- docs: add docs for #[island]macro by @gbj in #1691
- change: run effects after a tick by @gbj in #1680
- feat: with! macros by @blorbb in #1693
New Contributors
- @mrnossiom made their first contribution in #1532
- @lker-dev made their first contribution in #1557
- @Senzaki made their first contribution in #1564
- @flisky made their first contribution in #1571
- @rkuklik made their first contribution in #1444
- @rabidpug made their first contribution in #1548
- @Maneren made their first contribution in #1612
- @drdo made their first contribution in #1597
- @JonRCahill made their first contribution in #1604
- @realeinherjar made their first contribution in #1610
- @SadraMoh made their first contribution in #1617
- @dpytaylo made their first contribution in #1618
- @Lawqup made their first contribution in #1622
- @Gaareth made their first contribution in #1623
- @rambip made their first contribution in #1596
- @mrvillage made their first contribution in #1619
- @Banzobotic made their first contribution in #1626
- @liquidnya made their first contribution in #1648
- @flo-at made their first contribution in #1656
- @Baptistemontan made their first contribution in #1669
- @blorbb made their first contribution in #1670
- @mjarvis9541 made their first contribution in #1690
Full Changelog: v0.5.0-beta...v0.5.0-rc1