Comments (14)
@nordfjord thanks for the help, definitely learned something new.
from flyd.
@EmirGluhbegovic hello. I think it is drop repeats. Also, feel free to visit gitter chat.
from flyd.
@StreetStrider Is absolutely correct, we have the droprepeats module precisely for this usecase.
An example usage would be something along these lines.
import { dropRepeats } from 'flyd/module/droprepeats'
import { stream } from 'flyd'
const s = stream()
const result = [];
s.pipe(dropRepeats).map(val => result.push(val));
s(1)(1)(1)(2)(2)(3)
result // [1, 2, 3]
The module also exposes dropRepeatsWith
with which you can supply your own comparator.
e.g.
import { dropRepeatsWith } from 'flyd/module/droprepeats'
import { equals } from 'ramda'
import { stream } from 'flyd'
const dropRepatsWithEquals = dropRepeatsWith (equals)
const s = stream()
const result = []
s.pipe(dropRepeatsWithEquals).map(val => result.push(val))
s({a: 1})({a: 1})({a: 2})
result // [{a: 1}, {a: 2}]
from flyd.
@nordfjord @StreetStrider Thanks for the replies.
The issue I am having is that on a certain model state I fire off an action which updates the model state, the issue being that that causes the "StateChangeListener" to fire off again which then since the state is the same causes the same action to fire off again and so the loop continues ....
I would want the "StateChangeListener" to be able to compare the previous states state for a certain object value the the new states certain object value and if they differ then run the update action.
Looking at dropRepeat, looks like it will still be stuck in the loop. As the action will fire off which causes the listener to trigger the action etc...
from flyd.
@EmirGluhbegovic isn't that custom comparator would suffice for you? Or you need a full historical depth of your state to look in?
from flyd.
@StreetStrider Thanks for getting back so quick.
I only need to compare the most recent state to the previous state.
The part I am a little confused with, (so maybe its my lack of knowledge of Flyd and streams in general), is that there might be different things I want to compare, using the above example would be tricky to implement for different types of "state change listeners" as each needs to compare a different part of the state. I assume the easier way would be in each actual listener to have the comparison done there of prevState vs currentState and then trigger the potential action.
Let me know if more concrete examples would help, (i.e if the above makes any sense :p)
from flyd.
@EmirGluhbegovic Would you be willing to provide a small example we could play with? I'm not sure I'm following what you need.
as for
there might be different things I want to compare
I would think ramda could help you
import { dropRepeatsWith } from 'flyd/module/droprepeats'
import { pathEq } from 'ramda'
dropRepeatsWith(pathEq(['some', 'deeply', 'nested', 'prop']))
But a small example, perhaps a jsbin would be lovely so we can better understand the problem.
from flyd.
As a baseline
from flyd.
@nordfjord @StreetStrider I have added an example. Please let me know if that makes sense.
I added the example here:
view example here
from flyd.
I see, Looking at the code the big problem seems to be the updateRoute method.
It's mutating the navigation object.
meaning any comparison is futile at that point.
function updateRoute() {
update(R.assocPath(['navigation', 'path'], 'test'));
}
Is equivalent barring the mutation.
If we then add dropRepeatsWith
to the mix we can create a function eqPath
const eqPath = R.curry(function(p, v1, v2) {
const getPath = R.path(p);
return R.equals(getPath(v1), getPath(v2));
});
With that function we can use dropRepeatsWith
on the state stream
models
.pipe(dropRepeatsWith(eqPath(['navigation', 'path'])))
.map(routeSubscriber);
from flyd.
I see it works correctly, but I don't fully understand some of the code. Also what the is R object? Is that reference to Ramda?
If you can run me through the logic that would be very helpful.
Thank you
from flyd.
The most important part was changing the updateRoute
function
for an example why the old version was problematic, let's take a look at this:
const state = {route: ''};
const results = [state];
function test() {
state.route = 'test';
results.push(state);
}
test();
results; // [{route: 'test'}, {route: 'test'}]
This means any comparison is moot because of the mutation.
So to fix this we use R.assocPath
(R is the reference to the ramda object)
assocPath
associates a value to a given path immutably.
R.assocPath(['route'], 'test', {}) // {route: 'test'}
The example above would then yield
const state = {route: ''};
const results = [state];
function test() {
results.push(R.assocPath(['route'], 'test', state));
}
test();
results; // [{route: ''}, {route: 'test'}]
Now as for the dropRepeats, we needed a function that could compare a value inside a nested structure.
const eqPath = R.curry(function (p, v1, v2) {
const getPath = R.path(p); // getPath takes an object and returns the value at path p
return R.equals(getPath(v1), getPath(v2)); // compare the values at path p in both objects
});
We can then use eqPath
with dropRepeatsWith
to drop sequential equal values
model
.pipe(dropRepeatsWith(eqPath(['navigation', 'state'])))
.map(routeSubscriber)
from flyd.
@nordfjord Thank you, appreciate you taking your time to explain this.
I want to ask with regards to the curry function, are you using it so that, you automatically are giving it the first parameter with "eqPath(['navigation', 'state'])", then the first time it gets called the "v1" parameter will get called and the second time it gets called the function will have all 3 parameters and therefore run?
If that is the case does that mean then that every subsequent call then fills in the v1 field again and the following the v2 field? Havn't used Ramda or curry type functions, read the docs on ramda.
Want to understand what is exactly happening the background there with the curry function as that part of the eqPath function seems to be the key to the rest of the logic.
from flyd.
Curry allows you to call the function with any number of parameters, if they are too few then a function is returned which takes the rest of the arguments.
e.g.
const add = R.curry((a,b)=> a + b);
const add1 = add(1) // (b) => 1 + b
add1(2) // 3;
In our case we have eqPath
const eqState = eqPath(['navigation', 'state']) // (v1, v2)=> boolean
eqState({}, {}) // true
const eqStateTest = eqState({navigation: {state: 'test'}}) // (v2)=> boolean
eqStateTest({navigation: {}}) // false
eqStateTest({navigation: {state: 'test'}}) // true
from flyd.
Related Issues (20)
- add more dependency for existing combine HOT 7
- Merge stream delay HOT 6
- add package.module
- Drag 'n Drop example is broken HOT 2
- Feature Request - Supply metadata for a combined stream HOT 2
- Help to build control flow func HOT 3
- Do you think this Promise -> Stream conversion is a right alternative way? HOT 6
- Wrong chain + setImmediate behavior HOT 1
- Benchmark against Most.js HOT 3
- Can flyd streams be made lazy ? HOT 9
- HELP: Trouble reading api documentation HOT 1
- Enhancement: Add Readonly-Streams (at least in Typings) HOT 3
- What's the motivation for ending a stream? HOT 3
- question on serialize stream
- from Node stream HOT 2
- Question: Required (code) complexity for higher-order streams HOT 10
- Support multiple operators for Pipe HOT 4
- [Help Needed] CombineLatest in the style of RxJs HOT 17
- Switch Latest without Ramda Dependency HOT 6
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from flyd.