Closed lukechu10 closed 1 year ago
Patch coverage: 91.98%
and project coverage change: +4.69%
:tada:
Comparison is base (
ddf95d8
) 62.21% compared to head (8ebbeab
) 66.90%.
:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.
Hey @wingertge, I included the docs you wrote from #601 in this PR and I added you as a co-author. Hopefully you don't mind!
I will be merging this now since there is already quite a significant amount of changes. The remaining work of migrating the rest of the Sycamore code base to use the new reactivity system will be done in a different PR so as to not make this one bigger than necessary.
A brand new implementation of Reactivity!
This gets rid of all the lifetimes introduced in #337 while maintaining the ergonomics of not having to
clone
everything into every closure.Most of the API surface still has the same form, except without the lifetime annotations. A few APIs, however, need to be changed or removed all together, including
create_ref
andprovide_context_ref
. This is because these APIs internally relied on the arena allocator attached to each scope which has been removed completely. Instead, you can just usecreate_signal
andcreate_context
instead.Another API that has been removed completely is
RcSignal
. SinceSignal
s are'static
now, we can just include them directly in whichever state we want without any lifetime woes. However, this comes at the risk of accessing a signal beyond its "runtime-lifetime", i.e., it can still be accessed even after the scope is dropped, causing the app to immediately panic. In practice, however, these situations are rare enough that they justify the added ergonomics of removing lifetimes.One tricky part is when collections are involved with signals. The current design of Sycamore encourages using nested signals for fine-grained updates. This, however, is no longer a good solution with the new reactive primitives. This is because if we
create_signal
and insert the result into, say, aVec
, theSignal
will not be dropped until the enclosingScope
is dropped. Suppose we now want to remove a row from theVec
. TheSignal
, however, will keep on holding onto its data which essentially causes a memory leak.Leptos solves this issue by adding a
.dispose()
method onSignal
s so that you can manually clean up after yourself when you removeSignal
s from aVec
. I believe, however, that this approach is error-prone and boilerplate-y. Instead, I propose introducing a new "Store-API" modeled on SolidJS'screateStore
primitive. This would get rid of the need all together to have nested signals. Instead, everything can be kept inside a normal Rust data-structure wrapped inside aStore
which would keep track of reactive gets and sets with fine-grained updating.Edit:
Upon further consideration, I've decided to remove the explicit reactive scope tracking with
cx: Scope
in favor of implicitly tracking it. This brings the function signature back to the pre-0.8 style of:instead of:
which I believe is much nicer.
Remaining tasks:
Implement the Store API(Part 2?)Root
system should work on the server-side. Introduce aRootPool
?Migrate the entire Sycamore codebase to the new reactive system(Left for another PR)