Closed Naatan closed 2 years ago
Make sure that your Render
method is always responsible for creating new components/elements. Probably what you are doing is storing listitem
in a list somewhere and returning that multiple times in your Render
function. You need to return new listitem
s every time Render
is called.
Thanks, that was also the direction I was trying to move in. I had changed my component to instead of receiving a slice of MarkupOrChild
instead use a callback to receive that same slice. No dice so far though.. still trying to find out what I'm doing wrong.
What's the "vecty" way of creating a component that accepts child elements / components?
Turns out I missed a component. After changing my components to look like this:
type listitem struct {
vecty.Core
selected bool
markupOrChild func() []vecty.MarkupOrChild
}
It now works. But the markup is getting super unwieldy. Is this the recommended way? It does not feel intuitive.. sadly the intuitive approach is evidently error prone.
Also have to wonder what this does for previously initialized structs. eg. if I set c.selected=true
and it gets rerendered then either the property change is lost or vecty is doing something really questionable. Appreciate any insights into how the process works.
I struggled with this when I was trying to get it to work.
Have you looked at the todomvc example.
This renders a list of store.Items
Each time through the for
loop it retrieves an item
from store.Items
, it populates a new ItemView
with the item
data and appends it to items
(vecty.List
).
properties vs. state
Structure fields can be either a property or a state
If they are to be a property then you need to add `vecty:"prop"`
e.g.
type ItemView struct {
vecty.Core
SomePropField `vecty:"prop"`
SomeStateField
}
When an ItemView
is rerendered:
ItemView
is created.I see. So basically Vecty wants you to completely separate the rendering code from the state management code? I guess that makes sense, and is likely somewhere where most devs would end up anyway after the prototyping phase. It does still feel quite error prone though.
Appreciate the insights! I'm at least unblocked for now. For what it's worth I'd consider this the only part of vecty so far that I'd like to see some improvement on, everything else has been great! And to be fair it's not that this part is "bad", it's just not intuitive and prone to error.
By the way, can anyone tell me what this panic achieves? It seems disabling the panic makes the code function exactly the way I had assumed it would. Though I'm guessing it will create some type of breakage in other areas that I haven't reached?
It might be worth having a read of the following discussion
@VinceJnz Thanks, that's a useful read. Is implied in your response that the mechanic that this panic guards for is specifically this prop vs state mechanic?
It feels like a steep price to pay, surely there's better ways of addressing this use-case.
fwiw I ended up working around this issue with the following helper:
type MarkupOrChildProxy struct {
vecty.Core
Child vecty.MarkupOrChild
}
func RenderMarkupOrChild(markupOrChild ...vecty.MarkupOrChild) []vecty.MarkupOrChild {
result := []vecty.MarkupOrChild{}
for _, m := range markupOrChild {
switch v := m.(type) {
case vecty.MarkupList:
result = append(result, v)
case vecty.Component, *vecty.HTML, vecty.List, vecty.KeyedList:
result = append(result, &MarkupOrChildProxy{Child: v})
default:
panic(fmt.Sprintf("unsupported markupOrChild type: %T", v))
}
}
return result
}
func (c *MarkupOrChildProxy) Render() vecty.ComponentOrHTML {
return c.Child.(vecty.ComponentOrHTML)
}
func (c *MarkupOrChildProxy) SkipRender(prev vecty.Component) bool {
switch prev.(type) {
case *MarkupOrChildProxy:
return true
}
return false
}
This was influenced by other vecty projects I found that were using similar helpers.
Hopefully this type of workaround won't be required once vecty goes stable.
Due to lack of documentation I'm working off of examples, issues and backwards engineering. Sadly I feel like the issue of updating already rendered elements isn't easily discerned through any of those channels.
From the example code I found that I probably want to use
vecty.Rerender(elem)
. But so far any attempt I give this results in the following error:I find this error hard to understand. Is it telling me that once rendered an item cannot be rendered again? And if so, how am I meant to update rendered elements? I'm guessing there's a detail I'm missing.
The todo example doesn't seem to be doing anything fancy, I'm not sure what I'm doing wrong.
For what it's worth, here's an excerpt of the code I'm working with: