S
Solara12mo ago
pnjun

Efficiently rendering a list of components

Hey! I think i might be doing something in a non-solara way, since my app is having trouble re-rendering some compoents. I have a 'logbook' component that displays a list of entries in a loop, something like this:
@solara.component
def LogbookRender(logbook: Logbook):
appending, set_appending = solara.use_state(False) # Are we appending a new entry?

with solara.Card():
for entry in logbook:
EntryRender(entry)

if appending:
EntryRender(logbook.new_entry(), on_save=lambda: set_appending(False))
else:
solara.Button('Add Entry', on_click=lambda: set_appending(True))
@solara.component
def LogbookRender(logbook: Logbook):
appending, set_appending = solara.use_state(False) # Are we appending a new entry?

with solara.Card():
for entry in logbook:
EntryRender(entry)

if appending:
EntryRender(logbook.new_entry(), on_save=lambda: set_appending(False))
else:
solara.Button('Add Entry', on_click=lambda: set_appending(True))
The issue is that every time the user adds an entry to the list all of the previous entries are re-rendered, and this can take quite awhile for a long logbook. Is there a way to let solara know not to rerender all of the previous entries and just append the new one at the bottom of the container? I feel i might be doing something wrong but don't know what 😅 Cheers and thanks!
9 Replies
MaartenBreddels
MaartenBreddels12mo ago
Yeah, if you give an element a unique key, using .key(f'some-prefix-{entry.id}') is should be smarter
pnjun
pnjunOP12mo ago
Cool! Is there some documentation on the .key() method? Do i just call it on the component after i create it like this?
EntryRender(entry).key(f'some-prefix-{entry.id}')
EntryRender(entry).key(f'some-prefix-{entry.id}')
thanks a lot! I tried this and it does not seem to be any faster, everything is re-rendered anyway
MaartenBreddels
MaartenBreddels12mo ago
can you make a pycafe snippet that show this? This should work as advertised, if not, maybe something else is going on
pnjun
pnjunOP12mo ago
i will try to make something reproducible!
pnjun
pnjunOP12mo ago
Hey! I got a snippet working. The problem is in the fact that my logbook class returns a new entry object every time you iterate over it, even if the contents are the same. I In hindsight, it is obvious that the automatic caching is not working, since i call the components with a different object as argument. I am thinking if i can change the structure of my logbook class to deal with this, but i do not know it that is possible. The solution with the .key call sounds like the perfect approach, but adding the .key call as you suggest does not do anthtying, the caching still does not work. You can try my snipped with and without the .key call and the result is always the same, the components are always re-rendered even if they have the same key. Here is the snippet: https://app.py.cafe/snippet/solara/v1#c=H4sIAFrcDGcAA41UXU_bMBT9K5Z5IJVCWvoBIxLaBmPapO2Fh-2BoMqNbxKrjp3ZLiWq-t93nY9SUFFJX-x7r8-559i3G5pqDjSmJyQtIF0SvXKkcK6y8XBotWSGRRyehiTThnCdrkpQjjmhVaJOCMb62ly4YrWIUl0O14Ln4Jzozg995VfFDxBUdZSyDIYlY8aBWhjgHKRtyEptgMAzKysJNlGirLRxpIVMkD2VzFpyp5ypg0GcKIIfh4zM50IJN58HFmQWEgfPrk_7z0cjHyTXTe4N1E8Hhi0kvAbEYAe4D-W7BCIUMUzlEEz2c_6rBUjedWidCWAw8GxfOlvRqkortDNRnuabsJVkdVuOUVP3eJURygXZqQEsxHVONk1-e4p4vmCN3nfORLfM8J0fjeA2_puZJddr1UI3Dnygm1_CuuaEANuDOp3nEkJ00s3bNVrZoawszC2-Dwi-M2lhQPDm8RrXQFhVYfu-eUYUrEnTxucWcV9mQu93MiWyJ7Rpc-e3P-Y975raE3rAwGgJ3fJF8J4nNyvntAokW4C8zjxza3FCQ6LVPJUiXV5LVi44i_fkBkq7zoX2RiuWew_2PXv1mAJf5otoSA38WwkDfowsjl3_njHj6soPYhvBPTr2R8Caxpm3MqTAhbtTHo_GzqwwUtWu0ArPVLXmgsPZ0ygaz6JzPIx94KDReEOfwFgcVxqPkVxrd68RctOzGdyFNC2E5Kidxg-7jGMLlIxJHGdX0Ph8NgppKdTfdjtpdz9A5AXy-K3geCwTEm4Q1YK51fhXIRSYdxh86dmircWSinlcSreP2_BAFx3R-WgWjcaTq_FkOp1eXV6MPr3b_gsmWhlV9WvkVnkPezWNPNjlxWw2a-CPmHLciE7YMRN6_YdVF73qy9lHOPG9YZjJY6R9nWf1v23YXAY-yIfH7X-KXjAkEwYAAA
PyCafe
Playground for Python web frameworks. Run and edit Python code snippets for web frameworks in a web browser.
pnjun
pnjunOP12mo ago
Thanks a lot!
Edan Bainglass
Edan Bainglass5mo ago
I see that this has not received any attention for some time. I was wondering if you were able to resolve your issue? I have a similar situation where I am observing re-rendering in non-active tabs, where each tab is rendering a component that takes a model from a dynamic list of models. Changes in one component do not leak into another. However, adding/removing a model (which will add/remove a component) does cause an unwanted re-render in every tab, even though nothing has changed in those tabs. Memoization of the tabbed components didn't work. I then came across this issue and discovered the .key() method (@solara this is not well document). Unfortunately, it did not help in my case. However, I tried it in a small toy model, and it actually worked. No re-rendering in inactive tabs on add/remove operations. Trying to figure out how to step this back up to my actual use case. I hope to find the root issue in the process. Will report my findings here.
PyCafe
Playground for Python web frameworks. Run and edit Python code snippets for web frameworks in a web browser.
Edan Bainglass
Edan Bainglass5mo ago
@MaartenBreddels I got my actual use case to work. However, it suffers from what appears to be a bug that also exists in this updated toy model, where I lose reactiveness. In the toy model, I have a dynamic tab system, each tab rendering a reactive counter. When I add a tab, all counters but the new one no longer react (increment button no longer increments counter). Reactiveness is restored when I remove the .key() on the inner component. However, this restores the original issue of unnecessary re-rendering in inactive tabs on tab add/remove operations. Could you have a look? 🙏
PyCafe
Playground for Python web frameworks. Run and edit Python code snippets for web frameworks in a web browser.
Edan Bainglass
Edan Bainglass5mo ago
I now suspect that with .key(), the reason why inactive tabs don't re-render is perhaps not due to an understanding that they shouldn't, but actually this bug. They have lost all reactiveness, so nothing is firing.

Did you find this page helpful?