preface

Fish-redux is an official framework for Flutter state management. There are many commonly used state management frameworks, ranging from those officially recommended by Google to those written by individual developers. This article focuses on Fish_redux.

Common Flutter state management schemes:

Starting at zero, you know fish-Redux, for example

There are many ways to do this,

  • Call setText(“${count+1}”)
  • SetState (){“${count+1}”}

The native implementation of Flutter has no performance problems. OnDraw () is triggered when a setText is called. However, the implementation of Flutter calls setState causes the entire root layout to be rebuilt. How do you control the coarse-grained layout so that only the digital control layout that needs to change is rebuilt?

Fish-redux implementation

1. Build a Flutter project, Flutter2.0 is not supported because fish-Redux does not support Flutter2.0, now demo with version 1.22.6, add dependencies in pubspec.yaml,

Dependencies: flutter: SDK: flutter fish_redux: 0.3.7Copy the code

2. Download the FishReduxTemplate plugin

3. Create a folder called count, right-click it, and select FishReduxTemplate to generate the Page template code

4. Encode main.dart to create a page entry

import 'package:fish_redux/fish_redux.dart';
import 'package:flutter/material.dart';
import 'count/page.dart';

void main() {
  runApp(MyApp());
}

///Routing management
class RouteConfig {
  static const String countPage = 'page/count';
  static final AbstractRoutes routes = PageRoutes(
    pages: {
      ///Map your route name to the page, for example: RouteConfig. HomePage: homePage (),
      RouteConfig.countPage: CountPage(),
    },
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'FishReduxDemo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: RouteConfig.routes.buildPage(RouteConfig.countPage, null), // as the default page
        onGenerateRoute: (RouteSettings settings) {
          // Material page toggle style
          return MaterialPageRoute<Object>(builder: (BuildContext context) {
            returnRouteConfig.routes.buildPage(settings.name, settings.arguments); }); }); }}Copy the code
  1. Code Page. Dart
import 'package:fish_redux/fish_redux.dart';
import 'effect.dart';
import 'reducer.dart';
import 'state.dart';
import 'view.dart';
/// With the creation of the page, the Fish Redux framework creates Effect by default and the Reducer object manages the whole page
class CountPage extends Page<CountState.Map<String.dynamic>> {
  CountPage()
      : super(
          initState: initState, // Create a default state object
          effect: buildEffect(), // Create an Effect object
          reducer: buildReducer(), Create a Reducer object
          view: buildView, // Create the page layout, here is the actual page to display
          dependencies: Dependencies<CountState>(
            adapter: null,
            slots: <String, Dependent<CountState>>{},
          ),
          middleware: <Middleware<CountState>>[],
        );
}

Copy the code
  1. Code view.dart
import 'package:fimber/fimber_base.dart';
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter/material.dart';
import 'action.dart';
import 'state.dart';
/// The View layout shown on the home page
Widget buildView(CountState state, Dispatch dispatch, ViewService viewService) {
  return _bodyWidget(state, dispatch);
}

Widget _bodyWidget(CountState state, Dispatch dispatch) {
  return Scaffold(
    appBar: AppBar(
      title: Text("FishReduxDemo"),
    ),
    body: Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
           Text(state.count.toString(), style: TextStyle(fontSize: 40, color: Colors.red)),
        ],
      ),
    ),
    floatingActionButton: FloatingActionButton(
      onPressed: () {
        dispatch(CountActionCreator.increaseCount()); // 1. Click the event trigger
      },
      child: Icon(Icons.add),
    ),
  );
}
Copy the code
  1. Code effect.dart
import 'package:fimber/fimber_base.dart';
import 'package:fish_redux/fish_redux.dart';
import 'action.dart';
import 'state.dart';

Effect<CountState> buildEffect() {
  // Combine effect
  return combineEffects(<Object, Effect<CountState>>{
    CountAction.increase: _onIncreaseCount,
  });
}

///On the way
void _onIncreaseCount(Action action, Context<CountState> context) {
  // 2.Effect handles click events
  context.dispatch(CountActionCreator.updateCount());
}
Copy the code
  1. Code reduce.dart
import 'package:fish_redux/fish_redux.dart';
import 'action.dart';
import 'state.dart';

Reducer<CountState> buildReducer() {
  return asReducer(
    <Object, Reducer<CountState>>{
      CountAction.updateCount: _updateCount,
    },
  );
}
/// Notify the View layer to update the interface
CountState _updateCount(CountState state, Action action) {
  finalCountState newState = state.clone(); newState.. count = state.count +1; // 3. Core logic: Increment the number by 1 and return the newState object, at which point the page will refresh
  return newState;
}
Copy the code
  1. Code state.dart
import 'package:fish_redux/fish_redux.dart';

// state manages the data for each page
class CountState implements Cloneable<CountState> {
  int count;

  @override
  CountState clone() {
    returnCountState() .. count = count; } } CountState initState(Map<String.dynamic> args) {
  returnCountState().. count =0;
}

Copy the code

10. Code action.dart

import 'package:fish_redux/fish_redux.dart';

/// How many events a page has is defined in the enumeration
enum CountAction { updateCount,increase }

// Click the event handler class,
class CountActionCreator {
  /// Click event. If you need to send parameters, you can place them in the payload field. Payload is of dynamic type
  static Action increaseCount() {
    return Action(CountAction.increase,payload: "Event Parameters");
  }
  
  static Action updateCount() {
    return Action(CountAction.updateCount,payload: ["Optional"]); }}Copy the code

If you are a beginner, I believe you are confused at this point, what?

The principle of understanding

Dart button click event is triggereddispatch(CountActionCreator.increaseCount());

2. The framework automatically calls effect.dartbuildEffect()Configure the event corresponding to the method and then passcontext.dispatch()Continue to distribute the events

3. The reducer.dart is automatically called by the frameworkbuilderReducer()Method corresponding to the configured time. Finally, update the count in state, return state, and the framework will recreate the layout bound to the count in state.

This enables coarse-grained control of the layout and only rebuilds the layout that needs to change, improving performance. At the same time, service logic can be written in Effect or reducer, which is generally written in reducer. Although there is several times more code, the subsequent complexity of the business, through this separation of UI and business logic can be better extended. Is it a little bit like MVC, MVP, MVVM? For example, Android typically requests an interface in onCreate(), and the page is refreshed when the request is successful, whereas fish-redux can be handled in effect.dart

Effect<CountState> buildEffect() {
  // Combine effect
  return combineEffects(<Object, Effect<CountState>>{
    CountAction.increase: _onIncreaseCount,
    Lifecycle.initState: _onCreate,
  });
}

void _onCreate(Action action, Context<CountState> context){
  // Interface request..
  // After the request succeeds, the data is sent to the reducer using context.dispatchcontext.dispatch(...) ; }Copy the code

conclusion

Understanding the mechanics of Fish-Redux and knowing which methods are automatically called by the framework will save you from missteps in later coding.