Preventing Cells from re-rendering all child components

Hey everyone, just discovered Redwood.js and really like the project so far, and the community seems awesome, so great to meet you all!

In order to get to know the framework, I decided to write a simple little application which is basically just a list of places on one half of the screen, and a map with corresponding markers on the other half (similar to airbnb). The List component has pagination, so you are able to click through different pages to show different places. The problem I’m run into is that every time new dated is loaded in the Cell, every single child component is re-rendered (in the sense that both the <List> and <Map> components disappear and are replaced by the fallback text. Ideally when someone clicks on another page, the List and Map components should remain exactly the same, and the only changes that should be visible are directly in the <ul> <li> tags, which should show the newly fetched page data, and the markers on the map should also change with respect to the new data. But it seems as though the state of the child components is somehow lost each time a new query is made.

Is this just a side-effect of how Cells are designed? If anyone has some insights I would love to hear them, thanks guys!

2 Likes

Looks like some of the text in this post is missing, could you double check?

Included some html tags which discourse doesn’t like, thanks!

If you could share the code (or a reproducing sample) on GitHub, that would be useful in seeing where the update triggers.

@undertow Saw your question on the chat, somehow missed your answer to my question though. Sorry about that :frowning:

Here’s some context

me

Do you make a new query for new places when you select a new page?
If so, wouldn’t you want the map to rerender, to update with the new places?

@undertow

@Tobbe not exactly, and to be clear when i say re-render i mean the components are replaced with the fallback value. At the moment, when you click for the next page in the list, the whole List component, as well as the whole Map component are redrawing on the screen. With airbnb, those parts remain, and all you see is the list items and markers changing, but for me the whole component and its contents change at the moment
Put another way, the only components that should be “redrawing” is those that actually contain the updated data at the lowest possible level. For example, in my component, that should only be the Items component in <List><Search/><Filter/><Items/></List>. And for the Map, the only thing that should redraw is the markers themselves (not any other UI, like zoom buttons)

I think one thing you could do is split it up in more Cells. It sound like you have just one cell now that wraps both the list and the map. Correct?

Try having one cell inside the list, and another cell inside the map. Would that help? That way the map for example wouldn’t be re-rendered when the cell got new data

So, in your <List><Search/><Filter/><Items/></List>-example, how about doing something like this (conceptual pseudocode) <List><Search/><Filter/><Cell><Items/></Cell></List>

No worries Tobbe!

I thought about going this route, but the only thing i unsure of is if I would have to make 2 separate (but identical) queries, one for the list and one for the map. Didn’t seem that DRY, so i had some reservations. Or am i misunderstanding how cells work and one wouldn’t in fact need to make the same query twice?

And here’s a brief gist of the code: dpaste: BEN6UCGS3

oh and PrimaryLayout is wrapped in the default Redwood components, as well RecoilRoot.
There are some other little bugs which my non-redwood version didn’t exhibit, such as my Search and Filter components not retaining state, as well is issues with marker clusters retaining their state (clicked vs not). But i’m guessing these issues all have the same root cause.

I wouldn’t worry about duplicating the query. Your gql client should handle caching that, so it should be super fast

While the Cell is reloading, you’ll see the Loading component instead of any content there. This is default behaviour. As @Tobbe mentioned, you could just get the data where you use your data, to fragment the loading display.

As it currently stands, redwood does not handle a stale-while-refetch case, see:

I didn’t even know that graphql provides caching, that solves the “inefficiency” concern I had then.
Really appreciate the advice guys, i’ll try using separate cells for List and Map when I get home, and give an update if it works!

All that would be needed to support that would be to pass data to <Loading />, right?

stale-while-refetch could be implemented simply by swapping if (data) and if (loading).
the Success component may also take isLoading if stale visualisation is to be achieved.

Without an indication of isLoading, the user may interact with a soon-to-be-replaced state.

I was thinking something like

Loading = (data) => (
  <Success loading={true} ...data />
)

This could also work, and pretty much a matter of preference. Success could then be more appropriately called DataView or similar? Renaming might be a breaking change, but the behaviour change could also lead to subverted expectations from users.

Hey guys, just wanted to write back letting you know that splitting the Map cell into sub cells (one cell for each component which needs to re-render) worked great, thanks again for the advice. Is this the method that should be used every time you have a number of components which use the same data but where you want to prevent re-rendering? Or are you thinking about making some changes to the framework to better facilitate this?

We are thinking about making some changes to the framework, so you will have the option to do fetching in both places, or in the parent.

Awesome, looking forward to seeing what you come up with!

It’s a start: Stale while Fetch by Krisztiaan · Pull Request #1878 · redwoodjs/redwood · GitHub