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

Introduces the ability to make objects and array changes reactive by "tracking" them #12

Merged
merged 14 commits into from
Nov 21, 2024
22 changes: 22 additions & 0 deletions README.md
cesarParra marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,28 @@ export const counterPlusTwo = $computed(() => counterPlusOne.value + 1);

Because `$computed` values return a signal, you can use them as you would use any other signal.

## Tracking objects and arrays

By default, for a signal to be reactive it needs to be reassigned. This can be cumbersome when dealing with objects
and arrays, as you would need to reassign the whole object or array to trigger the reactivity.

To improve that experience, you can set the `track` flag to true when creating the signal. This will make the signal
reactive to changes in the object or array properties.

> 📒 Think about this as using the `@track` decorator in LWC properties. It works the exact same way behind the scenes.

```javascript
import { $signal } from "c/signals";

const obj = $signal({ x: 1, y: 2 }, { track: true });
const computedFromObj = $computed(() => obj.value.x + obj.value.y);

// When a value in the object changes, the computed value will automatically update
obj.value.x = 2;

console.log(computedFromObj.value); // 4
```

## Reacting to multiple signals

You can also use multiple signals in a single `computed` and react to changes in any of them.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
<div>Contact Name: {contactInfo.contactName}</div>
</div>
</div>
</template>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ export default class BusinessCard extends LightningElement {
contactName: contactName.value
})
).value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
<target>lightningCommunity__Default</target>
<target>lightningCommunity__Page</target>
</targets>
</LightningComponentBundle>
</LightningComponentBundle>
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@
value={contactName}
onchange={handleContactNameChange}
></lightning-input>
</template>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ export default class ContactInfoForm extends LightningElement {
handleContactNameChange(event) {
contactName.value = event.target.value;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
<target>lightningCommunity__Default</target>
<target>lightningCommunity__Page</target>
</targets>
</LightningComponentBundle>
</LightningComponentBundle>
2 changes: 1 addition & 1 deletion examples/counter/lwc/countChanger/countChanger.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
<button onclick={decrementCount}>Decrement</button>
<button onclick={incrementCount}>Increment</button>
</div>
</template>
</template>
2 changes: 1 addition & 1 deletion examples/counter/lwc/countChanger/countChanger.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ export default class CountChanger extends LightningElement {
decrementCount() {
counter.value--;
}
}
}
2 changes: 1 addition & 1 deletion examples/counter/lwc/countTracker/countTracker.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<template>
The current count is ($computed reactive property): {reactiveProperty} <br />
The counter plus two value is (nested computed): {counterPlusTwo}
</template>
</template>
2 changes: 1 addition & 1 deletion examples/counter/lwc/countTracker/countTracker.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ export default class CountTracker extends LightningElement {

counterPlusTwo = $computed(() => (this.counterPlusTwo = counterPlusTwo.value))
.value;
}
}
2 changes: 1 addition & 1 deletion examples/demo-signals/lwc/demoSignals/contact-info.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ import { $signal } from "c/signals";

export const accountName = $signal("ACME");

export const contactName = $signal("John Doe");
export const contactName = $signal("John Doe");
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
<description>Demo Signals</description>
<isExposed>false</isExposed>
<masterLabel>Demo Signals</masterLabel>
</LightningComponentBundle>
</LightningComponentBundle>
9 changes: 6 additions & 3 deletions examples/demo-signals/lwc/demoSignals/shopping-cart.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,17 @@ import updateShoppingCart from "@salesforce/apex/ShoppingCartController.updateSh
*/

// Store each state change in the cart history
export const cartHistory = $signal([]);
export const cartHistory = $signal([], { track: true });
$effect(() => {
console.log("cartHistory", JSON.stringify(cartHistory.value, null, 2));
});
let isUndoing = false;

