Skip to content

Latest commit

 

History

History
370 lines (250 loc) · 13.5 KB

README.md

File metadata and controls

370 lines (250 loc) · 13.5 KB

Idiomas: English | Português | Chinese

mobx.dart



pub package pub package pub package

Build Status Publish Coverage Status Netlify Status

Join the chat at https://discord.gg/dNHY52k

MobX para a Linguagem Dart.

Evolua a Gerência de Estado dos seus App Dart com o Transparent Functional Reactive Programming (TFRP)

Introdução

O MobX é uma biblioteca de gerenciamento de estado que simplifica a conexão dos dados reativos do seu aplicativo com a interface do usuário. Essa integração é completamente automática e parece muito natural. Como desenvolvedor de aplicativos, você se concentra exclusivamente em quais dados reativos precisam ser consumidos na interface do usuário (e em outros lugares) sem se preocupar em manter os dois sincronizados.

Não fazemos "mágica", apenas temos objetos inteligentes que se preparam para serem consumidos (observables), e as (reactions) os rastreia automaticamente para você. quando o observables mudam, todas as reactions são chamadas. O interessante é que as reactions podem ser qualquer coisa, desde um simples log do console, uma chamada de rede ou até mesmo uma renderização da interface do usuário.

MobX tem sido uma biblioteca muito eficiente para o javascript esse porte visa trazer essa mesma produtividade para os apps baseados em Dart

Patrocinadores

Somos muito gratos aos nossos patrocinadores por nos tornar parte do programa Open Source Software (OSS).

Começando

Acompanhe esse Guia de introdução ao MobX (em inglês).

Aprofundando

Para uma visão mais profunda do MobX, veja o MobX Quick Start Guide. Embora o livro use a versão JavaScript do MobX, os conceitos são 100% aplicáveis ao Dart e Flutter.

Conceitos Principais

MobX Triad

Temos 3 conceitos principais no MobX: Observables, Actions e Reactions.

Observables

Observables representam o reactive-state de sua aplicação. Eles são simples e escalares, mesmo em uma árvore de objetos complexa. Você pode expor sua árvore de observáveis que podem ser consumidas por outros Observables ou pela UI.

Um "contador reativo" pode ser representado pelo seguinte Observable

import 'package:mobx/mobx.dart';

final counter = Observable(0);

Também podem ser criados Observable mais complexos usando Classes(Orientação a Objetos):

class Counter {
  Counter() {
    increment = Action(_increment);
  }

  final _value = Observable(0);
  int get value => _value.value;
  set value(int newValue) => _value.value = newValue;

  Action increment;
  void _increment() {
    _value.value++;
  }
}

A primeira vista pode parecer algo verboso, por isso criamos mobx_codegen que permite substituir o código acima pelo seguinte:

import 'package:mobx/mobx.dart';

part 'counter.g.dart';

class Counter = CounterBase with _$Counter;

abstract class CounterBase with Store {
  @observable
  int value = 0;

  @action
  void increment() {
    value++;
  }
}

Agora, basta usar a anotação @Obsevable em uma propriedade da Classe, e sim! temos outros metadados para serem usados como cabeçalho neste boilerplate, porém eles são fixos e funcionam em qualquer tipo de classe. A medida que for criando classes mais complexas, esse boilerplate parecerá não existir, e você dará mais foco no escopo de sua regra.

Nota: Essas Anotações estão disponíveis no pacote mobx_codegen.

Computed Observables

O que pode ser derivado, deve ser derivado. Automaticamente.

O estado de sua aplicação consiste em core-state e derived-state. O core-state é o estado referente ao dominio ao qual você está lidando. Por exemplo, se você tiver uma entidade chamada Contact , as propriedades firstName e lastName formam o core-state do Contact. No entanto, fullName é um derived-state, obtido pela combinação do firstName e do lastName.

Esse derived state que depende do core-state ou de outro derived-state é chamado de Computed Observable. Ele muda automaticamente quando seus Observables são alterados.

Estado no MobX = Core-State + Derived-State

import 'package:mobx/mobx.dart';

part 'contact.g.dart';

class Contact = ContactBase with _$Contact;

abstract class ContactBase with Store {
  @observable
  String firstName;

  @observable
  String lastName;

  @computed
  String get fullName => '$firstName, $lastName';

}

No exemplo acima, fullName é sincronizado automaticamente quando há uma alteração no firstName e/ou lastName.

Actions

Actions é a forma como mudamos os nossos observables. Em vez de modificá-los diretamente, as actions adicionam mais significado semântico nas mudanças. Por exemplo, em vez de simplesmente chamar value++, seria melhor chamar um Action increment() pois faz mais sentido. Além disso, as actions também agrupam todas as notificações e garantem que as alterações sejam notificadas somente após a conclusão. Assim, os observables são notificados somente após a conclusão atômica da ação.

Observe que as ações também podem ser aninhadas; nesse caso, as notificações são enviadas quando a ação mais avançada é concluída.

final counter = Observable(0);

