Pre-order

Compositions

Inheritance is a useful tool for managing the complexity of Phlex views and components, but it can also lead to tight coupling and make it difficult to reuse components across different contexts. Compositions, on the other hand, offer a flexible and modular approach to building complex views.

Recall the Card component we created earlier.

class Card < Phlex::Component
  def around_template(&)
    super do
      div(class: "p-4 shadow rounded bg-color-neutral-100", &)
    end
  end

  # Having only a yield in the method will render whatever is passed into it
  # from the rendering call.
  def view_template
    yield
  end
end

Then we started constructing the ProfileCard component, which actually mixes several concerns poorly.

🔓 Unlock content

Pre-order this course to unlock this video, source code, and content.

Pre-order video course for $379 $249
class ProfileCard < ▓▓▓▓
  def ▓▓▓▓▓(&)
    ▓▓▓(class: "text-xl font-bold", &)
  end

  def ▓▓▓▓(&)
    ▓▓(&)
  end

  def ▓▓▓▓(name, &)
    ▓▓(class: "font-bold") { name }
    ▓▓ { yield }
  end

  def ▓▓▓▓▓▓▓▓▓▓▓▓▓
    yield
  end
end

▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓ ▓▓▓▓ ▓▓▓▓▓▓▓▓ ▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓

Decouple ProfileCard from Card

▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓

class ProfileCard < ▓▓▓▓▓▓▓▓▓::▓▓▓▓
  def ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓(&)
    super { ▓▓▓▓▓▓ ▓▓▓▓.▓▓▓(&)}
  end

  def ▓▓▓▓▓(&)
    ▓▓▓(class: "text-xl font-bold", &)
  end

  def ▓▓▓▓(&)
    ▓▓(&)
  end

  def ▓▓▓▓(name, &)
    ▓▓(class: "font-bold") { name }
    ▓▓ { yield }
  end

  def ▓▓▓▓▓▓▓▓▓▓▓▓▓
    yield
  end
end

▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓▓ ▓▓ ▓▓▓ ▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓ ▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓ ▓▓ ▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓ ▓ ▓▓▓▓▓

Extract List Component

▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓▓ ▓ ▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓

class List < ▓▓▓▓▓▓▓▓▓::▓▓▓▓
  def ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓(&)
    super { ▓▓(&)}
  end

  def ▓▓▓▓(name, &)
    ▓▓(class: "font-bold") { name }
    ▓▓ { yield }
  end

  def ▓▓▓▓▓▓▓▓▓▓▓▓▓
    yield
  end
end

▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓ ▓▓▓▓ ▓▓▓▓▓▓▓

class ProfileCard < ▓▓▓▓▓▓▓▓▓::▓▓▓▓
  def ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓(&)
    super { ▓▓▓▓▓▓ ▓▓▓▓.▓▓▓(&)}
  end

  def ▓▓▓▓▓(&)
    ▓▓▓(class: "text-xl font-bold", &)
  end

  def ▓▓▓▓(&)
    ▓▓▓▓▓▓ ▓▓▓▓.▓▓▓(&)
  end

  def ▓▓▓▓▓▓▓▓▓▓▓▓▓
    yield
  end
end

▓▓▓ ▓▓▓▓▓ ▓▓▓▓ ▓▓ ▓▓▓▓ ▓▓▓▓

<%= ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓.▓▓▓ do |▓▓▓▓|
  ▓▓▓▓.▓▓▓▓▓ { "Profile" }
  ▓▓▓▓.▓▓▓▓ do |▓▓▓▓|
    ▓▓▓▓.▓▓▓▓("Name") { "John Doe" }
    ▓▓▓▓.▓▓▓▓("Email") { "john@example.com" }
  end
end %>

▓▓▓ ▓▓▓▓

Eliminate render boilerplate

▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓ ▓▓▓▓ ▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓ ▓▓▓▓▓ ▓▓ ▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓ ▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓▓▓ ▓ ▓▓▓ ▓▓ ▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓ ▓▓ ▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓

▓ ▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓
module Components
  extend ▓▓▓▓▓::▓▓▓
end

▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓

▓▓▓▓▓▓ ▓▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓

class ProfileCard < ▓▓▓▓▓▓▓▓▓::▓▓▓▓
  def ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓(&)
    super { ▓▓▓▓(&)}
  end

  def ▓▓▓▓▓(&)
    ▓▓▓(class: "text-xl font-bold", &)
  end

  def ▓▓▓▓(&)
    ▓▓▓▓(&)
  end

  def ▓▓▓▓▓▓▓▓▓▓▓▓▓
    yield
  end
end