# State Management

<div id="introduction"></div>

## Introdução

O gerenciamento de estado permite que você atualize partes específicas da sua UI sem reconstruir páginas inteiras. No Nylo v7, você pode construir widgets que se comunicam e atualizam uns aos outros em todo o seu app.

Nylo fornece duas classes para gerenciamento de estado:
- **`NyState`** -- Para construir widgets reutilizáveis (como um badge de carrinho, contador de notificações ou indicador de status)
- **`NyPage`** -- Para construir páginas na sua aplicação (estende `NyState` com recursos específicos de página)

Use gerenciamento de estado quando você precisar:
- Atualizar um widget de uma parte diferente do seu app
- Manter widgets sincronizados com dados compartilhados
- Evitar reconstruir páginas inteiras quando apenas parte da UI muda


### Vamos primeiro entender o Gerenciamento de Estado

Tudo no Flutter é um widget, são apenas pequenos pedaços de UI que você pode combinar para fazer um app completo.

Quando você começa a construir páginas complexas, precisará gerenciar o estado dos seus widgets. Isso significa que quando algo muda, ex.: dados, você pode atualizar aquele widget sem ter que reconstruir a página inteira.

Existem muitas razões pelas quais isso é importante, mas a razão principal é desempenho. Se você tem um widget que está mudando constantemente, você não quer reconstruir a página inteira toda vez que ele muda.

É aqui que o Gerenciamento de Estado entra, ele permite que você gerencie o estado de um widget na sua aplicação.


<div id="when-to-use-state-management"></div>

### Quando Usar Gerenciamento de Estado

Você deve usar Gerenciamento de Estado quando tiver um widget que precisa ser atualizado sem reconstruir a página inteira.

Por exemplo, vamos imaginar que você criou um app de ecommerce. Você construiu um widget para exibir a quantidade total de itens no carrinho do usuário.
Vamos chamar este widget de `Cart()`.

Um widget `Cart` gerenciado por estado no Nylo ficaria assim:

**Passo 1:** Defina o widget com um nome de estado estático

``` dart
/// O widget Cart
class Cart extends StatefulWidget {

  Cart({Key? key}) : super(key: key);

  static String state = "cart"; // Identificador unico para o estado deste widget

  @override
  _CartState createState() => _CartState();
}
```

**Passo 2:** Crie a classe de estado estendendo `NyState`

``` dart
/// A classe de estado para o widget Cart
class _CartState extends NyState<Cart> {

  String? _cartValue;

  _CartState() {
    stateName = Cart.state; // Registrar o nome do estado
  }

  @override
  get init => () async {
    _cartValue = await getCartValue(); // Carregar dados iniciais
  };

  @override
  void stateUpdated(data) {
    reboot(); // Recarregar o widget quando o estado for atualizado
  }

  @override
  Widget view(BuildContext context) {
    return Badge(
      child: Icon(Icons.shopping_cart),
      label: Text(_cartValue ?? "1"),
    );
  }
}
```

**Passo 3:** Crie funções auxiliares para ler e atualizar o carrinho

``` dart
/// Obter o valor do carrinho do armazenamento
Future<String> getCartValue() async {
  return await storageRead(Keys.cart) ?? "1";
}

/// Definir o valor do carrinho e notificar o widget
Future setCartValue(String value) async {
    await storageSave(Keys.cart, value);
    updateState(Cart.state); // Isso aciona stateUpdated() no widget
}
```

Vamos detalhar isso.

1. O widget `Cart` é um `StatefulWidget`.

2. `_CartState` estende `NyState<Cart>`.

3. Você precisa definir um nome para o `state`, que é usado para identificar o estado.

4. O método `boot()` é chamado quando o widget é carregado pela primeira vez.

5. Os métodos `stateUpdate()` lidam com o que acontece quando o estado é atualizado.

Se você quiser experimentar este exemplo no seu projeto Nylo, crie um novo widget chamado `Cart`.

``` bash
metro make:state_managed_widget cart
```

Então você pode copiar o exemplo acima e testá-lo no seu projeto.

Agora, para atualizar o carrinho, você pode chamar o seguinte.

```dart
_updateCart() async {
  String count = await getCartValue();
  String countIncremented = (int.parse(count) + 1).toString();

  await storageSave(Keys.cart, countIncremented);

  updateState(Cart.state);
}
```


<div id="lifecycle"></div>

## Ciclo de Vida

O ciclo de vida de um widget `NyState` é o seguinte:

1. `init()` - Este método é chamado quando o estado é inicializado.

2. `stateUpdated(data)` - Este método é chamado quando o estado é atualizado.

    Se você chamar `updateState(MyStateName.state, data: "The Data")`, isso disparará **stateUpdated(data)** para ser chamado.

Uma vez que o estado é inicializado pela primeira vez, você precisará implementar como deseja gerenciar o estado.


<div id="state-actions"></div>

## Ações de Estado

Ações de estado permitem que você dispare métodos específicos em um widget de qualquer lugar no seu app. Pense nelas como comandos nomeados que você pode enviar para um widget.

Use ações de estado quando precisar:
- Disparar um comportamento específico em um widget (não apenas atualizá-lo)
- Passar dados para um widget e fazê-lo responder de uma maneira particular
- Criar comportamentos de widget reutilizáveis que podem ser invocados de múltiplos lugares