export const undoCartChange = () => {
isUndoing = true;
const lastState = cartHistory.value[cartHistory.value.length - 1];
// Remove the last state from the history
cartHistory.value = cartHistory.value.slice(0, -1);
cartHistory.value.splice(-1, 1);
if (lastState) {
updateCart(lastState);
}
Expand Down Expand Up @@ -55,7 +58,7 @@ async function updateCartOnTheServer(newCart, previousValue, mutate) {

// Store the previous value in the history
if (shouldUpdateHistory) {
cartHistory.value = [...cartHistory.value, previousValue];
cartHistory.value.push(previousValue);
}
} catch (error) {
mutate(null, error);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" ?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>60.0</apiVersion>
<status>Active</status>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
<div>
<h1>Selected Account</h1>
<template if:true={account.loading}>
<lightning-spinner alternative-text="Loading" size="large"></lightning-spinner>
<lightning-spinner
alternative-text="Loading"
size="large"
></lightning-spinner>
</template>

<template if:false={account.loading}>
Expand All @@ -14,4 +17,4 @@ <h1>Selected Account</h1>
</template>
</template>
</div>
</template>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ import { getAccount } from "c/demoSignals";

export default class DisplaySelectedAccount extends LightningElement {
account = $computed(() => (this.account = getAccount.value)).value;
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" ?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>60.0</apiVersion>
<description>Display Selected Account</description>
Expand All @@ -8,4 +8,4 @@
<target>lightningCommunity__Default</target>
<target>lightningCommunity__Page</target>
</targets>
</LightningComponentBundle>
</LightningComponentBundle>
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
options={accounts}
onchange={handleAccountChange}
></lightning-select>
</template>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ export default class ListAccounts extends LightningElement {
handleAccountChange(event) {
selectedAccountId.value = event.detail.value;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" ?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>60.0</apiVersion>
<description>List Accounts</description>
Expand All @@ -8,4 +8,4 @@
<target>lightningCommunity__Default</target>
<target>lightningCommunity__Page</target>
</targets>
</LightningComponentBundle>
</LightningComponentBundle>
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
<!-- Server Fetcher -->
<template>
<template if:true={contacts.loading}>
Loading
</template>
<template if:true={contacts.loading}> Loading </template>
<template if:false={contacts.loading}>
<template for:each={contacts.data} for:item="contact">
<div key={contact.Id}>
<p>{contact.Name}</p>
</div>
</template>
</template>
</template>
</template>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" ?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>60.0</apiVersion>
<description>Server Fetcher</description>
Expand All @@ -8,4 +8,4 @@
<target>lightningCommunity__Default</target>
<target>lightningCommunity__Page</target>
</targets>
</LightningComponentBundle>
</LightningComponentBundle>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" ?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>60.0</apiVersion>
<status>Active</status>
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<template></template>
<template></template>
14 changes: 10 additions & 4 deletions examples/shopping-cart/lwc/checkoutButton/checkoutButton.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import TwElement from "c/twElement";
import {$computed} from 'c/signals';
import {shoppingCart} from "c/demoSignals";
import { $computed, $effect } from "c/signals";
import { shoppingCart } from "c/demoSignals";

// States
import ready from "./states/ready.html";
import loading from "./states/loading.html";

export default class CheckoutButton extends TwElement {
itemData = $computed(() => this.itemData = shoppingCart.value).value;
itemData = shoppingCart.value;

connectedCallback() {
$effect(() => {
this.itemData = shoppingCart.value;
});
}

render() {
return this.itemData.loading ? loading : ready;
Expand All @@ -16,4 +22,4 @@ export default class CheckoutButton extends TwElement {
get isEmpty() {
return this.itemData.data.items.length === 0;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" ?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>60.0</apiVersion>
<description>Checkout Button</description>
Expand All @@ -8,4 +8,4 @@
<target>lightningCommunity__Default</target>
<target>lightningCommunity__Page</target>
</targets>
</LightningComponentBundle>
</LightningComponentBundle>
8 changes: 4 additions & 4 deletions examples/shopping-cart/lwc/checkoutButton/states/loading.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div class="mx-auto max-w-4xl pb-16">
<c-stencil height="50"></c-stencil>
</div>
</template>
<div class="mx-auto max-w-4xl pb-16">
<c-stencil height="50"></c-stencil>
</div>
</template>
41 changes: 20 additions & 21 deletions examples/shopping-cart/lwc/checkoutButton/states/ready.html
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
<template>
<div class="mx-auto max-w-4xl pb-16">
<div class="mt-10">
<button type="submit"
disabled={isEmpty}
class="w-full rounded-md border border-transparent bg-indigo-600 px-4 py-3
text-base font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none
focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 focus:ring-offset-gray-50
disabled:opacity-50 disabled:cursor-not-allowed">
Checkout
</button>
</div>
<div class="mx-auto max-w-4xl pb-16">
<div class="mt-10">
<button
type="submit"
disabled={isEmpty}
class="w-full rounded-md border border-transparent bg-indigo-600 px-4 py-3 text-base font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 focus:ring-offset-gray-50 disabled:opacity-50 disabled:cursor-not-allowed"
>
Checkout
</button>
</div>

<div class="mt-6 text-center text-sm text-gray-500">
<p>
or &nbsp;
<a href="#" class="font-medium text-indigo-600 hover:text-indigo-500">
Continue Shopping
<span aria-hidden="true"> &rarr;</span>
</a>
</p>
</div>
<div class="mt-6 text-center text-sm text-gray-500">
<p>
or &nbsp;
<a href="#" class="font-medium text-indigo-600 hover:text-indigo-500">
Continue Shopping
<span aria-hidden="true"> &rarr;</span>
</a>
</p>
</div>
</template>
</div>
</template>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" ?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>60.0</apiVersion>
<description>Shopping Cart Details</description>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<!-- loading -->
<template>
<div class="mx-auto max-w-4xl px-4 items-center justify-center flex">
<c-stencil height="419" width="864"></c-stencil>
</div>
<div class="mx-auto max-w-4xl px-4 items-center justify-center flex">
<c-stencil height="419" width="864"></c-stencil>
</div>
</template>
Loading
Loading