Open KoderFPV opened 7 years ago
I'm not sure exactly what your question is. Are you already running a mercury app that these components will be put inside?
It looks like you want parts_list
in the table component to be an array of objects like the ones created by the part_row
component, right? In that case I think you could just import the part_row
function and do something like:
export default (opts) => {
return hg.state({
parts_list: opts.parts.map(part_row_state),
})
}
@crabmusket Thanks it is nearly what I need. But I had to do this:
parts: Store.parts.map((part) => {
return part_model(part)**()**
})
And now when I have in part_row component :
channels: {
changeQuantity: changeQuantity
}
function changeQuantity(state, value) {
const quantity = parseInt(value.quantity)
state.quantity.set(quantity)
state.total_list_price.set(quantity * state.unit_price())
}
changeQuantity is triggered on event, it works, but it does not re render part_row. Do you know why?
Here is repo: https://github.com/Tarvald/bom Here part row state: https://github.com/Tarvald/bom/blob/master/src/components/parts_list/part_table/part/part.model.js Here part table state: https://github.com/Tarvald/bom/blob/master/src/components/parts_list/part_table/part_table.model.js
Hmm that doesn't look right - part_model(part)
will return a hg.state
, right? Then calling part_model(part)()
will get the value of the state as a plain JS object. But don't you want a tree of hg.state
objects? I imagine part_row
is not re-rendered for that reason? It's been too long since I worked with mercury :sweat_smile:
@crabmusket I thought that hg.state return ready-to-ready object with values. I don't understand why I should not get values of state as a plain JS object. And why should I want hg.state object? And I would like to re render part_row, that why I am doing this channels, and states tricks.
Sorry I'm quite new in FRP, mercury, states etc.
So even I did
parts_list: opts.parts.map(part_row_state),
In the render I had to do state.part_number() instead of just state.part_number And still row does not re render
Maybe I'm misremembering, and you can't nest hg.state
objects. The application state should be a tree of observ
able objects, and then when rendering happens, you turn the observ
tree into a non-observ
object (which is what all the render functions get passed).
Ok, so please take the following as a very subjective opinion: I personally found that it becomes very hard to manage observ-* trees when they become large, so at first I tried to fix it by throwing code at it (https://github.com/ashnur/observ-change, https://www.npmjs.com/package/observ-confined)
However this still was not quite good enough. So I went back and thought a lot about this, what is the best way to deal with state on the frontend when it becomes large and complicated, and since then I am using a mercury where I replaced the observ-* tree with https://github.com/typeetfunc/datascript-mori
Now, this has it's own issues, mainly that writing datalog in js and using mori functions is still a pita, but at least now state is easy. It's in one place, it's fast, and I can ask anything from it with a cool query language. So writing new views although is very verbose and takes longer than it should, it also gives a very flat structure that's easy to understand and grasp once you know what's happening.
Again, this fits my needs so far, when it doesn't, I tend to not use mercury but go for react/redux.
What I did to compose trees of state is write a base component that binds the state to a render function. I have the module here, npm here.
This allows me to have child components as part of the state tree, and call render on those child components directly without worrying about what their immediate render function is.
See also this section of the FAQ. Here Raynos seems to use struct
instead of state
for subcomponent states... but calling state
should return a struct
anyway so I'm not sure what the difference is :/
EDIT: oh hey. Back in my original comment I made a mistake. @Tarvald, maybe try this:
export default (opts) => {
return hg.state({
parts_list: hg.array(opts.parts.map(part_row_state)),
})
}
E.g. you need to convert the result of map
to an observable hg.array
before using it in the state. Maybe that will have some effect.
@crabmusket this kind of trial and error that I got bored with eventually and decided to read up on state management and ended up here: https://www.infoq.com/presentations/Value-Values :)
I have part table component, this component will use part_row component so lets imagine:
Part_row component:
State:
Renderer:
Table component
State:
And finally renderer:
Sooooo how to "connect" or "attach" in this pattern part state? I don understand that. Why I should create state for part_row component if I pass state to renderer. The only stupid solution what I can imagine would be
Table component State:
Thanks for help :) Regards