@@ -776,49 +776,63 @@ defmodule Phoenix.LiveView.Engine do
776776 # Rewrite slots in static parts
777777 static = slots_to_rendered ( static , vars , caller , Keyword . get ( meta , :slots , [ ] ) )
778778
779- cond do
780- # We can optimize when there are static parts and no dynamic parts.
781- # We skip live components because they have their own tracking.
782- static_extra != [ ] and dynamic == % { } and
783- not match? ( { :& , _ , [ { :/ , _ , [ { :live_component , _ , _ } , 1 ] } ] } , fun ) ->
784- keys =
785- for { key , value } <- static_extra ,
786- # We pass empty assigns because if this code is rendered,
787- # it means that upstream assigns were change tracked.
788- { _ , keys , _ } = analyze_and_return_tainted_keys ( value , vars , % { } , caller ) ,
789- # If keys are empty, it is never changed.
790- keys != % { } ,
791- do: { key , to_component_keys ( keys ) }
792-
793- # [id: [changed: [:id]], children: [vars_changed: [:children]]]
794- # -> [changed: [:id], vars_changed: [:children]]
795- vars_changed_keys =
796- Enum . flat_map ( keys , fn
797- { _assign , :all } -> [ ]
798- { _assign , keys } -> keys
799- end )
800-
801- static_changed =
802- quote do
803- unquote ( __MODULE__ ) . to_component_static (
804- unquote ( keys ) ,
805- unquote ( @ assigns_var ) ,
806- changed ,
807- % { unquote_splicing ( vars_changed_vars ( vars_changed_keys ) ) } ,
808- vars_changed
809- )
810- end
779+ static =
780+ cond do
781+ # Live components have their own tracking, so we skip the logic below
782+ match? ( { :& , _ , [ { :/ , _ , [ { :live_component , _ , _ } , 1 ] } ] } , fun ) ->
783+ static
784+
785+ # Compute change tracking for static parts
786+ static_extra != [ ] and ( dynamic == % { } or without_dependencies? ( dynamic , vars , caller ) ) ->
787+ keys =
788+ for { key , value } <- static_extra ,
789+ # We pass empty assigns because if this code is rendered,
790+ # it means that upstream assigns were change tracked.
791+ { _ , keys , _ } = analyze_and_return_tainted_keys ( value , vars , % { } , caller ) ,
792+ # If keys are empty, it is never changed.
793+ keys != % { } ,
794+ do: { key , to_component_keys ( keys ) }
795+
796+ # [id: [changed: [:id]], children: [vars_changed: [:children]]]
797+ # -> [changed: [:id], vars_changed: [:children]]
798+ vars_changed_keys =
799+ Enum . flat_map ( keys , fn
800+ { _assign , :all } -> [ ]
801+ { _assign , keys } -> keys
802+ end )
803+
804+ static_changed =
805+ quote do
806+ unquote ( __MODULE__ ) . to_component_static (
807+ unquote ( keys ) ,
808+ unquote ( @ assigns_var ) ,
809+ changed ,
810+ % { unquote_splicing ( vars_changed_vars ( vars_changed_keys ) ) } ,
811+ vars_changed
812+ )
813+ end
811814
812- quote do: % { unquote_splicing ( [ __changed__: static_changed ] ++ static ) }
815+ [ __changed__: static_changed ] ++ static
813816
814- dynamic == % { } ->
815- quote do: % { unquote_splicing ( static ) }
817+ true ->
818+ # We must disable change tracking when there is a non empty dynamic part
819+ # (for example `<.my_component {assigns}>`) in case the parent assigns
820+ # already contain a `__changed__` key
821+ [ __changed__: nil ] ++ static
822+ end
816823
817- true ->
818- quote do: Map . merge ( unquote ( dynamic ) , % { unquote_splicing ( static ) } )
824+ if dynamic == % { } do
825+ quote do: % { unquote_splicing ( static ) }
826+ else
827+ quote do: Map . merge ( unquote ( dynamic ) , % { unquote_splicing ( static ) } )
819828 end
820829 end
821830
831+ defp without_dependencies? ( ast , vars , caller ) do
832+ { _ , keys , _ } = analyze_and_return_tainted_keys ( ast , vars , % { } , caller )
833+ keys == % { }
834+ end
835+
822836 defp to_component_keys ( :all ) , do: :all
823837 defp to_component_keys ( map ) , do: Map . keys ( map )
824838
0 commit comments