Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reactivity v3! (Part 1) 🎉 #612

Merged
merged 43 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
98f010b
scopes
lukechu10 May 8, 2023
1a7ac42
signal get and set
lukechu10 May 8, 2023
49de48b
signals owned by scopes
lukechu10 May 8, 2023
eced3b7
memos and reactive graph update propagation
lukechu10 May 9, 2023
905e7d6
improve performance by reusing allocations in topo_sort
lukechu10 May 9, 2023
3bb62ef
add remaining reactive hooks
lukechu10 May 10, 2023
0ea7874
add some docs and reexport everything at top-level
lukechu10 May 10, 2023
c9cc6bc
add a lot more docs
lukechu10 May 10, 2023
731a069
add docs to everything and impl Debug, Display
lukechu10 May 10, 2023
645c517
add context api
lukechu10 May 10, 2023
2035fc2
migrate signal and memo tests over
lukechu10 May 10, 2023
81da2d5
separate effects from memos and defer effect callbacks
lukechu10 May 12, 2023
8a55ee6
migrate all effect tests
lukechu10 May 12, 2023
b699bad
check if effect is alive when calling it rather than removing links d…
lukechu10 May 12, 2023
cd00ef0
fix a few memo tests migrated from effects
lukechu10 May 12, 2023
0f07982
some perf optimizations around slotmap indexing
lukechu10 May 12, 2023
6f3510b
migrate over map_keyed and map_indexed
lukechu10 May 12, 2023
17c41f6
remove unnecessary Rc
lukechu10 May 12, 2023
bbc522b
make Accessor take ref instead of move
lukechu10 May 12, 2023
274ef5f
Merge branch 'master' into reactivity-v3
lukechu10 May 16, 2023
d2a8a16
add effect batching
lukechu10 May 16, 2023
b299fe9
Update some docs to new reactivity
lukechu10 May 16, 2023
1a6adc2
initial store API implementation
lukechu10 May 16, 2023
701d590
wip: add derive macro for State and macro for parsing lens path
lukechu10 Sep 6, 2023
49449f3
add StateTrigger trait and make get! take a Store<T>
lukechu10 Sep 6, 2023
30a9826
Implement set! macro.
lukechu10 Sep 7, 2023
e0a4273
fix doc comment
lukechu10 Sep 9, 2023
e3f69bd
Rename store2.rs to store.rs
lukechu10 Sep 9, 2023
c958edb
Merge remote-tracking branch 'upstream/master' into reactivity-v3
lukechu10 Sep 11, 2023
a07e2ed
Satisfy clippy
lukechu10 Sep 11, 2023
dea73d6
Split scope into a new file
lukechu10 Sep 14, 2023
362f1d1
Move tests into scope.rs as well
lukechu10 Sep 14, 2023
fc2eaa8
Remove explicit cx: Scope
lukechu10 Sep 14, 2023
69110ef
Set global root when propagating updates
lukechu10 Sep 14, 2023
825a9e3
Simplify Root internals
lukechu10 Sep 14, 2023
f4ac89c
Fix CI?
lukechu10 Sep 14, 2023
551da78
Update Cargo.toml for new crates
lukechu10 Sep 14, 2023
b04cca4
Fix RUSTFLAGS
lukechu10 Sep 14, 2023
3043afa
Fix RUSTFLAGS attempt 2
lukechu10 Sep 14, 2023
e9bed68
Fix conditional compilation
lukechu10 Sep 14, 2023
675a252
Remove examples folder from sycamore-reactive3
lukechu10 Sep 14, 2023
119f91d
Do not run all tests
lukechu10 Sep 14, 2023
8ebbeab
Ignore doctest in lib.rs
lukechu10 Sep 14, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build_website.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
- name: Install trunk
run: >
wget -qO-
https://github.com/thedodd/trunk/releases/download/v0.14.0/trunk-x86_64-unknown-linux-gnu.tar.gz
https://github.com/thedodd/trunk/releases/download/v0.16.0/trunk-x86_64-unknown-linux-gnu.tar.gz
| tar -xzf- && sudo mv trunk /usr/bin/

