Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add preload/2 that accepts list of previous assigns #2362

Closed
wants to merge 1 commit into from

Conversation

dvic
Copy link
Contributor

@dvic dvic commented Dec 17, 2022

Fixes #2357

@dvic
Copy link
Contributor Author

dvic commented Dec 17, 2022

@josevalim I took a stab at the preload/2 idea. If this PR is good to go then I can write some docs around it. How do you want to approach that? Leave the examples with preload/1 or rewrite to make use of preload/2?

@dvic
Copy link
Contributor Author

dvic commented Feb 28, 2023

@josevalim maybe this has now become obsolete / less relevant now that we have streams? My original usecase was that I wanted to differentiate between newly added and existing livecomponents in a list. But after reading https://fly.io/phoenix-files/phoenix-dev-blog-streams/ I guess lists won't be using (in most cases) live components at all?

@josevalim
Copy link
Member

Hi @dvic, sorry for the delay. I was not happy with the current proposal but I could not elaborate on why, so I left it in the "tinkering folder" in lieu of giving incomplete feedback.

It is up to you if you think streams resolve this, but I think I was finally able to come up with a better API than the one that exists today that also addresses your problem.

The issue with preload/upload dance is that you have to manage assigns in two different but deeply connected places: preload/1 and update/2. My proposal, therefore, is to introduce update_many/2.

A LiveView may implement either update_many/2 or update/2. The many version, it receives a list of assigns and a list of sockets. It must return a list of sockets in the same order that is given. The default implementation of update_many is something akin to:

def update_many(assigns, sockets) do
  assigns = preload(assigns)
  Enum.zip_with(assigns, sockets, fn assigns, socket -> update(assigns, socket) end)
end

I think this would simplify your use case considerably and be generally more flexible. preload could be deprecated in the long term. Thoughts?

@dvic
Copy link
Contributor Author

dvic commented Mar 16, 2023

Hi @dvic, sorry for the delay. I was not happy with the current proposal but I could not elaborate on why, so I left it in the "tinkering folder" in lieu of giving incomplete feedback.

No worries!

It is up to you if you think streams resolve this, but I think I was finally able to come up with a better API than the one that exists today that also addresses your problem.

The issue with preload/upload dance is that you have to manage assigns in two different but deeply connected places: preload/1 and update/2. My proposal, therefore, is to introduce update_many/2.

A LiveView may implement either update_many/2 or update/2. The many version, it receives a list of assigns and a list of sockets. It must return a list of sockets in the same order that is given. The default implementation of update_many is something akin to:

def update_many(assigns, sockets) do
  assigns = preload(assigns)
  Enum.zip_with(assigns, sockets, fn assigns, socket -> update(assigns, socket) end)
end

I think this would simplify your use case considerably and be generally more flexible. preload could be deprecated in the long term. Thoughts?

Interesting. This indeed solves the issue and I think that the API is more elegant as well.

However, as an upgrade path, wouldn't you want to allow either update_many/2 or preload/1 and always allow update/2? LiveView would then always be able to call update_many/2, which is either a generated one or a user implemented one. The generated implementation is then equal to the above. In this case a default update/2 is also generated, but this is already the case right?

In any case, implementation details aside, I think this is a good idea 👍 Curious to hear what others think about this!

@josevalim
Copy link
Member

For the upgrade path, update_many will always replace both preload+update. So if you define it, none of them would be called. But we want to avoid generating code into the user module and rely on function_exported? checks instead.

@dvic
Copy link
Contributor Author

dvic commented Jul 14, 2023

Closing this for now. If there's interest I can reserve some time for the update_many/2 approach 👍

@dvic dvic closed this Jul 14, 2023
@josevalim
Copy link
Member

Thank you @dvic. This is in the back of my mind but i don’t want to commit to anything yet before we address the LC and LV communication.

@josevalim
Copy link
Member

Hi @dvic, sorry for the delay in here. We would like to go ahead with update_many, can you please send a PR? You must either use update_many or preload+update. If preload is defined, we will emit a deprecation warning telling you to use update_many.

Also, we want to support send_update(@myself, assigns) as well. Would you like to send a PR for that too? :) Unrelated but I thought I would ask.

@dvic
Copy link
Contributor Author

dvic commented Jul 17, 2023

Hi @dvic, sorry for the delay in here. We would like to go ahead with update_many, can you please send a PR? You must either use update_many or preload+update. If preload is defined, we will emit a deprecation warning telling you to use update_many.

No worries, I'll pick this up! You can expect a PR this week.

Also, we want to support send_update(@myself, assigns) as well. Would you like to send a PR for that too? :) Unrelated but I thought I would ask.

Sure! I read the discussion earlier, this would indeed help a lot 👍 I'll send a separate PR for this.

@josevalim
Copy link
Member

Btw, ping :)

@dvic
Copy link
Contributor Author

dvic commented Aug 15, 2023

Btw, ping :)

Haven't forgotten about it, added a wip pr #2771

I found there are some sharp edges in adding this functionality without inserting user code. So what I did for now is update Utils.maybe_call_update! and Diff.maybe_call_preload and then in render_pending_components I have to rewrite the code to collect the sockets (if update_many is implemented) instead of the current reduce function, that's where I'm left :)

@dvic dvic mentioned this pull request Aug 15, 2023
4 tasks
@dvic dvic deleted the support-preload2 branch August 15, 2023 17:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

preload does not receive existing assigns
2 participants