I'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
Suspense
is 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_effect
so 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_property
by @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
logging
module to avoid name conflicts withlog
andtracing
by @gbj in #1658 - Router version bump by @martinfrances107 in #1673
- Chore: Bump to actions/checkout@v4 by @martinfrances107 in #1672
Rc
backedChildrenFn
by @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_state
function by @gbj in #1683 - fix: broken
mount_to_body
in 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