Skip to content

Commit

Permalink
fix: distinct is true by default
Browse files Browse the repository at this point in the history
  • Loading branch information
petyosi committed Dec 25, 2023
1 parent de0f9c2 commit 7eaae86
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 27 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Welcome to the README of Gurx, an extensible typescript-native reactive state ma

- **Open** - the node definition based approach lets you extend the logic of the state management by connecting more nodes and interactions to the existing ones. This lets you partition your state management logic into smaller, more manageable pieces and even build a plugin system on top of it.

- **Optimized** - any Gurx node can be marked as distinct, meaning that it will push through its subscribers only when a new value arrives. This allows you to avoid expensive computations and re-renders.
- **Optimized** - any Gurx node are marked as distinct by default, meaning that it will push through its subscribers only when a value different than the previous one is published. This allows you to avoid expensive computations and re-renders.

- **Multi publish/subscribe** - you can subscribe to multiple nodes at once, and you can publish to multiple nodes at once. A multi-push will execute a single traversal of the node graph, and will re-render the components only once, given that they are subscribed through a single point.

Expand Down Expand Up @@ -48,28 +48,28 @@ Note: You can name the node references with a dollar sign suffix, to indicate th
const myCell$ = Cell(
// initial value
0,
// distinct flag
true,
// the r is the realm instance that starts the cell
(r) => {
r.sub(myCell$, (value) => {
console.log('myCell$ changed to', value)
})
}
// distinct flag, true by default
true
)

