-
-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
1cc58eb
commit 2389fd5
Showing
9 changed files
with
380 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { Event, Store } from 'effector'; | ||
|
||
export function snapshot<SourceType, TargetType = SourceType>(_: { | ||
source: Store<SourceType>; | ||
clock?: Event<any>; | ||
fn?(value: SourceType): TargetType; | ||
}): Store<TargetType>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
const { restore, sample } = require('effector'); | ||
|
||
function snapshot({ source, clock, fn }) { | ||
const defaultValue = fn ? fn(source.defaultState) : source.defaultState; | ||
|
||
return restore(sample(source, clock, fn), defaultValue); | ||
} | ||
|
||
module.exports = { snapshot }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
# Patronum/Snapshot | ||
|
||
```ts | ||
import { snapshot } from 'patronum/snapshot'; | ||
``` | ||
|
||
## `result = snapshot({ source, clock, fn })` | ||
|
||
### Motivation | ||
|
||
This method allows to copy any store on optional trigger event. | ||
It useful when you want to save previous state of store before some actions. | ||
|
||
### Formulae | ||
|
||
```ts | ||
result = snapshot({ source, clock, fn }); | ||
``` | ||
|
||
- Call `fn` with data from `source` while `clock` triggered, and create store with the value | ||
- If function in `shape` returns `undefined`, the update will be skipped. | ||
|
||
### Arguments | ||
|
||
1. `source` ([_`Store`_]) — Source store, data from this unit passed to `fn` | ||
2. `clock` ([_`Event`_]) — Trigger event | ||
3. `fn` _(`(value: T) => U`)_ — Transformation function | ||
|
||
### Returns | ||
|
||
- `result` ([_`Store`_]) — Copied store | ||
|
||
[_`event`_]: https://effector.dev/docs/api/effector/event | ||
[_`effect`_]: https://effector.dev/docs/api/effector/effect | ||
[_`store`_]: https://effector.dev/docs/api/effector/store | ||
|
||
### Examples | ||
|
||
#### Exact copy of store | ||
|
||
```ts | ||
import { createStore } from 'effector'; | ||
import { snapshot } from 'patronum/snapshot'; | ||
|
||
const $original = createStore<string>('Example'); | ||
|
||
const $copy = snapshot({ source: $original }); | ||
``` | ||
|
||
#### Exact copy on trigger | ||
|
||
```ts | ||
import { restore, createEvent } from 'effector'; | ||
import { snapshot } from 'patronum/snapshot'; | ||
|
||
const changeText = createEvent<string>(); | ||
const createSnapshot = createEvent(); | ||
|
||
const $original = restore(changeText, 'Example'); | ||
|
||
const $snapshot = snapshot({ | ||
source: $original, | ||
clock: createSnapshot, | ||
}); | ||
|
||
changeText('New text'); | ||
|
||
// $original -> Store with "New text" | ||
// $snapshot -> Store with "Example" | ||
|
||
createSnapshot(); | ||
|
||
// $original -> Store with "New text" | ||
// $snapshot -> Store with "New text" | ||
``` | ||
|
||
#### Copy on trigger with transformation | ||
|
||
```ts | ||
import { restore, createEvent } from 'effector'; | ||
import { snapshot } from 'patronum/snapshot'; | ||
|
||
const changeText = createEvent<string>(); | ||
const createSnapshot = createEvent(); | ||
|
||
const $original = restore(changeText, 'Example'); | ||
|
||
const $lengthSnapshot = snapshot({ | ||
source: $original, | ||
clock: createSnapshot, | ||
fn: (text) => text.length, | ||
}); | ||
|
||
// $original -> Store with "Example" | ||
// $lengthSnapshot -> Store with 7 (length of "Example") | ||
|
||
changeText('New long text'); | ||
|
||
// $original -> Store with "New long text" | ||
// $lengthSnapshot -> Store with 7 (length of "Example") | ||
|
||
createSnapshot(); | ||
|
||
// $original -> Store with "New long text" | ||
// $lengthSnapshot -> Store with 13 (length of "New long text") | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import { createDomain, allSettled, fork } from 'effector'; | ||
import { snapshot } from './index'; | ||
|
||
test('works in forked scope', async () => { | ||
const app = createDomain(); | ||
|
||
const changeValue = app.createEvent<number>(); | ||
const copy = app.createEvent(); | ||
|
||
const $original = app.createStore(1).on(changeValue, (_, newValue) => newValue); | ||
|
||
const $copy = snapshot({ | ||
source: $original, | ||
clock: copy, | ||
}); | ||
|
||
const scope = fork(app); | ||
|
||
expect(scope.getState($copy)).toBe(1); | ||
|
||
await allSettled(changeValue, { scope, params: 2 }); | ||
await allSettled(copy, { scope }); | ||
|
||
expect(scope.getState($copy)).toBe(2); | ||
}); | ||
|
||
test('does not affects another scope', async () => { | ||
const app = createDomain(); | ||
|
||
const changeValue = app.createEvent<number>(); | ||
const copy = app.createEvent(); | ||
|
||
const $original = app.createStore(1).on(changeValue, (_, newValue) => newValue); | ||
|
||
const $copy = snapshot({ | ||
source: $original, | ||
clock: copy, | ||
}); | ||
|
||
const scope1 = fork(app); | ||
const scope2 = fork(app); | ||
|
||
expect(scope1.getState($copy)).toBe(1); | ||
expect(scope2.getState($copy)).toBe(1); | ||
|
||
await allSettled(changeValue, { scope: scope1, params: 2 }); | ||
await allSettled(copy, { scope: scope1 }); | ||
|
||
expect(scope1.getState($copy)).toBe(2); | ||
expect(scope2.getState($copy)).toBe(1); | ||
}); | ||
|
||
test('does not affect original store state', async () => { | ||
const app = createDomain(); | ||
|
||
const changeValue = app.createEvent<number>(); | ||
const copy = app.createEvent(); | ||
|
||
const $original = app.createStore(1).on(changeValue, (_, newValue) => newValue); | ||
|
||
const $copy = snapshot({ | ||
source: $original, | ||
clock: copy, | ||
}); | ||
|
||
const scope = fork(app); | ||
|
||
expect(scope.getState($copy)).toBe(1); | ||
expect($copy.getState()).toBe(1); | ||
|
||
await allSettled(changeValue, { scope, params: 2 }); | ||
await allSettled(copy, { scope }); | ||
|
||
expect(scope.getState($copy)).toBe(2); | ||
expect($copy.getState()).toBe(1); | ||
}); |
Oops, something went wrong.