Skip to content

Commit

Permalink
Add previousValue method
Browse files Browse the repository at this point in the history
  • Loading branch information
zerobias committed Dec 14, 2023
1 parent 9731c2d commit 3350602
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 1 deletion.
4 changes: 3 additions & 1 deletion src/babel-plugin-factories.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"patronum/once",
"patronum/or",
"patronum/pending",
"patronum/previous-value",
"patronum/reset",
"patronum/reshape",
"patronum/snapshot",
Expand Down Expand Up @@ -44,6 +45,7 @@
"once": "once",
"or": "or",
"pending": "pending",
"previousValue": "previous-value",
"reset": "reset",
"reshape": "reshape",
"snapshot": "snapshot",
Expand All @@ -54,4 +56,4 @@
"throttle": "throttle",
"time": "time"
}
}
}
27 changes: 27 additions & 0 deletions src/previous-value/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Node, Store, createStore, launch, step } from 'effector';

export function previousValue<State>(store: Store<State>): Store<State | null>;
export function previousValue<State, Init>(
store: Store<State>,
initialValue: Init,
): Store<State | Init>;
export function previousValue<State, Init = null>(
store: Store<State>,
initialValue: Init | null = null,
) {
const $prevValue = createStore<State | Init | null>(initialValue);
const storeNode: Node = (store as any).graphite;
storeNode.seq.push(
step.compute({
fn(upd, _, stack) {
launch({
target: $prevValue,
params: stack.a,
defer: true,
});
return upd;
},
}),
);
return $prevValue;
}
55 changes: 55 additions & 0 deletions src/previous-value/previous-value.fork.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { allSettled, createEvent, createStore, fork, restore } from 'effector';

import { previousValue } from './index';

it('has null when store is not changed', () => {
const scope = fork();
const $initalStore = createStore(10);
const $prevValue = previousValue($initalStore);

expect(scope.getState($prevValue)).toBe(null);
});

it('has initial value when defined', () => {
const scope = fork();
const $initalStore = createStore(10);
const $prevValue = previousValue($initalStore, 0);

expect(scope.getState($prevValue)).toBe(0);
});

it('has first value on update', async () => {
const scope = fork();
const changeInitialStore = createEvent<number>();
const $initalStore = restore(changeInitialStore, 10);

const $prevValue = previousValue($initalStore);

await allSettled(changeInitialStore, { scope, params: 20 });

expect(scope.getState($prevValue)).toBe(10);
});

it('has previous value on multiple updates', async () => {
const scope = fork();
const changeInitialStore = createEvent<number>();
const $initalStore = restore(changeInitialStore, 10);

const $prevValue = previousValue($initalStore);

await allSettled(changeInitialStore, { scope, params: 20 });
await allSettled(changeInitialStore, { scope, params: 30 });
await allSettled(changeInitialStore, { scope, params: 40 });

expect(scope.getState($prevValue)).toBe(30);
});

it('has first scope value after first update', async () => {
const inc = createEvent();
const $initalStore = createStore(0);
const $prevValue = previousValue($initalStore, -1);
$initalStore.on(inc, (x) => x + 1);
const scope = fork({ values: [[$initalStore, 10]] });
await allSettled(inc, { scope });
expect(scope.getState($prevValue)).toBe(10);
});
41 changes: 41 additions & 0 deletions src/previous-value/previous-value.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { createEvent, createStore, restore } from 'effector';

import { previousValue } from './index';

it('has null when store is not changed', () => {
const $initalStore = createStore(10);
const $prevValue = previousValue($initalStore);

expect($prevValue.getState()).toBe(null);
});

it('has initial value when defined', () => {
const $initalStore = createStore(10);
const $prevValue = previousValue($initalStore, 0);

expect($prevValue.getState()).toBe(0);
});

it('has first value on update', () => {
const changeInitialStore = createEvent<number>();
const $initalStore = restore(changeInitialStore, 10);

const $prevValue = previousValue($initalStore);

changeInitialStore(20);

expect($prevValue.getState()).toBe(10);
});

it('has previous value on multiple updates', () => {
const changeInitialStore = createEvent<number>();
const $initalStore = restore(changeInitialStore, 10);

const $prevValue = previousValue($initalStore);

changeInitialStore(20);
changeInitialStore(30);
changeInitialStore(40);

expect($prevValue.getState()).toBe(30);
});
65 changes: 65 additions & 0 deletions src/previous-value/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# previousValue

:::note since
patronum 2.1.0
:::

```ts
import { previousValue } from 'patronum';
// or
import { previousValue } from 'patronum/previous-value';
```

### Motivation

The method allows to get previous value of given store. Usually need for analytics

### Formulae

```ts
$target = previousValue($source);
$target = previousValue($source, 'initial value');
```

### Arguments

1. `$source` ([_`Store`_]) - source store
2. `defaultValue` (_optional_) - default value for `$target` store, if not passed, `null` will be used

### Returns

- `$target` ([_`Store`_]) - new store that contain previous value of `$source` after first update and null or default value (if passed) before that

### Example

Push analytics with route transition:

```ts
import { createStore, createEvent, createEffect, sample } from 'effector';
import { previousValue } from 'patronum';

const openNewRoute = createEvent<string>();
const $currentRoute = createStore('main_page');
const $previousRoute = previousValue($currentRoute);

const sendRouteTransitionFx = createEffect(async ({ prevRoute, nextRoute }) => {
console.log(prevRoute, '->', newRoute)
await fetch(...)
});

sample({clock: openNewRoute, target: $currentRoute});

sample({
clock: openNewRoute,
source: {
prevRoute: $previousRoute,
nextRoute: $currentRoute,
},
target: sendRouteTransitionFx,
});

openNewRoute('messages');
// main_page -> messages
openNewRoute('chats');
// messages -> chats
```

0 comments on commit 3350602

Please sign in to comment.