S
SolidJS14mo ago
crowned

How to allow updating of elements instead of destroying and rendering the elements?

I have an array of 100 objects and an div is rendered for each object. Whenever the array changes, a new set of 100 divs are rendered for the new objects. How do I make it such that there are always 100 divs and whenever the array changes, the contents of these divs are changed instead of the divs being re-rendered (destroyed and created). I'm doing this to improve performance and user experience
34 Replies
crowned
crownedOP14mo ago
So the video above (Delay_in_Updating) shows what happens when I click a button to update the array. There is a delay before the current menu state (below the 'Categories' heading) is updated. I understand that this is because it has to update the array and re-render the divs.
crowned
crownedOP14mo ago
crowned
crownedOP14mo ago
And the video above (Instant_Updating) shows what happens when I only put a dummy array with 100 empty objects so that no divs are destroyed and created when the button is pressed. As you can see, the current menu state (shown as text below the 'Categories' heading) updates instantly. But how do I make the state update instantly (even if dummy data shows for the 100 divs) and when the divs are created, they display smoothly instead of the user waiting for an update which makes the app seem laggy. Or if my question is impossible, how can I provide a better User Experience.
Alex Lohr
Alex Lohr14mo ago
Use fine-grained reactivity as much as possible. Reuse object instances as much as possible. Without having a look at your code, I cannot make more detailed suggestions.
crowned
crownedOP14mo ago
Okay, I'm working on uploading a demo to codesandbox. Here is the demo https://codesandbox.io/p/sandbox/frosty-knuth-dlr3dp?file=%2Fsrc%2FApp.tsx You can check out the comment in MediaList.tsx line 39 Kindly check it out. @Alex Lohr
JCM
JCM14mo ago
I think that if you want to reuse the div's when replacing an array with another array having different content, you can use Index instead of For Conceptually For will reuse the dom element for elements in the array that didn't change. In the function rendering an element, the content supplied as value and the index is a signal as it might change it's location when array elements are added and removed. When inserting an element at index 0, it will create dom elements for that new element and all the others will be reused as they didn't change. Index on the other hand will always link the dom elements to the index array. In the function rendering an element, the index is a value, and the content is a signal (as it might change). When inserting an element at index 0, it will update the existing dom element, and will need to do the same for all others, since they shift down (and will need to create a new dom element for last item). Usually For is the safer default as it's probably more efficient on average. If your usual use case is to replace the whole content of the array, Index should perform better.
crowned
crownedOP14mo ago
Okay. I’ll try that out now.
Alex Lohr
Alex Lohr14mo ago
Sorry, was abroad for some hours. I'm checking it out.
crowned
crownedOP14mo ago
Okay. Thank you very much. I used the
Index
Index
but it doesn't work as expected. It only updates the UI when I fetch new data from the database to display. It doesn't update when I use previously saved data
Alex Lohr
Alex Lohr14mo ago
By the way, if you want a good example on how to shape the reactive state for a pagination, have a look at https://github.com/solidjs-community/solid-primitives/blob/main/packages/pagination/src/index.ts#L82-L242
GitHub
solid-primitives/packages/pagination/src/index.ts at main · solidjs...
A library of high-quality primitives that extend SolidJS reactivity. - solidjs-community/solid-primitives
Alex Lohr
Alex Lohr14mo ago
Index should update even on previously saved data, if you give it a new array with the previous objects.
crowned
crownedOP14mo ago
Okay. I'll check it out now. Maybe I should pass a function that returns the array? In the codesandbox, I included an apiDemo.json file so we have a fixed media signal.
Alex Lohr
Alex Lohr14mo ago
Here's a demo: https://primitives.solidjs.community/playground/pagination - unfortunately, the CSS for the demo is broken; I really need to fix that.
Solid Primitives
A library of high-quality primitives that extend SolidJS reactivity
crowned
crownedOP14mo ago
Okay, I'll try it out. @JCM I tried using a createMemo to create a new array but the Index still didn't work. https://codesandbox.io/p/sandbox/frosty-knuth-dlr3dp?file=%2Fsrc%2FMediaList.tsx%3A50%2C33 In the meantime, I'll work on implementing the pagination primitive.
JCM
JCM14mo ago
Index and For have behave differently internally, but the both render an array correctly. Swapping one for another can perform differently, but shouldn't change correctness. It looks like the problem is in MediaCard. You break reactivity by assigning props to local variables. I didn't show the problem in the For case as it was recreating the component from scratch, but it would show if you would use finer grained reactivity. In short, try fix MediaCard first. As it's a big example, I just skimmed over it; not sure I got all the details right.
crowned
crownedOP14mo ago
Okay, I understand. I'll fix it now. I'll memoize the derived values
andi
andi14mo ago
for a different idea from what has been mentioned: you could use a virtual scrolling/ list component the gist of it is that it only renders the elements that are in the viewport https://github.com/minht11/solid-virtual-container
joenano
joenano14mo ago
You need to create the cards outside the index/for, at the top level of the component for example, then they wont be rerenderd in the index/for loop
crowned
crownedOP14mo ago
Yeah but the issue is I will have to implement spatial-navigation soon and implementing virtual scrolling + spatial nav is going to take quite a while/be difficult to get right.
joenano
joenano14mo ago
i ran into this problem a few times
crowned
crownedOP14mo ago
Okay, but how do I update the cards when the data changes if they're not in the index/for?
joenano
joenano14mo ago
with a signal and createeffect then inside the index yous use {mediaCard} instead of <MediaCard ... />
crowned
crownedOP14mo ago
I don't really understand. Can I see what you mean? You can copy my code from the codesandbox and edit it here in discord
joenano
joenano14mo ago
where does the data change looks like your passing in a media prop that doesnt ever change inside the component
crowned
crownedOP14mo ago
The media prop in App.jsx never changes. But the property accessed by the MediaList page changes whenever you click on a Sidebar item.
joenano
joenano14mo ago
none of the other files are loading so I cant see whats going on, but if the data is changing outside mediaList, and medialist is rerendering on a signal, then it wont work because you rerunning that component every time and creating the list of cards every time You'll want to move your data fetching into the media list component so you dont have to rerender it every time.
crowned
crownedOP14mo ago
MediaList won't re-render since Solid doesn't re-render components Thank you @JCM and @Alex Lohr I was able to use fine-grained reactivity along with Index to better update the divs instead of re-rendering them. I have a better understanding of the term now. Now, another issue I want to bring up is that the page signal (which is updated when you click on a sidebar menu item) updates faster when I am not updating the 100 divs. I am outputting the signal to the screen (below the Categories heading in the sidebar). When I use the dummyData for the Index, the page signal updates faster because there are no other effects/memos to update in the UI.
const dummyData = Array(100).fill({})
<Index each={dummyData}></Index>
const dummyData = Array(100).fill({})
<Index each={dummyData}></Index>
But when I use the props.media array, it takes a while for the page UI output to update because 100 divs have to update along with it:
<Index each={props.media}></Index>
<Index each={props.media}></Index>
JCM
JCM14mo ago
Yes, when rendering big lists and facing performance issues, virtualization is the way to go. There is also: https://tanstack.com/virtual/v3
joenano
joenano14mo ago
it will rerender when the media signal in its props changes
crowned
crownedOP14mo ago
Okay. But don't you think virtual lists will interfere with spatial navigation? Also, how can I make it such that the page signal updates quickly while the media is still updating in the UI. Unless, I create 2 page signals. One for the MediaCards updating and one for the sidebar/other things I need to update quickly. It sounds weird to create 2 signals so I thought there may be a better way or something I'm missing
JCM
JCM14mo ago
Not sure what you mean with spatial navigation. If you use pagination, virtualization is probably not necessary as the amount of elements on the page won't be big. I have never combined virtualization with pagination, but it should work. Signals are synchronous, so if you call a signal setter like setPage, all the dom will be updated when you reach the next line of code (unless it's batched). Should there be data fetching in the background from the server that is asynchronous, a Resource it the standard way to deal with that.
crowned
crownedOP14mo ago
Spatial Navigation involves navigating the UI using keyboard keys (or a remote). It usually involves getting a map of all the available elements and determining the next best one to navigate to depending on the direction key/button pressed so a virtual-list would interfere with that. I'll implement the spatial-nav, then the virtual-list and see what happens. Yes, I understand that. But in the case that there are a 1001 elements to update, how do I make sure 1 specific element is updated before the rest. One way I thought of is by creating the illusion of a smoother UI by first rendering Skeleton Loading Cards before updating them to the actual cards. So I update the Sidebar first, then after that I update the MediaCards or something like that. What do you think? Is there a better/smarter way? For reference, I have a createResource in the original code that fetches the data for pages when there is no data to display. And since the Resource is async, the page signal updates instantly. But when trying to access already saved data in the media signal, there is a delay.
JCM
JCM14mo ago
Admittedly, I haven't spend much time looking at the example, so I'm not really sure I understand the problem correctly. But in the case that there are a 1001 elements to update, how do I make sure 1 specific element is updated before the rest. Unless I misunderstand the problem, I don't think you should aim for that. The interface should visualize the data in a consistent way (eg. data-> UI). If you need to order the updates in function of importance or urgency, it's getting messy. Paging and/or virtualization should fix the performance issues.
crowned
crownedOP14mo ago
Okay, thank you for the advice. That means I’ll look at ways I can get a smoother change which means I’ll look into the virtualization next, then transitions. Thank you to everyone who contributed and helped. 🤍
Want results from more Discord servers?
Add your server