// Since signals have no initial value, you need to specify the type of data that will flow through them
const mySignal$ = Signal<number>(
// distinct flag
true,
// the r is the realm instance that starts the cell
(r) => {
r.sub(mySignal$, (value) => {
console.log('mySignal$ changed to', value)
})
// publishing a value through a signal will publish it into $myCell as well
r.link(mySignal$, myCell$)
}
},
// distinct flag
true
)
```

Expand Down
4 changes: 2 additions & 2 deletions src/examples.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Action, Cell, RealmProvider, useCellValue, useCellValues, usePublisher } from '.'

const foo$ = Cell('foo', true)
const bar$ = Cell('bar', true)
const foo$ = Cell('foo')
const bar$ = Cell('bar')

const q$ = Action((r) => {
r.sub(q$, () => {
Expand Down
4 changes: 2 additions & 2 deletions src/readme.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { map, Signal, Cell, RealmProvider, useCellValue, usePublisher } from '.'

// Create a cell with an initial value
const cell$ = Cell('foo', true)
const cell$ = Cell('foo')

// A signal, that will update the cell when its value changes
const signal$ = Signal<number>(true, (r) => {
const signal$ = Signal<number>((r) => {
r.link(
r.pipe(
signal$,
Expand Down
22 changes: 13 additions & 9 deletions src/realm.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ describe('gurx cells/signals', () => {

it('supports init function for cells', () => {
const a = Cell(2)
const b = Cell(2, true, (r) => {
const b = Cell(2, (r) => {
r.link(b, a)
})
r.pub(b, 3)
Expand All @@ -51,7 +51,7 @@ describe('gurx cells/signals', () => {

it('supports init function for signals', () => {
const a = Cell(2)
const b = Signal(true, (r) => {
const b = Signal((r) => {
r.link(b, a)
})
r.pub(b, 3)
Expand Down Expand Up @@ -92,9 +92,9 @@ describe('realm features', () => {
})

it('supports undefined initial value', () => {
const n = Cell<string | undefined>(undefined, true)
const q = Cell(1, true)
const tc = Cell<number>(0, true)
const n = Cell<string | undefined>(undefined)
const q = Cell(1)
const tc = Cell<number>(0)
r.link(
r.pipe(
r.combine(n, q),
Expand Down Expand Up @@ -411,7 +411,7 @@ describe('realm features', () => {
})

it('does not recall subscriptions for distinct stateful nodes', () => {
const a = Cell('foo', true)
const a = Cell('foo')
const spy = vi.fn()
r.sub(a, spy)
r.pub(a, 'foo')
Expand All @@ -421,7 +421,7 @@ describe('realm features', () => {

it('does not recall subscriptions for distinct stateful child nodes', () => {
const a = Cell('bar')
const b = Cell('foo', true)
const b = Cell('foo')
const spy = vi.fn()
r.connect({
map: (value) => value,
Expand All @@ -436,7 +436,11 @@ describe('realm features', () => {
})

it('supports custom comparator when distinct flag is set', () => {
const a = Cell({ id: 'foo' }, (current, next) => (current !== undefined ? current.id === next.id : false))
const a = Cell(
{ id: 'foo' },
() => {},
(current, next) => (current !== undefined ? current.id === next.id : false)
)
const spy = vi.fn()
r.sub(a, spy)
r.pub(a, { id: 'foo' })
Expand All @@ -446,7 +450,7 @@ describe('realm features', () => {

it('supports subscribing to multiple nodes', () => {
const a = Cell('bar')
const b = Cell('foo', true)
const b = Cell('foo')
const spy = vi.fn()
r.connect({
map: (value) => value,
Expand Down
16 changes: 8 additions & 8 deletions src/realm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,10 @@ export class Realm {
* Creates or resolves an existing cell instance in the realm. Useful as a joint point when building your own operators.
* @returns a reference to the cell.
* @param value - the initial value of the cell
* @param distinct - false by default. Pass true to mark the cell as a distinct one, or a custom comparator in case of a non-primitive value.
* @param distinct - true by default. Pass false to mark the signal as a non-distinct one, meaning that publishing the same value multiple times will re-trigger a recomputation cycle.
* @param node - optional, a reference to a cell. If the cell has not been touched in the realm before, the realm will instantiate a reference to it. If it's registered already, the function will return the reference.
*/
cellInstance<T>(value: T, distinct: Distinct<T> = false, node = Symbol()): NodeRef<T> {
cellInstance<T>(value: T, distinct: Distinct<T> = true, node = Symbol()): NodeRef<T> {
if (!this.state.has(node)) {
this.state.set(node, value)
if (distinct !== false) {
Expand All @@ -128,10 +128,10 @@ export class Realm {
/**
* Creates or resolves an existing signal instance in the realm. Useful as a joint point when building your own operators.
* @returns a reference to the signal.
* @param distinct - false by default. Pass true to mark the signal as a distinct one, or a custom comparator in case of a non-primitive value.
* @param distinct - true by default. Pass false to mark the signal as a non-distinct one, meaning that publishing the same value multiple times will re-trigger a recomputation cycle.
* @param node - optional, a reference to a signal. If the signal has not been touched in the realm before, the realm will instantiate a reference to it. If it's registered already, the function will return the reference.
*/
signalInstance<T>(distinct: Distinct<T> = false, node = Symbol()): NodeRef<T> {
signalInstance<T>(distinct: Distinct<T> = true, node = Symbol()): NodeRef<T> {
if (distinct !== false) {
this.distinctNodes.set(node, distinct === true ? defaultComparator : (distinct as Comparator<unknown>))
}
Expand Down Expand Up @@ -671,8 +671,8 @@ export class Realm {
* Defines a new **stateful node** and returns a reference to it.
* Once a realm instance publishes or subscribes to the node, an instance of that node it will be registered in the realm.
* @param value - the initial value of the node. Stateful nodes always have a value.
* @param distinct - if true, the node will only emit values that are different from the previous value. Optionally, a custom distinct function can be provided if the node values are non-primitive.
* @param init - an optional function that will be called when the node is registered in a realm. Can be used to create subscriptions and define relationships to other nodes. Any referred nodes will be registered in the realm automatically.
* @param distinct - if true, the node will only emit values that are different from the previous value. Optionally, a custom distinct function can be provided if the node values are non-primitive.
* @example
* ```ts
* const foo$ = Cell('foo', true, (r) => {
Expand All @@ -685,7 +685,7 @@ export class Realm {
* If you need to get the current value of a stateful node, use {@link Realm.getValue}.
* @category Nodes
*/
export function Cell<T>(value: T, distinct: Distinct<T> = false, init: (r: Realm) => void = noop): NodeRef<T> {
export function Cell<T>(value: T, init: (r: Realm) => void = noop, distinct: Distinct<T> = true): NodeRef<T> {
return tap(Symbol(), (id) => {
nodeDefs$$.set(id, { type: 'cell', distinct, initial: value, init })
}) as NodeRef<T>
Expand All @@ -694,8 +694,8 @@ export function Cell<T>(value: T, distinct: Distinct<T> = false, init: (r: Realm
/**
* Defines a new **stateless node** and returns a reference to it.
* Once a realm instance publishes or subscribes to the node, an instance of that node it will be registered in the realm.
* @param distinct - if true, the node will only emit values that are different from the previous value. Optionally, a custom distinct function can be provided if the node values are non-primitive.
* @param init - an optional function that will be called when the node is registered in a realm. Can be used to create subscriptions and define relationships to other nodes. Any referred nodes will be registered in the realm automatically.
* @param distinct - true by default. The node emits values that are different from the previous value. Optionally, a custom distinct function can be provided if the node values are non-primitive.
* @example
* ```ts
* const foo$ = Signal<string>(true, (r) => {
Expand All @@ -706,7 +706,7 @@ export function Cell<T>(value: T, distinct: Distinct<T> = false, init: (r: Realm
* ```
* @category Nodes
*/
export function Signal<T>(distinct: Distinct<T> = false, init: NodeInit<T> = noop): NodeRef<T> {
export function Signal<T>(init: NodeInit<T> = noop, distinct: Distinct<T> = false): NodeRef<T> {
return tap(Symbol(), (id) => {
nodeDefs$$.set(id, { type: 'signal', distinct, init })
}) as NodeRef<T>
Expand Down

0 comments on commit 7eaae86

Please sign in to comment.