Search code examples
javascriptfunctional-programmingrxjsfrpbacon.js

Bacon.js (FRP) - Add/remove values from array and save in storage


I'm new to Bacon.js and FRP concepts. I'm struggling with implementing very basic functionality. I have an array of saved values in some local storage:

['A', 'B', 'C']

I have an asynchronous function that reads these values from storage (returns Promise).

I have 'add' event to add new item to array and 'remove' event to remove item from array. Every array update should write down updated array into the local storage.

I ended up with this solution but it doesn't work as expected:

const items = Bacon
    .fromPromise(storage.get('items'))
    .mapError(() => [])
    .merge(Bacon.fromEvent(events, 'add').map(l => [l]))
    .merge(Bacon.fromEvent(events, 'remove').map(l => [l]))
    .skipDuplicates()
    .filter(l => l)
    .toProperty();

items.onValue((items) => {
    // everytime rewrites storage with new array (but without old values)
    console.log(items); 
    storage.put('items', items);
 });

return items;

So at the start behavior is:

  • we read data from storage (that's fine): ['A', 'B', 'C']
  • but when 'add' event is fired with D item, it is not added to existed array, item replaces previous array values: ['D']

How I can do it with Bacon? I was thinking of update method but unfortunately initial value of it should be not a stream or some other async action.


Solution

  • Use Bacon.update. You can use an empty array as the initial value and provide the async initial value from your storage as one of the input streams for Bacon.update. So, try something like

    const items = Bacon.update([],
      Bacon.fromPromise(storage.get('items')), (_, items) => items,
      Bacon.fromEvent(events, 'add'), (items, newItem) => items.concat(newItem),
      Bacon.fromEvent(events, 'remove'), (items, removedItem) => 
        items.filter((item) => item != removedItem)
    )