Value Notifier com Pattern State

Edson Melo Souza
Flutter Brasil
Published in
3 min read6 days ago

No ultimo post sobre ValueNotifier falamos de forma mais abstrata, por isso, nesse post irei detalha mais sobre ValueNotifier e State Pattern juntos. Vamos la?

Vamos recapitular rapidamente. As sintaxes mais utilizadas para a criação do ValueNotifier são as seguintes:


class TodoController {
final todoNotifier = ValueNotifier<List<TodoModel>>([])
//final anyThingNotifierHere = ValueNotifier<AnyThing>([])

Future<void> loadTodos() {
todoNotifier.value = []; // Todo models adicionados aqui
}

}

Ou

class TodoController extends ValueNotifier<List<TodoModel>> {
TodoController(): super([]);

Future<void> loadTodos() {
value = [] // Todo models adicionados aqui
}
}

No entanto, neste post, utilizaremos mais essa segunda abordagem. Então, vamos lá.

Gosto muito da explicação do guru sobre o padrão State, mas vou resumir de forma sucinta aqui. O padrão State nada mais é do que definir os diferentes momentos da aplicação. Como assim? Vou explicar com mais detalhes abaixo. Por exemplo, temos uma tela que carrega “Todos”, e nessa tela podemos determinar que ela terá diferentes momentos/estados:

  • START -> Este é o momento inicial da nossa tela.
  • LOADING -> Este é o momento de carregamento (geralmente colocamos um CircularProgressIndicator ou algo semelhante).
  • LOADED -> Aqui o carregamento (LOADING) terminou e já temos os nossos “Todos”.
  • ERROR -> Aqui o carregamento (LOADING) terminou, mas ocorreu algum problema.

Aqui está traduzido para o código:

sealed class TodoState {}

//Estado START
class TodoStateStart extends TodoState {}

// Estado LOADING
class TodoStateLoading extends TodoState {

}

// Estado de LOADED
class TodoStateLoaded extends TodoState {
final List<TodoModel> todos;

TodoStateLoading({
required this.todos,
});
}

// Estado de ERROR
class TodoStateError extends TodoState {
final String message;
TodoStateError({
required message,
});
}

Vamos utilizar isso em conjunto com ValueNotifier:

class TodoController extends ValueNotifier<TodoState> {
Todocontroller(): super(TodoStateStart());

Future<void> loadTodos() {
try {
value = TodoStateLoading();
// requiscao à alguma fonte de dados aqui
value = TodoStateLoaded(todos: [TodoModel(title: "Teste")]);
} on ErroTal catch (erro) {
value = TodoStateError(message: erro.message);
}
}
}

Você pode observar que, no ValueNotifier, aplicamos o conceito de polimorfismo na prática utilizando o tipo base TodoState. Dessa forma, podemos usar diferentes formas que estendem a classe base, como TodoStateLoading, TodoStateLoaded, entre outras.

class MyWidget extends StatefulWidget {
const MyWidget({super.key});

@override
State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget>
with SingleTickerProviderStateMixin {
final todoController = TodoController();

@override
Widget build(BuildContext context) {
return ValueListenableBuilder(
valueListenable: todoController,
builder: (BuildContext context, value, Widget? child) {
final state = value;
if (state is TodoStateLoading) {
return const CircularProgressIndicator();
}

if (state is TodoStateError) {
return Text(state.message);
}

if (state is TodoStateSuccess) {
return ListView.builder(
itemCount: state.todos.length,
itemBuilder: (BuildContext context, int index) {
final todo = state.todos[index];
return ListTile(
title: Text(todo.title),
);
},
);
}
},
);
}
}

Como você pode ver acima, podemos usar o padrão State para controlar o que será mostrado em cada estado. Na minha modesta opinião, isso é muito bonito e funcional.

Você pode ter acesso a mais conteúdo gratuito e de qualidade como este entrando na comunidade FlutterBrasil, para uma melhor imersão no mundo do Flutter. Espero que tenha gostado. Meu nome é Edson, do Flutter Brasil, e te vejo no próximo artigo. Até logo!

--

--

Edson Melo Souza
Flutter Brasil

Programador Mobile flutter, react native, kotlin para android e typescript. Apaixonado pelas melhores tecnologias do mercado.