final increment = Action((){
  counter.value++;
});

Use a anotação @action para criar uma Ação na sua classe!

import 'package:mobx/mobx.dart';

part 'counter.g.dart';

class Counter = CounterBase with _$Counter;

abstract class CounterBase with Store {
  @observable
  int value = 0;

  @action
  void increment() {
    value++;
  }
}

Asynchronous Actions

MobX.dart já lida automaticamente com métodos assíncrono sem a necessidade de alguma outra ferramenta. runInAction.

@observable
String stuff = '';

@observable
loading = false;

@action
Future<void> loadStuff() async {
  loading = true; // Isso notifica os observadores
  stuff = await fetchStuff();
  loading = false; //Isso também notifica os observadores
}

Reactions

Reactions completa a Tríade do MobX (observables, actions and reactions). Eles são os observadores do nosso sistema reativo e notificam qualquer observable rastreado que tenha mudado. O Reaction possui alguns métodos para seu uso, conforme será listado abaixo, todos eles retornam a ReactionDisposer, uma função que pode ser chamada para eliminar a reação.

Uma das melhores caracteristicas das reactions é que ele rastreia automaticamente qualquer observável sem precisar declarar nada. O fato de ter um observável dentro do escopo de uma Reaction é o suficiente para rastreá-lo.

O código que você escreve com o MobX parece literalmente sem cerimônia!

ReactionDisposer autorun(Function(Reaction) fn)

Executa uma Reaction na hora em que é rastreada na função anônima fn.

import 'package:mobx/mobx.dart';

final greeting = Observable('Hello World');

final dispose = autorun((_){
  print(greeting.value);
});

greeting.value = 'Hello MobX';

// Done with the autorun()
dispose();


// Prints:
// Hello World
// Hello MobX

ReactionDisposer reaction<T>(T Function(Reaction) predicate, void Function(T) effect)

Monitora um observável dentro de uma função de predicate() e executa o effect(). Quando o predicado retornar um valor diferente do anterior. Apenas variáveis dentro do predicate() são rastreados.

import 'package:mobx/mobx.dart';

final greeting = Observable('Hello World');

final dispose = reaction((_) => greeting.value, (msg) => print(msg));

greeting.value = 'Hello MobX'; // Cause a change

// Done with the reaction()
dispose();


// Prints:
// Hello MobX

ReactionDisposer when(bool Function(Reaction) predicate, void Function() effect)

Monitora um observável dentro de uma função de predicate() e executa o effect() quando when é true. Após executar o effect(), when chama o dispose automaticamente. Você pode pensar no when quando quiser executar a reaction apenas uma vez. Você também não precisará se preocupar com o dispose quando estiver usando o when().

import 'package:mobx/mobx.dart';

final greeting = Observable('Hello World');

final dispose = when((_) => greeting.value == 'Hello MobX', () => print('Someone greeted MobX'));

greeting.value = 'Hello MobX'; // Causes a change, runs effect and disposes


// Prints:
// Someone greeted MobX

Future<void> asyncWhen(bool Function(Reaction) predicate)

Similar ao when porém retorna um Future, que é completado quando o predicate() retorna true. Essa é uma maneira conveniente de esperar um predicate() se tornar true.

final completed = Observable(false);

void waitForCompletion() async {
  await asyncWhen(() => _completed.value == true);

  print('Completed');
}

Observer

O Observer é um widget (que é parte do pacote flutter_mobx), e nos provê uma observação dos observers por meio de uma função de builder. Toda vez que o observable mudar, o Observer renderizará novamente na view.

Abaixo temos um exemplo do Counter em sua totalidade.

import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart';

part 'counter.g.dart';

class Counter = CounterBase with _$Counter;

abstract class CounterBase with Store {
  @observable
  int value = 0;

  @action
  void increment() {
    value++;
  }
}

class CounterExample extends StatefulWidget {
  const CounterExample({Key key}) : super(key: key);

  @override
  _CounterExampleState createState() => _CounterExampleState();
}

class _CounterExampleState extends State<CounterExample> {
  final _counter = Counter();

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          title: const Text('Counter'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              const Text(
                'You have pushed the button this many times:',
              ),
              Observer(
                  builder: (_) => Text(
                        '${_counter.value}',
                        style: const TextStyle(fontSize: 20),
                      )),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: _counter.increment,
          tooltip: 'Increment',
          child: const Icon(Icons.add),
        ),
      );
}

Contribuição

Se você leu até aqui, então 🎉🎉🎉. Existem algumas maneiras de como você pode contribuir para a crescente comunidade do MobX.dart.

  • Escolha qualquer problema marcado com "good first issue"
  • Propor qualquer recurso ou aprimoramento
  • Reportar um erro
  • Corrigir um bug
  • Participe de uma discussão e ajude na tomada de decisão
  • Melhore a documentação documentation. A Documentação é de suma importância e de grande prioridade para a comunidade.
  • Enviar uma solicitação pull :-)
  • Entre na comunidade Join the chat at https://discord.gg/dNHY52k