- name: Cargo generate-lockfile
Expand Down
18 changes: 11 additions & 7 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,23 +48,27 @@ jobs:
target/
key: ${{ runner.os }}-cargo-${{ matrix.rust }}-${{ hashFiles('**/Cargo.lock') }}

- name: Run tests with default features
- name: Run tests for packages/sycamore with default features
# Only run tests for sycamore to prevent stray feature flags from other tests.
run: cd packages/sycamore && cargo test

- name: Run tests with all features
- name: Run tests (with UI tests) on 1.72.0
if: matrix.rust == '1.72.0'
env:
RUN_UI_TESTS: true
run: cargo test --all-features
run: cargo test

- name: Run tests on stable
if: matrix.rust == 'stable'
run: cargo test

- name: Run tests with all features excluding UI
if: matrix.rust != '1.72.0'
- name: Run all tests on nightly
if: matrix.rust == 'nightly'
run: cargo test --all-features

- name: Run headless browser tests
- name: Run headless browser tests on nightly
run: cd packages/sycamore && wasm-pack test --firefox --chrome --headless --all-features
if: always()
if: matrix.rust == 'nightly'

clippy:
name: Clippy
Expand Down
77 changes: 41 additions & 36 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,43 +1,48 @@
[workspace]
resolver = "2"
members = [
# Packages
"packages/sycamore",
"packages/sycamore-core",
"packages/sycamore-futures",
"packages/sycamore-macro",
"packages/sycamore-reactive",
"packages/sycamore-router",
"packages/sycamore-router-macro",
"packages/sycamore-web",
# Packages
"packages/sycamore",
"packages/sycamore-core",
"packages/sycamore-futures",
"packages/sycamore-macro",
"packages/sycamore-reactive",
"packages/sycamore-reactive3",
"packages/sycamore-reactive-macro",
"packages/sycamore-router",
"packages/sycamore-router-macro",
"packages/sycamore-web",

# Examples
"examples/components",
"examples/context",
"examples/counter",
"examples/http-request",
"examples/http-request-builder",
"examples/hydrate",
"examples/iteration",
"examples/js-framework-benchmark",
"examples/hello-builder",
"examples/hello-world",
"examples/higher-order-components",
"examples/motion",
"examples/number-binding",
"examples/ssr",
"examples/svg",
"examples/timer",
"examples/todomvc",
"examples/transitions",
"examples/attributes-passthrough",
"examples/js-snippets",
# Examples
"examples/components",
"examples/context",
"examples/counter",
"examples/http-request",
"examples/http-request-builder",
"examples/hydrate",
"examples/iteration",
"examples/js-framework-benchmark",
"examples/hello-builder",
"examples/hello-world",
"examples/higher-order-components",
"examples/motion",
"examples/number-binding",
"examples/ssr",
"examples/svg",
"examples/timer",
"examples/todomvc",
"examples/transitions",
"examples/attributes-passthrough",
"examples/js-snippets",

# Website
"docs",
"website",
# Website
"docs",
"website",

# Tools
"packages/tools/bench",
"packages/tools/bench-diff",
# Tools
"packages/tools/bench",
"packages/tools/bench-diff",
]

[profile.bench]
debug = true
35 changes: 35 additions & 0 deletions docs/next/advanced/advanced_reactivity.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,38 @@
TODO

Help us out by writing the docs and sending us a PR!

## Batching Updates

Sycamore's fine grained reactivity system updates immediately when a signal changes. This works great
in most cases because only things that depend on that change will actually be rerun. But what if
you need to make changes to two or more related signals?

### The `batch` function

The batch function lets you execute a closure and delay any effects until it completes. This means
you can update multiple related signals and only have their dependent effects run once.

Not only can this improve performance, but can even improve safety in your code since updating
related signals synchronously can cause your effects to run with an unintended state. Batching
the calls means you only ever run your effects when you're done with your mutations. You can think
of batching a little bit like database transactions.

### Example

