Fish-Redux Developing flutter (PART 1)

In the previous two articles, we looked at fish-Redux and implemented simple functions. This time we’ll look at some other features of Fish-Redux. Take a look at the resulting graph:

1 Make a list using Component and Adapter

1.1 Create a list page and define data

The page creation process is omitted as before. I created a page called List with the following results

Add our page to app.dart. Dart is modified as follows

Widget createApp() {
  final AbstractRoutes routes = PageRoutes(
    pages: <String, Page<Object.dynamic> > {'entrance_page': EntrancePage(),
      'grid_page': GridPage(),
      'list_page':ListPage(),   // Add our new page here});/ / to omit...
Copy the code

Then implement a page jump from the Grid page to the page. Create the action, dispatch the action in view, receive the action in effect, and jump to the page

1.2 create a component

Then we create a Component under the List package for each item of the list.

The first step is to create a Component from the plug-in

First create a package named item, then create the FishReduxTemplate under item, this time selecting Component.

Dart in the component is similar to Page. Dart in the page.

The second step defines the component data and UI

We give state three fields: Type (icon shape), title (title), and Content (content). Dart: modify /list/item/state.dart as follows

import 'package:fish_redux/fish_redux.dart';

class ItemState implements Cloneable<ItemState> {

  int type;
  String title;
  String content;

  ItemState({this.type, this.title, this.content});

  @override
  ItemState clone() {
    returnItemState() .. type = type .. title = title .. content = content; } } ItemState initState(Map<String.dynamic> args) {
  return ItemState();
}
Copy the code

Then we implement the view of item, using the state data above and displaying different ICONS depending on type (see comments). / list/item/the dart is as follows

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

import 'action.dart';
import 'state.dart';

Widget buildView(ItemState state, Dispatch dispatch, ViewService viewService) {
  return Container(
    margin: EdgeInsets.fromLTRB(0.0.0.10),
    height: 120.0,
    color: Colors.white,
    child: GestureDetector(
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          // Left icon
          Container(
            padding: const EdgeInsets.only(right: 5.0),
            child: Center(
              child: Icon(
              // Different types display different ICONS
                state.type == 1 ? Icons.account_circle : Icons.account_box,
                size: 50.0,),),),/ / on the right side
          Expanded(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.start,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                // The header section
                Container(
                  height: 30,
                  child: Text(
                    state.title,
                    style: TextStyle(fontSize: 22.0),),),// Content section
                Text(
                  state.content,
                  style: TextStyle(fontSize: 16.0),
                ),
              ],
            ),
          ),
        ],
      ),
      onTap: () {
        //todo click events},),); }Copy the code

1.3 Associating Components with Web Pages

Component concludes. Next we use the components in the list.

Step 1 Create the Adapter

First, store the State data of each Item in the State of List. / list/state. The dart/as follows

import 'package:fish_demo/list/item/state.dart';
import 'package:fish_redux/fish_redux.dart';

class ListState implements Cloneable<ListState> {
  
  List<ItemState> items;    // Save item state

  @override
  ListState clone() {
    returnListState() .. items = items; } } ListState initState(Map<String.dynamic> args) {
  return ListState();
}
Copy the code

Then we associate the list with the item, and we use one of the fish-Redux components called adapter. Create FishReduxTemplate with the plugin in the list package. Then select the DynamicFlowAdapter and uncheck all other boxes. Name it list as follows

The second step implements the Connector

We see that the default Adapter code has two classes ready for us: a ListAdapter and a _ListConnector. In the ListAdapter, we configure the components to be associated, that is, add the components to the pool. And list and component data adaptation by implementing a connector. The completed /list/adapter.dart is as follows

import 'package:fish_demo/list/state.dart';
import 'package:fish_redux/fish_redux.dart';

import 'item/component.dart';
import 'item/state.dart';

class ListAdapter extends DynamicFlowAdapter<ListState> {
  ListAdapter()
      : super(
          pool: <String, Component<Object> > {"MyItem": ItemComponent(),  // Reference the component
          },
          connector: _ListConnector(),
        );
}

class _ListConnector extends ConnOp<ListState.List<ItemBean>> {
  @override
  List<ItemBean> get(ListState state) {
    // Check whether the items in ListState are empty
    if(state.items? .isNotEmpty ==true) {
      // If not empty, convert item data to a list of ItemBeans
      return state.items
        .map<ItemBean>((ItemState data) => ItemBean('MyItem', data))
        .toList(growable: true);
    }else{
      // If it is empty, return the empty list
      return<ItemBean>[]; }}@override
  void set(ListState state, List<ItemBean> items) {
    // The process of modifying the ItemBean changes to the item state
    if(items? .isNotEmpty ==true) {
      state.items = List<ItemState>.from(
        items.map<ItemState>((ItemBean bean) => bean.data).toList());
    } else{ state.items = <ItemState>[]; }}@override
  subReducer(reducer) {
    // TODO: implement subReducer
    return super.subReducer(reducer); }}Copy the code

The third step is to add the Adapter to the dependencies of the list page

We open the Page file of the List page and add adapter to the dependencies of the page. The following

import 'package:fish_demo/list/adapter.dart';/ / note 1
import 'package:fish_redux/fish_redux.dart' hide ListAdapter;/ / note 1

import 'effect.dart';
import 'reducer.dart';
import 'state.dart';
import 'view.dart';

class ListPage extends Page<ListState.Map<String.dynamic>> {
  ListPage()
      : super(
            initState: initState,
            effect: buildEffect(),
            reducer: buildReducer(),
            view: buildView,
            dependencies: Dependencies<ListState>(
                adapter: NoneConn<ListState>() + ListAdapter(),/ / note 2
                slots: <String, Dependent<ListState>>{
                }),
            middleware: <Middleware<ListState>>[
            ],);

}
Copy the code

I’ve made two notes about the code above.

Note 1: We are referring to the custom ListAdapter, not the ListAdapter class that comes with Fish-redux. (Should have known the name when not called ListAdapter…)

Note 2: The “plus” used here is the fish-redux overloaded operator. The latter is our custom Adapter, and since we no longer need the connector on the outer layer, the former passes in a NoneConn.

Step 4 Lists the UI

Dart: /list/view.dart: /list/view.dart: / list/the dart is as follows

import 'package:fish_redux/fish_redux.dart';
import 'package:flutter/material.dart';
import 'state.dart';

Widget buildView(ListState state, Dispatch dispatch, ViewService viewService) {
  
  ListAdapter adapter = viewService.buildAdapter();     / / create the adapter

  return Scaffold(
      appBar: new AppBar(
        title: new Text('List page'),
      ),
      body: Container(
        child: ListView.builder(
          itemBuilder: adapter.itemBuilder, // Configure adapter to list
          itemCount: adapter.itemCount,     //))); }Copy the code

1.4 With fake data

Finally, let’s add some fake data to the List page to see what happens. We’ve already learned how to do that

  1. Effect creates dummy data when the page is initialized
  2. Effect sends an action with fake data
  3. Reducer received action and updated state with dummy data

This time the action takes parameters. Post the code

Let’s run it and see what it looks like

2 Use global Store to change the theme

This time let’s touch store. It is responsible for managing global state, as demonstrated by theme colors.

2.1 Creating a Global State

Whereas previously pages and components were created using the plug-in template, Store created them manually. Create a package called Store. Dart is then created, which we use to hold global state. In this case, save the theme color. / store/state. The dart is as follows

import 'dart:ui';
import 'package:fish_redux/fish_redux.dart';

abstract class GlobalBaseState {
  Color get themeColor;
  set themeColor(Color color);
}

class GlobalState implements GlobalBaseState.Cloneable<GlobalState> {
  @override
  Color themeColor;

  @override
  GlobalState clone() {
    returnGlobalState(); }}Copy the code

Notice that we define an abstract class GlobalBaseState that contains the themeColor field. We’ll let all page states inherit it later. We also wrote an implementation class GlobalState, which is the GlobalState.

2.2 create the store

Dart is the App store. Dart is the App store. / store/store. The dart is as follows

import 'package:fish_redux/fish_redux.dart';
import 'state.dart';

class GlobalStore {
  static Store<GlobalState> _globalStore;

  static Store<GlobalState> getstore => _globalStore ?? = createStore<GlobalState>(GlobalState(), buildReducer()); }Copy the code

You can see that the Store holds global state, and it can also have a Reducer to handle events. Next we define its actions and reducer.

2.3 Create Store Actions and reducer

Dart is created to define an event that changes the color of the theme. / store/action. The dart is as follows

import 'package:fish_redux/fish_redux.dart';

enum GlobalAction { changeThemeColor }

class GlobalActionCreator {
  static Action onchangeThemeColor() {
    return constAction(GlobalAction.changeThemeColor); }}Copy the code

Dart is created to receive events and change the GlobalState theme color. Dart is as follows (here we have the theme color switch back and forth between blue and green)

import 'dart:ui';
import 'package:fish_redux/fish_redux.dart';
import 'package:flutter/material.dart' hide Action;
import 'action.dart';
import 'state.dart';

Reducer<GlobalState> buildReducer() {
  return asReducer(
    <Object, Reducer<GlobalState>>{
      GlobalAction.changeThemeColor: _onchangeThemeColor,
    },
  );
}

GlobalState _onchangeThemeColor(GlobalState state, Action action) {
  final Color color =
  state.themeColor == Colors.green ? Colors.blue : Colors.green;
  returnstate.clone().. themeColor = color; }Copy the code

And then the whole store is written. You and your family

2.4 inheritance GlobalBaseState

We inherited GlobalBaseState state from all pages and set the title bar color to themeColor in the page view. There are three interfaces (entrance, grid and list) that need to be modified. Take the list page as an example, the first one is /list/state.dart

Then/list/view. The dart

The other two pages are shown in the same way.

2.5 associated state

How do you relate individual page states to the global GlobalState? We need to configure the visitor in app.dart. In this case, we determine whether the page inherits GlobalBaseState and then associate the page with the global Store, meaning that the page’s state changes with the global state update. The modified app.dart is as follows

Widget createApp() {
  final AbstractRoutes routes = PageRoutes(
    pages: <String, Page<Object.dynamic> > {'entrance_page': EntrancePage(),
      'grid_page': GridPage(),
      'list_page': ListPage(),
    },
    visitor: (String path, Page<Object.dynamic> page) {
      /// The condition Page is met<T>, T is a subclass of GlobalBaseState.
      if (page.isTypeof<GlobalBaseState>()) {
        // set up a one-way data connection for AppStore driver PageStore
        /// 1. Parameter 1 AppStore
        /// 2. Parameter 2 How should pagestore. state change when AppStore
        page.connectExtraStore<GlobalState>(
          GlobalStore.store, (Object pagestate, GlobalState appState) {
          final GlobalBaseState p = pagestate;
          if(p.themeColor ! = appState.themeColor) {if (pagestate is Cloneable) {
              final Object copy = pagestate.clone();
              final GlobalBaseState newState = copy;
              newState.themeColor = appState.themeColor;
              returnnewState; }}returnpagestate; }); }});// The following omission...
}
Copy the code

2.6 Triggering a Theme Change

Finally, I want to switch the theme color by clicking item on the List page.

The first step

Dart: /list/item/action.dart

import 'package:fish_redux/fish_redux.dart';

enum ItemAction { action, onThemeChange }

class ItemActionCreator {
  static Action onAction() {
    return const Action(ItemAction.action);
  }

  static Action onThemeChange() {
    return constAction(ItemAction.onThemeChange); }}Copy the code

The second step

We send this event when the item clicks. / list/item/the dart is as follows


Widget buildView(ItemState state, Dispatch dispatch, ViewService viewService) {
  return Container(
    margin: EdgeInsets.fromLTRB(0.0.0.10),
    height: 120.0,
    color: Colors.white,
    child: GestureDetector(
      child: Row(
        / / to omit...), onTap: () { dispatch(ItemActionCreator.onThemeChange()); },),); }Copy the code

The third step

Receives the event in Effect and sends the global change theme color event we defined earlier. / list/item/effect. The dart is as follows

import 'package:fish_demo/store/action.dart';
import 'package:fish_demo/store/store.dart';
import 'package:fish_redux/fish_redux.dart';
import 'action.dart';
import 'state.dart';

Effect<ItemState> buildEffect() {
  return combineEffects(<Object, Effect<ItemState>>{
    ItemAction.action: _onAction,
    ItemAction.onThemeChange: _onThemeChange,
  });
}

void _onAction(Action action, Context<ItemState> ctx) {
}

void _onThemeChange(Action action, Context<ItemState> ctx) {
  GlobalStore.store.dispatch(GlobalActionCreator.onchangeThemeColor());
}
Copy the code

Finally run to see the effect: step by step into the list page, click item several times, the theme color changes accordingly. Return to the parent page, the theme color has also been changed.

conclusion

So far, we have seen some basic uses of fish-Redux. Since students on the client side have little contact with redux framework, they should change their thinking, read more documents and think more when using it.

Project source github.com/Jegaming/Fi…

🤗 If my content is helpful to you, welcome to like, comment, forward, favorites.