``` dart
// Enviando uma acao para o widget
stateAction('hello_world_in_widget', state: MyWidget.state);

// Outro exemplo com dados
stateAction('show_high_score', state: HighScore.state, data: {
  "high_score": 100,
});
```

No seu widget, você pode definir as ações que deseja tratar.

``` dart
...
@override
get stateActions => {
  "hello_world_in_widget": () {
    print('Hello world');
  },
  "reset_data": (data) async {
    // Exemplo com dados
    _textController.clear();
    _myData = null;
    setState(() {});
  },
};
```

Então, você pode chamar o método `stateAction` de qualquer lugar na sua aplicação.

``` dart
stateAction('hello_world_in_widget', state: MyWidget.state);
// prints 'Hello world'

User user = User(name: "John Doe", age: 30);
stateAction('update_user_info', state: MyWidget.state, data: user);
```

Se você já tem uma instância de `StateActions` (por ex. do método estático `stateActions()` de um widget), pode chamar `action()` diretamente nela em vez de usar a função livre:

``` dart
// Usando a funcao livre
stateAction('reset_avatar', state: UserAvatar.state);

// Usando o metodo da instancia StateActions — equivalente, menos repeticao
final actions = UserAvatar.stateActions(UserAvatar.state);
actions.action('reset_avatar');
actions.action('update_user_image', data: user);
```

Você também pode definir suas ações de estado usando o método `whenStateAction` no seu getter `init`.

``` dart
@override
get init => () async {
  ...
  whenStateAction({
    "reset_badge": () {
      // Redefinir a contagem do badge
      _count = 0;
    }
  });
}
```


<div id="state-actions-nystate"></div>

### NyState - Ações de Estado

Primeiro, crie um widget stateful.

``` bash
metro make:stateful_widget [widget_name]
```
Exemplo: metro make:stateful_widget user_avatar

Isso criará um novo widget no diretório `lib/resources/widgets/`.

Se você abrir esse arquivo, poderá definir suas ações de estado.

``` dart
class _UserAvatarState extends NyState<UserAvatar> {
...

@override
get stateActions => {
  "reset_avatar": () {
    // Exemplo
    _avatar = null;
    setState(() {});
  },
  "update_user_image": (User user) {
    // Exemplo
    _avatar = user.image;
    setState(() {});
  },
  "show_toast": (data) {
    showSuccessToast(description: data['message']);
  },
};
```

Finalmente, você pode enviar a ação de qualquer lugar na sua aplicação.

``` dart
stateAction('reset_avatar', state: MyWidget.state);
// prints 'Hello from the widget'

stateAction('reset_data', state: MyWidget.state);
// Redefinir dados no widget

stateAction('show_toast', state: MyWidget.state, data: "Hello world");
// exibe um toast de sucesso com a mensagem
```


<div id="state-actions-nypage"></div>

### NyPage - Ações de Estado

Páginas também podem receber ações de estado. Isso é útil quando você deseja disparar comportamentos no nível da página a partir de widgets ou outras páginas.

Primeiro, crie sua página gerenciada por estado.

``` bash
metro make:page my_page
```

Isso criará uma nova página gerenciada por estado chamada `MyPage` no diretório `lib/resources/pages/`.

Se você abrir esse arquivo, poderá definir suas ações de estado.

``` dart
class _MyPageState extends NyPage<MyPage> {
...

@override
bool get stateManaged => false; // definir como true para habilitar acoes de estado nesta pagina

@override
get stateActions => {
  "test_page_action": () {
    print('Hello from the page');
  },
  "reset_data": () {
    // Exemplo
    _textController.clear();
    _myData = null;
    setState(() {});
  },
  "show_toast": (data) {
    showSuccessToast(description: data['message']);
  },
};
```

Finalmente, você pode enviar a ação de qualquer lugar na sua aplicação.

``` dart
stateAction('test_page_action', state: MyPage.path);
// prints 'Hello from the page'

stateAction('reset_data', state: MyPage.path);
// Redefinir dados na pagina

stateAction('show_toast', state: MyPage.path, data: {
  "message": "Hello from the page"
});
// exibe um toast de sucesso com a mensagem
```

Você também pode definir suas ações de estado usando o método `whenStateAction`.

``` dart
@override
get init => () async {
  ...
  whenStateAction({
    "reset_badge": () {
      // Redefinir a contagem do badge
      _count = 0;
    }
  });
}
```

Então você pode enviar a ação de qualquer lugar na sua aplicação.

``` dart
stateAction('reset_badge', state: MyWidget.state);
```


<div id="updating-a-state"></div>

## Atualizando um Estado

Você pode atualizar um estado chamando o método `updateState()`.

``` dart
updateState(MyStateName.state);

// ou com dados
updateState(MyStateName.state, data: "The Data");
```

Isso pode ser chamado de qualquer lugar na sua aplicação.

**Veja também:** [NyState](/docs/7.x/ny-state) para mais detalhes sobre helpers de gerenciamento de estado e métodos de ciclo de vida.


<div id="building-your-first-widget"></div>

## Construindo seu Primeiro Widget

No seu projeto Nylo, execute o seguinte comando para criar um novo widget.

``` bash
metro make:stateful_widget todo_list
```

Isso criará um novo widget `NyState` chamado `TodoList`.

> Nota: O novo widget será criado no diretório `lib/resources/widgets/`.
