meteorhacks/flow-components

stateFn for #each loop

Opened this issue · 6 comments

Hi, I migrated the templates of my app to FlowComponents and overall this worked out great and improved my code a lot. However, in some cases I have lost the fine-grained reactivity I had before. These cases follow all the same pattern:

{{#each state$myArray}}
{{>render component="my-component" myProperty=this}}
{{/each}}

If I understand this right, I need to use stateFn$ to wrap the value of myProperty in a function, to avoid rerenderings if myProperty changes. But how can I do this in these cases, where stateFn$myProperty can not be used? Another case in which this problem occurs is something like:

{{>render component="my-component" myProperty=state$myObj.myProperty}}

stateFn for this may not work. I need to think some way to do it.

You should not use . operator for states. They will cause re-rendering. This is not only for flow-components. But for templates in general.

Hi, as this issue is really vital for my project I created a small example to examine the rerendering behavior of simple blaze templates compared to flow components. Please excuse the rather long message.

  • First of all, the example shows that the . operator does not cause rerendering in general.
  • Secondly, I discovered some interesting differences between the handling of live queries and their fetched results.

You can find the source code here: https://github.com/christianvoigt/flow-components-rerendering-test
I have deployed the example here: http://flow-components-rerendering-test.meteor.com/

I have created a local collection called Greetings and inserted some initial greetings of the form {text:String} that are displayed in two #each loops. The first uses a normal template that has the attribute greetingText=this.text. The second loop uses a flow component with the same attribute.

Please open the console to get log messages about how many "greeting templates" and "greeting components" were created, rendered and destroyed. If you click on the first link that inserts a new document into the collection, you will see that only one new template is created and rendered, while all flow components are destroyed, recreated and rerendered. This is the problem we already talked about. Interestingly, this problem only occured if I used Greetings.find().fetch() instead of Greetings.find() for the #each loops.

So one option would be to only use live queries in these cases. But this is very limiting. I thought maybe it would be possible to wrap this.text in the #each loop into a function similar to what stateFn$ does, but that doesn't seem to work either.

If you click on the second link, the text of one document in the collection will be updated. As I already said above, this does not cause a rerendering of any of the normal templates, even though I used the . operator. But it does cause a complete rerendering of the list of components.

Do you have any ideas for a workaround I could implement on my own? If I can't get this to behave in the same fine-grained way as it did before, I fear I have to revert to simple Blaze templates for now.

Yes, I have the same question sort of...

Can you perhaps show an example when you use parent + child components looping over a collection and what the default/expected behavior is when you update the cursor/document or any reactive var/state in the component.

rclai commented

@arunoda If we shouldn't pass . into the child component, how should we pass it in order for it to be more efficient?

+1

I have this issue too of components inside #each loops always rendering on changes. Any idea on how to fix it?