Showing
1 changed file
with
40 additions
and
20 deletions
@@ -270,35 +270,52 @@ Get.bottomSheet( | @@ -270,35 +270,52 @@ Get.bottomSheet( | ||
270 | ``` | 270 | ``` |
271 | 271 | ||
272 | ## Gerenciador de estado simples | 272 | ## Gerenciador de estado simples |
273 | -Há atualmente vários gerenciadores de estados para o Flutter. Porém, a maioria deles envolve usar `ChangeNotifier` para atualizar os widgets e isso é uma abordagem muito ruim no quesito performance de aplicações de médio ou grande porte. Você pode checar na documentação oficial do Flutter que o [`ChangeNotifier` deveria ser usado com um ou no máximo dois listeners](https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html), fazendo-o praticamente inutilizável em qualquer aplicação média ou grande. Outros gerenciadores de estado são bons, mas tem suas nuances. BLoC é bem seguro e eficiente, mas é muito complexo (especialmente para iniciantes), o que impediu pessoas de desenvolverem com Flutter. MobX é mais fácil que o BLoc e é reativo, quase perfeito eu diria, mas você precisa usar um code generator que, para aplicações de grande porte, reduz a produtividade (você terá que beber vários cafés até que seu código esteja pronto denovo depois de um `flutter clean`, o que não é culpa do MobX, o code generatoe que é muito lento!). Provider usa o `InheritedWidget` para entregar o mesmo listener, como uma forma de solucionar o problema reportado acima com o ChangeNotifier, o que indica que qualquer acesso ao ChangeNotifier dele tem que ser dentro da árvore de widgets por causa do `context` necessário para acessar o Inherited. | 273 | +Há atualmente vários gerenciadores de estados para o Flutter. Porém, a maioria deles envolve usar `ChangeNotifier` para atualizar os widgets e isso é uma abordagem muito ruim no quesito performance em aplicações de médio ou grande porte. Você pode checar na documentação oficial do Flutter que o [`ChangeNotifier` deveria ser usado com um ou no máximo dois listeners](https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html), fazendo-o praticamente inutilizável em qualquer aplicação média ou grande. Outros gerenciadores de estado são bons, mas tem suas nuances. BLoC é bem seguro e eficiente, mas é muito complexo (especialmente para iniciantes), o que impediu pessoas de desenvolverem com Flutter. MobX é mais fácil que o BLoc e é reativo, quase perfeito eu diria, mas você precisa usar um code generator que, para aplicações de grande porte, reduz a produtividade (você terá que beber vários cafés até que seu código esteja pronto denovo depois de um `flutter clean`, o que não é culpa do MobX, na verdade o code generator que é muito lento!). Provider usa o `InheritedWidget` para entregar o mesmo listener, como uma forma de solucionar o problema reportado acima com o ChangeNotifier, o que indica que qualquer acesso ao ChangeNotifier dele tem que ser dentro da árvore de widgets por causa do `context` necessário para acessar o Inherited. |
274 | 274 | ||
275 | -Get não é melhor ou pior que nenhum gerenciador de estado, mas você deveria analisar esses pontos tanto quanto os argumentos abaixo para escolher entre usar Get na sua forma pura (Vanilla), ou usando-o em conjunto com outro gerenciador de estado. Definitivamente, Get não é o inimigo nenhum gerenciador, porque Get é um microframework, não apenas um gerenciador, e pode ser usado tanto sozinho quanto em conjunto com eles. | 275 | +Get não é melhor ou pior que nenhum gerenciador de estado, mas você deveria analisar esses pontos tanto quanto os argumentos abaixo para escolher entre usar Get na sua forma pura, ou usando-o em conjunto com outro gerenciador de estado. Definitivamente, Get não é o inimigo de nenhum gerenciador, porque Get é um microframework, não apenas um gerenciador, e pode ser usado tanto sozinho quanto em conjunto com eles. |
276 | 276 | ||
277 | -Get tem um gerenciador de estado que é extremamente leve e fácil (escrito em apensar 95 linha de código), que não usa ChangeNotifier, vai atender a necessidade especialmente daqueles novos no Flutter, e não vai causar problemas em aplicações de grande porte. | 277 | +Get tem um gerenciador de estado que é extremamente leve e fácil (escrito em apenas 95 linha de código), que não usa ChangeNotifier, vai atender a necessidade especialmente daqueles novos no Flutter, e não vai causar problemas em aplicações de grande porte. |
278 | 278 | ||
279 | -Que melhoras na performance o Get traz? | 279 | +**Que melhoras na performance o Get traz?** |
280 | 280 | ||
281 | 1. Atualiza somente o widget necessário. | 281 | 1. Atualiza somente o widget necessário. |
282 | 282 | ||
283 | 2. Não usa o `ChangeNotifier`, é o gerenciador de estado que utiliza menos memória (próximo de 0mb até agora). | 283 | 2. Não usa o `ChangeNotifier`, é o gerenciador de estado que utiliza menos memória (próximo de 0mb até agora). |
284 | 284 | ||
285 | -3. Esqueça StatefulWidget's! Com Get voce nunca mais vai precisar. Com outros gerenciadores de estado, você provavelmente precisa usar um StatefulWidget para pegar a instância do seu Provider, BLoc, MobX controller, etc. Mas já parou para pensar que seu AppBar, seu Scaffold e a maioria dos widgets que estão na sua classe são stateless? Então porque salvar o estado de uma classe inteira, se você pode salvar somente o estado de um widget stateful? Get resolve isso também. Crie uma classe Stateless, faça tudo stateless. Se vocÊ precisar atualizar um único componente, envolvar ele com o GetBuilder, e seu estado será mantido. | 285 | +3. Esqueça StatefulWidget's! Com Get você nunca mais vai precisar deles. Com outros gerenciadores de estado, você provavelmente precisa usar um StatefulWidget para pegar a instância do seu Provider, BLoc, MobX controller, etc. Mas já parou para pensar que seu AppBar, seu Scaffold e a maioria dos widgets que estão na sua classe são stateless? Então porque salvar o estado de uma classe inteira, se você pode salvar somente o estado de um widget stateful? Get resolve isso também. Crie uma classe Stateless, faça tudo stateless. Se você precisar atualizar um único componente, envolva ele com o `GetBuilder`, e seu estado será mantido. |
286 | 286 | ||
287 | 4. Organize seu projeto de verdade! Controllers não devem ficar na sua UI, coloque seus `TextEditController`, ou qualquer controller que você usa dentro da classe Controller. | 287 | 4. Organize seu projeto de verdade! Controllers não devem ficar na sua UI, coloque seus `TextEditController`, ou qualquer controller que você usa dentro da classe Controller. |
288 | 288 | ||
289 | -5. Você precisa acionar um evento para atualizar um widget assim que ele é renderizado? GetBuilder tem a propriedade `initState` assim como um StatefulWidget, e você pode acionar eventos a partir do seu controller, diretamente de lá. Sem mais de eventos serem colocados no initState. | 289 | +5. Você precisa acionar um evento para atualizar um widget assim que ele é renderizado? GetBuilder tem a propriedade `initState()` assim como um StatefulWidget, e você pode acionar eventos a partir do seu controller, diretamente de lá. Sem mais de eventos serem colocados no initState. |
290 | 290 | ||
291 | -6. Você precisa acionar uma ação como fechar `Stream`s, timers, etc? GetBuilder também tem a propriedade `dispose`, onde você pode acionar eventos assim que o widget é destruído. | 291 | +6. Você precisa acionar uma ação como fechar Streams, timers, etc? GetBuilder também tem a propriedade `dispose()`, onde você pode acionar eventos assim que o widget é destruído. |
292 | 292 | ||
293 | 7. Use `Stream`s somente se necessário. Você pode usar seus StreamControllers dentro do seu controller normalmente, e usar `StreamBuilder` normalmente também, mas lembre-se, um Stream consume uma memória razoável, programação reativa é linda, mas você não abuse. 30 Streams abertos simultaneamente podem ser ainda piores que o `ChangeNotifier` (e olha que o ChangeNotifier é bem ruim) | 293 | 7. Use `Stream`s somente se necessário. Você pode usar seus StreamControllers dentro do seu controller normalmente, e usar `StreamBuilder` normalmente também, mas lembre-se, um Stream consume uma memória razoável, programação reativa é linda, mas você não abuse. 30 Streams abertos simultaneamente podem ser ainda piores que o `ChangeNotifier` (e olha que o ChangeNotifier é bem ruim) |
294 | -8. Atualizar widgets sem gastar memória com isso. Get guarda somente a ID do criador GetBuilder, e atualiza esse GetBuilder quando necessário. O consumo de memória do ID do Get é muito baixo mesmo para milhares de GetBuilders. Quando você cria um novo GetBuilder, na verdade você está compartilhando o estado do GetBuilder quem tem um ID do creator. Um novo estado não é criado para cada GetBuilder, o que reduz MUITO o consumo de memória RAM em aplicações grandes. Basicamente sua aplicação vai ser toda stateless, e os poucos widgets que serão Stateful (dentro do GetBuilder) vão ter um estado único, e assim atualizar um deles vai atualizar todos eles. O estado é só um. | ||
295 | 294 | ||
296 | -9. Get é onisciente e na maioria dos casos sabe o momento exato de tirar um controller da memória. Você não precisa se preocupar com quando descartar o controller, Get sabe o melhor momento para fazer isso. Exemplo: | 295 | +8. Atualizar widgets sem gastar memória com isso. Get guarda somente a "ID do criador" do GetBuilder, e atualiza esse GetBuilder quando necessário. O consumo de memória do ID do GetBuilder é muito baixo mesmo para milhares de GetBuilders. Quando você cria um novo GetBuilder, na verdade você está compartilhando o estado do GetBuilder quem tem um ID do creator. Um novo estado não é criado para cada GetBuilder, o que reduz MUITO o consumo de memória RAM em aplicações grandes. Basicamente sua aplicação vai ser toda stateless, e os poucos widgets que serão Stateful (dentro do GetBuilder) vão ter um estado único, e assim atualizar um deles vai atualizar todos eles. O estado é um só. |
297 | 296 | ||
298 | -`Class A => Class B (tem o controller X) => Class C (tem o controller X)` | 297 | +9. Get é onisciente e na maioria dos casos sabe o momento exato de tirar um controller da memória. Você não precisa se preocupar com quando descartar o controller, Get sabe o melhor momento para fazer isso. |
299 | 298 | ||
300 | -Na classe A o controller não está ainda na memória, porque você ainda não o usou (Get carrega só quando precisa). Na classe B você usou o controller, e ele entrou na memória. Na classe C você usou o mesmo controller da classe B, Get vai compartilhar o estado do controller B com o controller C, e o mesmo controller ainda esta na memória. Se você fechar a classe C e classe B, Get vai tirar o controller X da memória automaticamente e liberar recursos, porque a classe A não está usando o controller. Se você navegar para a Classe B denovo, o controller X vai entrar na memória denovo. Se em vez de ir para a classe C você voltar para a classe A, Get vai tirar o controller da memória do mesmo jeito. Se a classe C não usar o controller, e você tirar a classe B da memória, nenhuma classe estaria usando o controller X, e novamente o controller seria descartado. A única exceção que pode atrapalhar o Get, é se | ||
301 | -Você remover classe N da rota de forma inesperada, e tentasse usar o controller na classe C. Nesse caso, o ID do creator do controller que estava em B seria deletado, e o Get foi programado para remover da memória todo controller que não tem nenhum ID de creator. Se é sua intenção fazer isso, adicione a config `autoRemove: false` no GetBuilder da classe B, e use `adoptID = true;` no GetBuilder da classe C. | 299 | +Vamos analisar o seguite exemplo: |
300 | + | ||
301 | +`Class A => Class B (ControllerX) => Class C (ControllerX)` | ||
302 | + | ||
303 | +* Na classe A o controller não está ainda na memória, porque você ainda não o usou (Get carrega só quando precisa). | ||
304 | + | ||
305 | +* Na classe B você usou o controller, e ele entrou na memória. | ||
306 | + | ||
307 | +* Na classe C você usou o mesmo controller da classe B, então o Get vai compartilhar o estado do controller B com o controller C, e o mesmo controller ainda estará na memória. | ||
308 | + | ||
309 | +* Se você fechar a classe C e classe B, Get vai tirar o controller X da memória automaticamente e liberar recursos, porque a classe A não está usando o controller. | ||
310 | + | ||
311 | +* Se você navegar para a Classe B denovo, o controller X vai entrar na memória denovo. | ||
312 | + | ||
313 | +* Se em vez de ir para a classe C você voltar para a classe A, Get vai tirar o controller da memória do mesmo jeito. | ||
314 | + | ||
315 | +* Se a classe C não usar o controller, e você tirar a classe B da memória, nenhuma classe estaria usando o controller X, e novamente o controller seria descartado. | ||
316 | + | ||
317 | +**Nota**: A única exceção que pode atrapalhar o Get, é se | ||
318 | +Você remover classe B da rota de forma inesperada, e tentasse usar o controller na classe C. Nesse caso, o ID do creator do controller que estava em B seria deletado, e o Get foi programado para remover da memória todo controller que não tem nenhum ID de creator. Se é sua intenção fazer isso, adicione a config `autoRemove: false` no GetBuilder da classe B, e use `adoptID = true;` no GetBuilder da classe C. | ||
302 | 319 | ||
303 | ### Uso do gerenciador de estado simples | 320 | ### Uso do gerenciador de estado simples |
304 | 321 | ||
@@ -322,11 +339,11 @@ GetBuilder<Controller>( | @@ -322,11 +339,11 @@ GetBuilder<Controller>( | ||
322 | ``` | 339 | ``` |
323 | **Feito!** | 340 | **Feito!** |
324 | 341 | ||
325 | -* Você já aprendeu como gerenciar estados com o Get. | ||
326 | -* Nota: Você talvez queira uma maior organização, e não querer usar a propriedade `init`. Para isso, você pode criar uma classe e extendê-la da classe `Bindings`, e nela mencionar os controllers que serão criados dentro daquela rota. Controllers não serão criados naquele momento exato, muito pelo contrário, isso é apenas uma declaração, para que na primeira vez que vc use um Controller, Get vai saber onde procurar. Get vai continuar no formato "lazyLoad" (carrega somente quando necessário) e vai continuar descartando os Controllers quando eles não forem mais necessários. Veja pub.dev example para ver como funciona. | 342 | +Você já aprendeu como gerenciar estados com o Get. |
327 | 343 | ||
344 | +Nota: Você talvez queira uma maior organização, e não querer usar a propriedade `init`. Para isso, você pode criar uma classe e extendê-la da classe `Bindings`, e nela mencionar os controllers que serão criados dentro daquela rota. Controllers não serão criados naquele momento exato, muito pelo contrário, isso é apenas uma declaração, para que na primeira vez que vc use um Controller, Get vai saber onde procurar. Get vai continuar no formato "lazyLoad" (carrega somente quando necessário) e vai continuar descartando os Controllers quando eles não forem mais necessários. Veja pub.dev example para ver como funciona. | ||
328 | 345 | ||
329 | -Se você navegar por várias rotas e precisa de algum daat que estava em um outro controller previamente utilizado, você só precisa utilizar o GetBuilder novamente (sem o init): | 346 | +Se você navegar por várias rotas e precisa de algum dado que estava em um outro controller previamente utilizado, você só precisa utilizar o GetBuilder novamente (sem o init): |
330 | 347 | ||
331 | ```dart | 348 | ```dart |
332 | class OutraClasse extends StatelessWidget { | 349 | class OutraClasse extends StatelessWidget { |
@@ -340,9 +357,10 @@ class OutraClasse extends StatelessWidget { | @@ -340,9 +357,10 @@ class OutraClasse extends StatelessWidget { | ||
340 | ), | 357 | ), |
341 | ); | 358 | ); |
342 | } | 359 | } |
360 | +} | ||
343 | ``` | 361 | ``` |
344 | 362 | ||
345 | -Se você precisa utilizar seu controller em vários outros lugares, e fora do GetBuilder, apenas crie um getter no seu controller and consiga seu controller facilmente (ou use `Get.find<Controller>()`) | 363 | +Se você precisa utilizar seu controller em vários outros lugares, e fora do GetBuilder, apenas crie um getter no seu controller que você consegue ele facilmente (ou use `Get.find<Controller>()` ) |
346 | 364 | ||
347 | ```dart | 365 | ```dart |
348 | class Controller extends GetController { | 366 | class Controller extends GetController { |
@@ -350,7 +368,7 @@ class Controller extends GetController { | @@ -350,7 +368,7 @@ class Controller extends GetController { | ||
350 | /// Você não precisa disso. Eu recomendo usar isso apenas | 368 | /// Você não precisa disso. Eu recomendo usar isso apenas |
351 | /// porque a sintaxe é mais fácil. | 369 | /// porque a sintaxe é mais fácil. |
352 | /// com o método estático: Controller.to.counter(); | 370 | /// com o método estático: Controller.to.counter(); |
353 | - /// sem o método estático: Get.find<Contreoller>(); | 371 | + /// sem o método estático: Get.find<Controller>(); |
354 | /// Não há diferença em performance, nem efeito colateral por usar esse sintaxe. Só uma não precisa da tipage, e a outra forma a IDE vai autocompletar. | 372 | /// Não há diferença em performance, nem efeito colateral por usar esse sintaxe. Só uma não precisa da tipage, e a outra forma a IDE vai autocompletar. |
355 | static Controller get to => Get.find(); // adicione esta linha | 373 | static Controller get to => Get.find(); // adicione esta linha |
356 | 374 | ||
@@ -373,13 +391,13 @@ FloatingActionButton( | @@ -373,13 +391,13 @@ FloatingActionButton( | ||
373 | Quando você pressionar o FloatingActionButton, todos os widgets que estão escutando a variável `counter` serão atualizados automaticamente. | 391 | Quando você pressionar o FloatingActionButton, todos os widgets que estão escutando a variável `counter` serão atualizados automaticamente. |
374 | 392 | ||
375 | #### Sem StatefulWidget; | 393 | #### Sem StatefulWidget; |
376 | -Usar StatefulWidgets significa guardar o estado de telas inteiras desnecessariamente, mesmo porque se você precisa recarregar minimamente algum widget, você vai incorporá-lo num Consumer/Observer/BlocProvider/GetBuilder, que vai ser outro StatefulWidget. | 394 | +Usar StatefulWidget's significa guardar o estado de telas inteiras desnecessariamente, mesmo porque se você precisa recarregar minimamente algum widget, você vai incorporá-lo num Consumer/Observer/BlocProvider/GetBuilder, que vai ser outro StatefulWidget. |
377 | A classe StatefulWidget é maior que a classe StatelessWidget, o que vai alocar mais memória, e isso pode não fazer uma diferença significativa com uma ou duas classes, mas com certeza vai quando você tiver 100 delas! | 395 | A classe StatefulWidget é maior que a classe StatelessWidget, o que vai alocar mais memória, e isso pode não fazer uma diferença significativa com uma ou duas classes, mas com certeza vai quando você tiver 100 delas! |
396 | + | ||
378 | A não ser que você precise usar um mixin, como o `TickerProviderStateMixin`, será totalmente desnecessário usar um StatefulWidget com o Get. | 397 | A não ser que você precise usar um mixin, como o `TickerProviderStateMixin`, será totalmente desnecessário usar um StatefulWidget com o Get. |
379 | 398 | ||
380 | Você pode chamar todos os métodos de um StatefulWidget diretamente de um GetBuilder. | 399 | Você pode chamar todos os métodos de um StatefulWidget diretamente de um GetBuilder. |
381 | Se você precisa chamar o método `initState()` ou `dispose()` por exemplo, é possível chamá-los diretamente: | 400 | Se você precisa chamar o método `initState()` ou `dispose()` por exemplo, é possível chamá-los diretamente: |
382 | - | ||
383 | ```dart | 401 | ```dart |
384 | GetBuilder<Controller>( | 402 | GetBuilder<Controller>( |
385 | initState: (_) => Controller.to.fetchApi(), | 403 | initState: (_) => Controller.to.fetchApi(), |
@@ -398,7 +416,9 @@ void onInit() { | @@ -398,7 +416,9 @@ void onInit() { | ||
398 | ``` | 416 | ``` |
399 | * Nota: Se você quiser rodar um método no momento que o controller é chamado pela primeira vez, você NÃO PRECISA usar construtores para isso, na verdade, usando um package que é focado em performance como o Get, isso chega no limite de má prática, porque se desvia da lógica que os controllers são criados ou alocados (Se você criar uma instância desse controller, o construtor vai ser chamado imediatamente, e ele será populado antes de ser usado, ou seja, você está alocando memória e não está utilizando, o que fere os princípios desse package). Os métodos `onInit()` e `onClose()` foram criados para isso, eles serão chamados quando o controller é criado, ou usados pela primeira vez, dependendo de como você está utilizando o Get (lazyPut ou não). Se quiser, por exemplo, fazer uma chamada para sua API para popular dados, você pode esquecer do estilo antigo de usar `initState()/dispose()`, apenas comece sua chamada para a api no `onInit`, e apenas se você precisar executar algum comando como fechar stream, use o `onClose()`. | 417 | * Nota: Se você quiser rodar um método no momento que o controller é chamado pela primeira vez, você NÃO PRECISA usar construtores para isso, na verdade, usando um package que é focado em performance como o Get, isso chega no limite de má prática, porque se desvia da lógica que os controllers são criados ou alocados (Se você criar uma instância desse controller, o construtor vai ser chamado imediatamente, e ele será populado antes de ser usado, ou seja, você está alocando memória e não está utilizando, o que fere os princípios desse package). Os métodos `onInit()` e `onClose()` foram criados para isso, eles serão chamados quando o controller é criado, ou usados pela primeira vez, dependendo de como você está utilizando o Get (lazyPut ou não). Se quiser, por exemplo, fazer uma chamada para sua API para popular dados, você pode esquecer do estilo antigo de usar `initState()/dispose()`, apenas comece sua chamada para a api no `onInit`, e apenas se você precisar executar algum comando como fechar stream, use o `onClose()`. |
400 | 418 | ||
401 | -O propósito desse package é precisamente te dar uma solução completa para navegação de rotas, gerenciamente de dependências e estados, usando o mínimo possível de dependências, com um alto grau de decoupling. Get envolve em todos as API de baixo e alto nível dentro de si mesmo, para ter certeza que você irá trabalhar com o mínimo possível de coupling. Nós centralizamos tudo em um único package. Dessa forma, você pode colocar somente widgets na sua view, e deixar a parte do seu time que trabalhar com a lógica de negócio livre, para que possam trabalhar sem depender de nenhum elemento da View. Isso fornece um ambiente de trabalho muito mais limpo, para que parte do seu time possa trabalhar apenas com os widgets, sem se preocupar sobre enviar dados para o controller, e outra parte do seu time trabalhe apensar com lógica de negócio, sem depender de nenhum elemento da view. | 419 | +O propósito desse package é precisamente te dar uma solução completa para navegação de rotas, gerenciamente de dependências e estados, usando o mínimo possível de dependências, com um alto grau de decoupling. Get envolve em todas as APIs de baixo e alto nível dentro de si mesmo, para ter certeza que você irá trabalhar com o mínimo possível de coupling. |
420 | + | ||
421 | +Nós centralizamos tudo em um único package. Dessa forma, você pode colocar somente widgets na sua view, e o controller pode ter só lógica de negócio, sem depender de nenhum elemento da View. Isso fornece um ambiente de trabalho muito mais limpo, para que parte do seu time possa trabalhar apenas com os widgets, sem se preocupar sobre enviar dados para o controller, e outra parte se preocupe apenas com a lógica de negócio, sem depender de nenhum elemento da view. | ||
402 | 422 | ||
403 | Então, para simplificar isso: | 423 | Então, para simplificar isso: |
404 | 424 |
-
Please register or login to post a comment