-
-
Notifications
You must be signed in to change notification settings - Fork 117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How can I know what is the real path that changed from a monkey update? #438
Comments
Hello @dumconstantin. If you need to access paths that were edited you should listen to the tree's update events. They hold this information. |
Hey @Yomguithereal, yeah, I tried doing that but then I don't know how to link the monkey update to the tree update because neither knows about the other. I have a listener on a monkey (that may have other monkeys in its dependency) and a list of paths I don't want the updateFn to be triggered if the changed path is in the list. My actual use case is like: let tree = new Baobab({
a: {
prop1: { ... },
prop2: 123,
prop3: { ... },
prop4: 'asd'
},
b: monkey(['a'], identity)
})
tree.select('b').on('update', e => {
let exclude = ['prop1', 'prop3']
if (-1 === exclude.indexOf(e.target.actualPropChange)) {
doAction()
}
})
// This is the type of action I don't want to do anything
tree.select('a', 'prop1', 'deepProp').set(321)
// But I want to react to this
tree.select('a', 'prop2').set(321) |
Would having the transaction details of the update in the cursor update event payload help you? |
Yes, quite a lot actually. Knowing exactly what change triggered the monkey to update makes reasoning about the data structure much easier. Is there a way to achieve that? |
I might add the information to the cursor's payload data then. Just need some time to think about it to see whether it's really relevant or not. |
That would be great, I really need it for an app I'm currently building. Do you need for me to describe better my current setup and rationale behind this request? |
Yes. This would be nice. |
Sure. This is what I have at the moment: // using RamdaJS for the functions
let monkey = Baobab.monkey
let tree = new Baobab({
entities1: {},
entities2: {},
entity2ByEntity1: monkey(['entities2'], compose(map(indexBy(prop('id'))), groupBy(prop('entity1_id')), values)
visible: {
entity1: monkey(['entities1'], filter(propEq('visible', true)),
entity2: monkey(['visible', 'entity1'], ['entity2ByEntity1'], compose(mergeAll, values, useWith(pick, [keys, values]))
}
})
// I'm using RiotJS and I made a cursor mixin that allows
// Riot components to subscribe to the baobab state.
// dataCursor:: string (namespace) -> { propName: baobab path }
// The mixin receives an update event, sets the new state on the Riot component
// and then triggers the component to update
<entity2>{ props ... }</entity2>
<entity1>
<entity2 each={ data.entities2 }></entity2>
this.dataCursor('data', {
entities2: ['visible', 'entity2']
})
</entity1>
<entities>
<entity1 each={ data.entities1 }></entity1>
this.dataCursor('data', {
entities1: ['visible', 'entity1']
})
</entity> As I developed the application further the state tree grew as more entities were added. However the data is hierarchical. So the above structure is a bit redundant and monkeys are mostly used to provide the following hierarchy:
If I try to implement the above structure then the What I would like to do is this: <entities>
<entity1 each={ data.entities1 }></entity1>
this.dataCursor('data', {
entities1: {
path: ['visible', 'entity1'],
updateOff: ['entities2', 'entities4'] // don't update the state if any of these change
})
// or
this.dataCursor('data', {
entities1: {
path: ['visible', 'entity1'],
updateOn: ['prop1', 'prop2'] // update the state only if these change
}
})
</entity>
// and inside the dataCursor something like
tree.select(entities1.path).on('update', e => {
if (-1 !== e.data.updatedPaths.indexOf(entities.updateOn) {
tag.data = tree.select(entities1.path).get()
tag.update()
}
}) I don't want to do a comparison between the data in the riot tag and the new data because the state tree should be the single source of truth. Also I wouldn't want to do diffs on the tree on the update function because I expect that cursor events mean the same thing (I don't need to know the value that changed but I do need the path to the value that changed so I can trigger an update). With the diff/updatePaths are available at the cursor event level I am able to better structure the data tree without any worries of overflowing the app with unnecessary updates on higher level components. |
Hmm, I had a thought, maybe adding the monkeys to the tree update event would be a much better (and maybe simpler solution). The way I thought about it now is kind like: tree.on('update', e => {
let paths = join(e.data.paths, e.data.monkeyPaths)
if (-1 !=== paths.indexOf(RiotTagDataListeningPaths) {
// trigger an update on all the riot tags according to their updateOn/updateOff rules
}
}) |
Diff should indeed be avoided. The whole point of this library is to avoid costly diffs and rely on paths and referential comparisons enabled by the immutability/persistence system. Which leads me to wonder if this wouldn't be possible to implement someting in RiotJS like React's |
Yup, that's exactly what I felt about Baobab and why a big light bulb got lit when I saw it. I'm trying to move every piece of logic onto the Baobab tree, so instead of doing computation inside components (which includes the I also need to push data changes to streams or third party APIs, so I can't rely on the internal mechanisms of Riot/React etc to figure out if indeed something needs refreshing. I'm looking at Baobab to provide a universal mechanism to propagate the new state according to what every listener needs. I was thinking now of using the |
I also could see value in having the exact list of paths passed both to cursor changes and monkey callbacks. In our case it's wanting to know only if an item has been added/removed from an array as opposed to just a property on an item changing. Access to the paths makes knowing that easy and allow us to avoid re-computing the monkey data unless an item was added/removed. |
I haven't used baobab with arrays yet but I think this is where you'd need the event details most. As a workaround for nested object, I found using watchers with specific paths to the properties I need, instead of just on the parent object, avoids the problem of recompilation. Constantin Dumitrescu
|
Consider the following:
What should I replace the
e.target.actualPathThatChanged
with to get['foo', 'bam']
?The text was updated successfully, but these errors were encountered: