paldepind / flyd

The minimalistic but powerful, modular, functional reactive programming library in JavaScript.
MIT License
1.56k stars 85 forks source link

Feature Request - Supply metadata for a combined stream #191

Open kesupile opened 5 years ago

kesupile commented 5 years ago

I'm attempting to use flyd to build a state management system. The application state comprises of smaller states that can be subscribed to, and a combined state (using a combined stream) that can also be subscribed to as a whole. I would like a way to pass metadata from the independent stream to the dependent stream when a new value is emitted.

I imagine the API looking something like this:

import { stream, combine } from 'flyd';

const stream1 = stream(0)
const stream2 = stream(0)

const combined = combine((v1, v2, self, changed, meta) => {
  console.log('data', v1()) // => 0
  console.log('data', v2()) // => 1
  console.log('meta', meta) // => {metadata: true}
}, [stream1, stream2])

stream2(1, {metadata: true})

If there is already a workflow that provides this functionality, could you tell me about it?

nordfjord commented 5 years ago

I'm not quite sure what you're trying to achieve with the metadata thing, could you elaborate a bit on what it is you're actually trying to achieve?

nordfjord commented 5 years ago

Perhaps you could in your library do something like:

const stream = (...args)=> {
  const s = flyd.stream(...args);
  s.metadata = flyd.stream();
  // pretend we received an update
  s.metadata.map(()=> s(s()));
  return s;
}

// ... later

const combined = combine((v1, v2) => {
  const metadata = {...v1.metadata(), ...v2.metadata()};
  console.log('data', v1());
  console.log('data', v2());
  console.log('meta', metadata);
}, [s1, s2])

Maybe you could enforce usage of the streams as a Tuple

const s1 = stream([1])
const s2 = stream([0]);

const combined = combine(()=> {
  const values = [s1, s2].map(v => v());
  const [v1, v2] = values.map(v => v[0]);
  const meta = values.reduce((p,v)=> Object.assign(p, v[1] || {}), {});
  console.log('data', v1);
  console.log('data', v2);
  console.log('meta', meta);
}, [s1, s2])

s2([1, {metadata: true}])