No final de 2018, o Google, com a ajuda da comunidade de código-fonte aberto, fez um grande presente para os desenvolvedores de dispositivos móveis ao lançar a primeira versão estável da estrutura de desenvolvimento móvel de plataforma cruzada Flutter.
No entanto, ao desenvolver aplicativos grandes um pouco maiores que o Hello Worlds de uma página, os desenvolvedores podem ter incertezas. Como escrever um aplicativo? A estrutura é bastante jovem, ainda não há uma base suficiente de bons exemplos de código aberto, com base nos quais seria possível entender os prós e os contras do uso de vários padrões, para entender o que deveria ser usado nesse caso específico e o que não.
A situação é salva pelo fato de o Flutter ter um certo grau de semelhança com o React e o React Native, o que significa que você pode aprender com alguma experiência de programação no último. Talvez por isso, bibliotecas como Flutter Flux , Flutter Hooks , MobX e várias implementações de Redux tenham aparecido ao mesmo tempo. Por um longo tempo, a versão mais popular foi Brian Egan, chamada Flutter Redux .
No entanto, alguns meses atrás, o primeiro commit foi visto pela biblioteca Fish Redux , publicada sob o nome de Alibaba. Em pouco tempo, a biblioteca ganhou grande popularidade, já no primeiro dia antes da implementação de Brian em termos de número de estrelas, e no segundo dia estava duas vezes à frente.
Apesar de sua popularidade, o Fish tem problemas com a documentação, que na maioria das vezes fornece uma descrição das classes existentes com alguns exemplos curtos. Para piorar a situação, alguma documentação está disponível apenas em chinês. Há outra dificuldade: quase não há problema de língua inglesa, portanto, confiar na experiência de outros desenvolvedores é muito difícil, o que é muito crítico, pois apenas as primeiras versões de pré-visualização estão sendo lançadas.
Então, qual é a diferença significativa entre a versão Fish'a de Brian? Flutter Redux é uma estrutura de gerenciamento de estado. O Fish é uma estrutura de aplicativos que coloca o Redux no centro como base para o gerenciamento do estado. I.e. O peixe resolve mais algumas tarefas e não se limita à state management
.
Uma das principais características do Fish Redux é a união de vários redutores por meio da expressão direta da relação entre eles, quando o Redux regular não oferece essa oportunidade, forçando os desenvolvedores a implementar tudo por conta própria. Mas voltemos a isso mais tarde, tendo lidado com o que é esse redutor, assim como com o próprio Fish Redux.
A relação entre Redutor, Efeito e Vista no componente

A base de tudo no Fish Redux é o Component. Este é um objeto que consiste em três partes: Efeito, Redutor e Visualização. Vale ressaltar que apenas o View, ou seja, Efeito e Redutor são opcionais; um componente pode funcionar sem eles. O componente também tem um estado atual.
Estado
Por exemplo, pegue um clicker. Deixe haver apenas um campo em seu estado - contagem, o que indicará o número perfeito de cliques.
class ClickerState implements Cloneable<ClickerState> { int count = 0; @override ClickerState clone() { return ClickerState() ..count = count; } }
Os estados devem ser imutáveis, imutáveis. A imunidade do estado pode ser facilmente mantida implementando a interface Cloneable. No futuro, quando você precisar criar um novo estado, poderá simplesmente usar o método clone()
.
Redutor
A essência do redutor é responder a alguma ação retornando um novo estado. O redutor não deve causar efeitos colaterais.
Escreveremos um redutor simples que aumentará a contagem em algum número após o recebimento da ação correspondente (um pouco mais baixa).
ClickerState clickerReducer(ClickerState state, Action action) {
Além disso, esse redutor pode ser escrito da seguinte forma:
Reducer<ClickerState> buildClickerReducer() { asReducer({ Actions.increase: (state, action) => state.clone() ..count = state.count + action.payload,
Acção
Ação - uma classe na biblioteca FishRedux que contém dois campos:
Object type
- Object type
ação, geralmente um objeto enum
dynamic payload
- parâmetro de ação, opcional.
Um exemplo:
enum Actions { increase }
Ver
A lógica está pronta, resta mostrar o resultado. View é uma função que assume como parâmetros o estado atual, expedição, ViewService e retorna um Widget.
A função de despacho é necessária para enviar ações: uma ação cuja criação descrevemos anteriormente.
O ViewService contém o BuildContext atual (da biblioteca padrão de vibração) e fornece métodos para criar dependências, mas sobre elas posteriormente.
Um exemplo:
Widget clickerView(ClickerState state, Dispatch dispatch, ViewService viewService) { return RaisedButton( child: Text(state.count.toString()), onPressed: () => dispatch(ActionsCreate.increase(1))
Componente
Vamos montar nosso componente a partir de tudo isso:
class ClickerComponent extends Component<ClickerState> { ClickerComponent() : super( reducer: clickerReducer, view: clickerView, ); }
Como você pode ver, o efeito não é usado em nosso exemplo, porque não é necessário. Um efeito é uma função que deve executar todos os efeitos colaterais. Mas vamos apresentar um caso em que você não pode prescindir do Effect. Por exemplo, isso poderia ser um aumento em nossa contagem de um número aleatório do serviço random.org.
Exemplo de implementação de efeito import 'package:http/http.dart' as http;
Page
Há uma extensão para o componente chamada Página <T, P>. A página inclui dois campos adicionais:
T initState(P params)
- uma função que retorna o estado inicial. Será chamado quando a página for criada.
List<Middleware<T>> middleware
- uma lista de Middleware - funções que serão chamadas antes do redutor.
E também um método:
Widget buildPage(P params)
- que coleta a página em um widget em funcionamento.
Vamos criar a página principal do aplicativo:
class MainPage extends Page<void, void> { MainPage(): super( initState: (dynamic param) {}, view: (state, dispatch, viewService) => Container(), ); }
Uma página estende um componente, o que significa que pode incluir redutor, efeito e tudo o mais que um componente comum possui.
No exemplo, foi criada uma página em branco que não possui estado, nem redutores ou efeitos. Nós vamos corrigir isso mais tarde.
Tudo isso tem uma forma um pouco diferente e no Flutter Redux de Brian Egan, bem como em outras implementações do Redux. Vamos para o recurso principal da nova biblioteca - dependências.
Dependências
O Fish Redux requer que você defina explicitamente as dependências entre os componentes. Se você deseja usar um subcomponente em um componente, é necessário não apenas gravar esses dois componentes, mas também criar um conector que será responsável pela conversão de um estado para outro. Suponha que desejamos incorporar um ClickerComponent em uma página da MainPage.
Primeiro, você precisa adicionar o estado à nossa página:
class MainState implements Cloneable<MainState> { ClickerState clicker; @override MainState clone() { return MainState() ..clicker = clicker; } static MainState initState(dynamic params) { return MainState() ..clicker = ClickerState(); } }
Agora podemos escrever o Connector:
class ClickerConnector extends ConnOp<MainState, ClickerState> { @override ClickerState get(MainState state) => state.clicker;
Só isso. Está tudo pronto para adicionar nosso componente:
class MainPage extends Page<MainState, void> { MainPage(): super( initState: MainState.initState, dependencies: Dependencies( slots: { 'clicker': ClickerComponent().asDependent(ClickerConnector()),
Portanto, agora você pode criar um aplicativo de trabalho completo adicionando o seguinte código ao main.dart
:
void main() => runApp(MyApp()); class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { @override Widget build(BuildContext context) => MaterialApp(home: MainPage().buildPage(null)); }
Todo o código separado por arquivo está disponível aqui . Tenha uma boa experiência de desenvolvimento com o Flutter.