Expose subscribe / unsubscribe functions from Atom
Summary: Allow subscribing to Atom state changes Reviewed By: mweststrate Differential Revision: D28027692 fbshipit-source-id: 24fd7ea16b013c364bbb1d25b30c48bc698db014
This commit is contained in:
committed by
Facebook GitHub Bot
parent
dcc7e06afc
commit
140cf38ffd
71
desktop/flipper-plugin/src/state/__tests__/atom.node.tsx
Normal file
71
desktop/flipper-plugin/src/state/__tests__/atom.node.tsx
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @format
|
||||
*/
|
||||
|
||||
import {createState} from '../atom';
|
||||
|
||||
test('can subscribe to atom state changes', () => {
|
||||
const state = createState('abc');
|
||||
let receivedValue: string | undefined;
|
||||
let receivedPrevValue: string | undefined;
|
||||
const unsubscribe = state.subscribe((value, prevValue) => {
|
||||
receivedValue = value;
|
||||
receivedPrevValue = prevValue;
|
||||
});
|
||||
try {
|
||||
state.set('def');
|
||||
expect(receivedValue).toBe('def');
|
||||
expect(receivedPrevValue).toBe('abc');
|
||||
state.set('ghi');
|
||||
expect(receivedValue).toBe('ghi');
|
||||
expect(receivedPrevValue).toBe('def');
|
||||
} finally {
|
||||
unsubscribe();
|
||||
}
|
||||
});
|
||||
|
||||
test('can unsubscribe from atom state changes', () => {
|
||||
const state = createState('abc');
|
||||
let receivedValue: string | undefined;
|
||||
let receivedPrevValue: string | undefined;
|
||||
const unsubscribe = state.subscribe((value, prevValue) => {
|
||||
receivedValue = value;
|
||||
receivedPrevValue = prevValue;
|
||||
});
|
||||
try {
|
||||
state.set('def');
|
||||
expect(receivedValue).toBe('def');
|
||||
expect(receivedPrevValue).toBe('abc');
|
||||
} finally {
|
||||
unsubscribe();
|
||||
}
|
||||
state.set('ghi');
|
||||
expect(receivedValue).toBe('def');
|
||||
expect(receivedPrevValue).toBe('abc');
|
||||
});
|
||||
|
||||
test('can unsubscribe from atom state changes using unsubscribe method', () => {
|
||||
const state = createState('abc');
|
||||
let receivedValue: string | undefined;
|
||||
let receivedPrevValue: string | undefined;
|
||||
const listener = (value: string, prevValue: string) => {
|
||||
receivedValue = value;
|
||||
receivedPrevValue = prevValue;
|
||||
};
|
||||
state.subscribe(listener);
|
||||
try {
|
||||
state.set('def');
|
||||
expect(receivedValue).toBe('def');
|
||||
expect(receivedPrevValue).toBe('abc');
|
||||
} finally {
|
||||
state.unsubscribe(listener);
|
||||
}
|
||||
state.set('ghi');
|
||||
expect(receivedValue).toBe('def');
|
||||
expect(receivedPrevValue).toBe('abc');
|
||||
});
|
||||
@@ -17,11 +17,13 @@ export type Atom<T> = {
|
||||
get(): T;
|
||||
set(newValue: T): void;
|
||||
update(recipe: (draft: Draft<T>) => void): void;
|
||||
subscribe(listener: (value: T, prevValue: T) => void): () => void;
|
||||
unsubscribe(listener: (value: T, prevValue: T) => void): void;
|
||||
};
|
||||
|
||||
class AtomValue<T> implements Atom<T>, Persistable {
|
||||
value: T;
|
||||
listeners: ((value: T) => void)[] = [];
|
||||
listeners: ((value: T, prevValue: T) => void)[] = [];
|
||||
|
||||
constructor(initialValue: T) {
|
||||
this.value = initialValue;
|
||||
@@ -33,8 +35,9 @@ class AtomValue<T> implements Atom<T>, Persistable {
|
||||
|
||||
set(nextValue: T) {
|
||||
if (nextValue !== this.value) {
|
||||
const prevValue = this.value;
|
||||
this.value = nextValue;
|
||||
this.notifyChanged();
|
||||
this.notifyChanged(prevValue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,16 +53,17 @@ class AtomValue<T> implements Atom<T>, Persistable {
|
||||
this.set(produce(this.value, recipe));
|
||||
}
|
||||
|
||||
notifyChanged() {
|
||||
notifyChanged(prevValue: T) {
|
||||
// TODO: add scheduling
|
||||
this.listeners.slice().forEach((l) => l(this.value));
|
||||
this.listeners.slice().forEach((l) => l(this.value, prevValue));
|
||||
}
|
||||
|
||||
subscribe(listener: (value: T) => void) {
|
||||
subscribe(listener: (value: T, prevValue: T) => void) {
|
||||
this.listeners.push(listener);
|
||||
return () => this.unsubscribe(listener);
|
||||
}
|
||||
|
||||
unsubscribe(listener: (value: T) => void) {
|
||||
unsubscribe(listener: (value: T, prevValue: T) => void) {
|
||||
const idx = this.listeners.indexOf(listener);
|
||||
if (idx !== -1) {
|
||||
this.listeners.splice(idx, 1);
|
||||
|
||||
Reference in New Issue
Block a user