Componentes
Renderizando listas com slots
Tempo de leitura: 3 minutos
Imagine que você está construindo uma aplicação que lista termos de boxing. Sua implementação inicial se parece muito como o código abaixo:
Mix.install([
{:liveview_playground, "~> 0.1.5"}
])
defmodule PageLive do
use LiveviewPlaygroundWeb, :live_view
def mount(_params, _session, socket) do
boxing_terms = [
%{term: "Jab", definition: "A quick, straight punch thrown with the lead hand."},
%{
term: "Hook",
definition:
"A punch thrown in a circular motion targeting the side of the opponent's head or body."
},
%{
term: "Cross",
definition:
"A powerful punch thrown with the rear hand across the body, traveling straight toward the opponent."
}
]
socket = assign(socket, boxing_terms: boxing_terms)
{:ok, socket}
end
def render(assigns) do
~H"""
<dl class="max-w-xs mx-auto">
<div class="grid grid-cols-1 gap-y-2">
<div :for={item <- @boxing_terms} class="border-b border-gray-300">
<dt class="text-lg font-semibold"><%= item.term %></dt>
<dd class="text-gray-600"><%= item.definition %></dd>
</div>
</div>
</dl>
"""
end
end
LiveviewPlayground.start(scripts: ["https://cdn.tailwindcss.com"])
Até aqui nada que você não tenha visto. Um assign para definir a lista de termos, um loop usando o atributo especial :for
e cada item sendo renderizado. Porém, devido às aulas anteriores, você nota que você poderia simplificar um pouco mais esse código gerando um componente para esconder todas essas classes e, ao mesmo tempo, ter uma reusabilidade maior no seu <dl>
.
#Misturando slots e listas
Até então nossos slots só renderizavam um único elemento. Seja um título ou um subtítulo, não havia nenhum loop envolvido. Vamos aprender como combinar listas e slots. Crie e execute um arquivo chamado rendering_slot_list.exs
:
Mix.install([
{:liveview_playground, "~> 0.1.5"}
])
defmodule CoreComponents do
use LiveviewPlaygroundWeb, :html
attr :terms, :list, required: true
slot :dt, required: true
slot :dd, required: true
def dl(assigns) do
~H"""
<dl class="max-w-xs mx-auto">
<div class="grid grid-cols-1 gap-y-2">
<div :for={item <- @terms} class="border-b border-gray-300">
<dt class="text-lg font-semibold"><%= render_slot(@dt, item) %></dt>
<dd class="text-gray-600"><%= render_slot(@dd, item) %></dd>
</div>
</div>
</dl>
"""
end
end
defmodule PageLive do
use LiveviewPlaygroundWeb, :live_view
import CoreComponents
def mount(_params, _session, socket) do
boxing_terms = [
%{term: "Jab", definition: "A quick, straight punch thrown with the lead hand."},
%{
term: "Hook",
definition:
"A punch thrown in a circular motion targeting the side of the opponent's head or body."
},
%{
term: "Cross",
definition:
"A powerful punch thrown with the rear hand across the body, traveling straight toward the opponent."
}
]
socket = assign(socket, boxing_terms: boxing_terms)
{:ok, socket}
end
def render(assigns) do
~H"""
<.dl terms={@boxing_terms}>
<:dt :let={item}><%= item.term %></:dt>
<:dd :let={item}><%= item.definition %></:dd>
</.dl>
"""
end
end
LiveviewPlayground.start(scripts: ["https://cdn.tailwindcss.com"])
Mais uma vez usando a ideia de CoreComponents
criamos um componente chamado <.dl>
para deixar claro que esta é a nossa versão da tag HTML <dl>
. Também escolhemos o nome dos nossos slots de modo a imitar o HTML: <:dt>
(description term) e <:dd>
(description detail).
O componente em sí não é muito diferente do que você já viu anteriormente. Usamos um loop com :for
e para cada elemento nós usamos a função render_slot/2
. A diferença é que desta vez passamos um segundo argumento para essa função: o item atual do loop.
Quando um segundo argumento é passado para o render_slot/2
, na utilização do slot podemos usar o atributo especial :let={var}
para armazenar o elemento atual em var
. Deste modo, conseguimos simplificar um componente que trabalha com loops e tornamos nossa render/1
da LiveView extremamente enxuta.
#Resumindo!
- Você pode simplificar loops criando componentes.
-
Slots podem receber variáveis de loop passando elas no segundo argumento de
render_slot/2
e recebendo no slot com:let={nome_da_var}
. - Usar slots e componentes contribui em deixar o código das suas LiveViews mais enxutos.
Feedback
Você tem algum feedback sobre esta página? Conte-nos!