In this example, we are assigning both names on a button click and this triggers our rendered update
twice. Using batch lets us avoid that.

```rust
let update_names = || {
batch(|| {
first_name.set_fn(|first_name| first_name + "n");
last_name.set_fn(|last_name| last_name + "!");
});
}
create_effect(cx, || {
// This would run twice when `update_names` is called without batching. With batching, it only
// runs once.
format!("{} {}", first_name.get(), last_name.get());
});
```
4 changes: 2 additions & 2 deletions docs/next/basics/control_flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ let visible = create_signal(cx, true);

view! { cx,
div {
(if *visible.get() {
(if visible.get() {
view! { cx, "Now you see me" }
} else {
view! { cx, } // Now you don't
Expand All @@ -32,7 +32,7 @@ let is_empty = create_selector(cx, || !name.get().is_empty());

view! { cx,
h1 {
(if *is_empty.get() {
(if is_empty.get() {
view! { cx, span { (name.get()) } }
} else {
view! { cx, span { "World" } }
Expand Down
17 changes: 6 additions & 11 deletions docs/next/basics/reactivity.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,7 @@ Reactivity is based on reactive primitives. A `Signal` is one such example of a
At it's simplest, a `Signal` is simply a wrapper around a type that can be read and written to and
which can be listened on whenever its wrapped value is mutated.

To create a signal, we use `create_signal(cx, ...)`. Note that the return value of this method is
not actually `Signal` but `&Signal`. The reason for this is because the created signal is allocated
on the reactive scope and therefore has its lifetime tied with the scope. Furthermore, this allows
using Rust's lifetime system to make sure signals are not accessed once its enclosing scope has been
destroyed.

To create a signal, we use `create_signal(cx, ...)`.
Here is an example of creating a signal, accessing it via `.get()`, and modifying it via
`.set(...)`.

Expand All @@ -51,7 +46,7 @@ accomplished like so:

```rust
let state = create_signal(cx, 0);
create_effect(cx, || println!("The state changed. New value: {}", state.get()));
create_effect(cx, move || println!("The state changed. New value: {}", state.get()));
// Prints "The state changed. New value: 0"
// (note that the effect is always executed at least 1 regardless of state changes)

Expand All @@ -75,11 +70,11 @@ In fact, we can easily create a derived state (also know as derive stores) using

```rust
let state = create_signal(cx, 0);
let double = create_memo(cx, || *state.get() * 2);
let double = create_memo(cx, || state.get() * 2);

assert_eq!(*double.get(), 0);
assert_eq!(double.get(), 0);
state.set(1);
assert_eq!(*double.get(), 2);
assert_eq!(double.get(), 2);
```

`create_memo(...)` automatically recomputes the derived value when any of its dependencies change.
Expand Down Expand Up @@ -109,7 +104,7 @@ let state = create_signal(cx, 0);
let text = G::text(String::new() /* placeholder */);
create_effect(cx, move || {
// Update text when `state` changes.
text.update_text(Some(&state.get()));
text.update_text(Some(&state.get(),to_string()));
});
element.append(&text);
element
Expand Down
2 changes: 1 addition & 1 deletion examples/http-request-builder/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,5 @@ fn main() {
console_error_panic_hook::set_once();
console_log::init_with_level(log::Level::Debug).unwrap();

sycamore::render(|cx| App(cx));
sycamore::render(App);
}
19 changes: 19 additions & 0 deletions packages/sycamore-reactive-macro/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "sycamore-reactive-macro"
categories = ["gui", "wasm", "web-programming"]
description = "Reactive primitives for Sycamore"
edition = "2021"
homepage = "https://github.com/sycamore-rs/sycamore"
keywords = ["wasm", "gui", "reactive"]
license = "MIT"
readme = "../../README.md"
repository = "https://github.com/sycamore-rs/sycamore"
version = "0.9.0-beta.1"

[lib]
proc-macro = true

[dependencies]
proc-macro2 = "1.0.60"
syn = "2.0.18"
quote = "1.0.28"
Loading
Loading