we have pretty old(autumn 2019) Phoenix LiveView module. I’m going to do refactoring of some logic inside. I will move some logic to own modules, contexts, etc. But it will be still fat module.
Current details:
LoC: 698
fn handle_* : 34
assign(*): 56
There is a lot of communication between frontend and backend. There is a lot of 3rd party JS libs and a lot of combinations. But it’s simple one page site where we generate some forms, js elements depends on current visitor configuration or data object setup.
So my question is: How can I remove this complexity of fat PhLV logic? We tried to create more LV with live_redirect but it’s not good idea for our use case. It’s question more about code readability than about domain/business logic. So I’m looking forward for some ideas or experience with this issue.
thanks, I was thinking about it. I take about 1 hour yesterday and I figured out that is not good solution for me. Because when something is changed inside Component, whole component is re-rendered. And it’s not possible in my use case. Some “components” are stateful in frontend. For example 3rd party js sdk “iframe” is generated. So in case something is changed for this LV Component it would be re-render specific div. This div contain temporary stored data from JS SDK or iframe. So ti would be closed and I lost state.
It would be perfect to use components but I have to change html or re-render component only if I want to. Yes, I don’t have to give update to component when I don’t want. But it would be same issue what I have now. Huge parent LV and component would be just simple dump nested template.
Yes, that’s true but I think phx-update=“ignore” will still re-render component on backend. Not sure.
But I already started with another approach.
I had something like this:
def handle_event("vendor1_some_event", %{ "somethign" => data}, socket) do
def handle_info({:vendor_1_another_event, some_data}, socket) do
So I had specific handlers for every event or message for vendors in LiveView module. This created that mess. I’m going to move all of these into 2 generic handlers. Something like this:
def handle_event( vendor_event, data, socket) do
assigns = VendorResolver.handle_event(vendor_event, data, socket.assigns)
{:noreply, %{socket | assigns: assigns}}
end
Similar for handle_info. VendorResolver will pattern match vendor and call function from vendor integration module. So I should have just 2 handlers after this kind of refactoring. Or I hope so. I will see how it will go. This should change how we add new vendor. Dev will have to do less changes. Just add new module with integration, add it to resolver and add template. At the end VendorResolver is not own module. It’s:
Vendors (Resolver)
Vendors.Vendor1
Vendors.VendorN
There is still some parts which I haven’t resolved. For example when I need send message to LiveView module from integration module. Process.send_after/4 should work but…