Veja como esconder e exibir componentes de forma reativa com Show.when
Veja como esconder e exibir componentes de forma reativa com Show.when
Nos posts anteriores da série vimos o State puro (contador) e o ComputedState (tamanho de texto). Agora vamos ver um padrão diferente, mas igualmente essencial em qualquer UI: mostrar ou esconder um componente inteiro dependendo de uma condição. No Megalodonte, isso é resolvido com o Show.when.
O exemplo de hoje é bem lúdico: um jogo de "esconde-esconde" simples. Um botão, e um texto que aparece e desaparece cada vez que você clica nele.
O problema
Em UIs imperativas, esconder um componente normalmente envolve chamar algo como setVisible(false) ou remover manualmente o nó da árvore de renderização — e depois lembrar de recolocá-lo de volta corretamente quando a condição mudar. É fácil esquecer um caso, ou deixar o componente "vivo" (consumindo memória, escutando eventos) mesmo quando está invisível.
Com Show.when, você declara a condição, e o framework decide quando montar e desmontar o componente.
O código
Main.java — o mesmo ponto de entrada padrão dos exemplos anteriores:
package my_app;
import megalodonte.ListenerManager;
import megalodonte.application.MegalodonteApp;
import megalodonte.base.theme.ThemeManager;
import megalodonte.theme.DefaultTheme;
public class Main {
static void main() {
ThemeManager.setTheme(new DefaultTheme());
MegalodonteApp.run(context -> context.useView(new HomeScreen()), ev->{
if(ev == MegalodonteApp.Event.CloseRequest){
System.out.println("Clicked on X - close application");
ListenerManager.disposeAll();
}
});
}
}
HomeScreen.java — onde o Show.when entra em ação:
package my_app;
import megalodonte.base.components.Component;
import megalodonte.base.components.ScreenComponent;
import megalodonte.base.state.State;
import megalodonte.components.Button;
import megalodonte.components.Text;
import megalodonte.components.layout_components.Container;
import megalodonte.props.ContainerProps;
import megalodonte.v2.Show;
public class HomeScreen implements ScreenComponent {
State<Boolean> isVisible = new State<>(false);
@Override
public Component render() {
return new Container(new ContainerProps().paddingAll(25))
.children(
new Button("Hide and seek - game").onClick(this::toggleVisibility),
Show.when(isVisible, ()-> new Text("You catch me"))
);
}
void toggleVisibility(){
isVisible.set(!isVisible.get());
}
}
Como funciona, na prática
isVisibleé umState<Boolean>comum — o mesmo tipo de estado que já usamos no contador, só que guardandotrue/falseem vez de um número.Show.when(isVisible, () -> new Text("You catch me"))recebe o estado booleano e uma função (Supplier<Component>) que constrói o componente a ser exibido. EnquantoisVisibleforfalse, oTextnem chega a ser criado. Quando viratrue, oShowchama a função, monta o componente e o insere na tela.- O método
toggleVisibility()só inverte o valor booleano comisVisible.set(!isVisible.get()). Ele não sabe (nem precisa saber) que existe um componente sendo mostrado ou escondido — só muda o estado, e a UI reage. - Como essa é a variante reativa do
Show.when(que recebe umState<Boolean>, e não umbooleanfixo), o framework reavalia a condição toda vez que o estado muda — é isso que permite o clique no botão alternar a visibilidade infinitamente.
Por que isso importa
Esse padrão é a base de praticamente qualquer UI condicional: mensagens de erro que só aparecem quando há um erro, painéis que se expandem/recolhem, campos de formulário que dependem de uma escolha anterior, loaders que somem quando os dados chegam. Em vez de gerenciar visibilidade manualmente, você declara "isso aparece quando X é verdadeiro" e deixa o framework cuidar do resto.
Publiquei também a versão desse post no Reddit, com mais contexto sobre o ecossistema Megalodonte:
Link do post no Reddit: https://www.reddit.com/r/JavaFX/s/ndzLI534Ym