如何在 flutter redux 中观察状态变化

How to watch state changes in flutter redux

我是 Flutter Redux 的新手,我遇到了一个问题,我完全不知道如何处理它!我提取了主要代码以保持这种简单 - 点击指示器切换 PageView,滚动 PageView 以同步指示器。这是我的代码:

应用程序状态:

class AppState {
  final List menuList;
  final int currentIndex;

  AppState({this.menuList, this.currentIndex});
}

减速器:

 AppState appReducer(AppState state, Object action) {
  return AppState(
      menuList: menuListReducer(state.menuList, action),
      currentIndex: currentIndexReducer(state.currentIndex, action));
}

final menuListReducer = combineReducers<List>(
    [TypedReducer<List, SetMenuListAction>(_setMenuList)]);

List _setMenuList(List menuList, SetMenuListAction action) {
  menuList = action.menuList;
  return menuList;
}

final currentIndexReducer = combineReducers<int>(
    [TypedReducer<int, SetCurrentIndexAction>(_setCurrentIndex)]);

int _setCurrentIndex(int currentIndex, SetCurrentIndexAction action) {
  currentIndex = action.index;
  return currentIndex;
}

动作:

class SetMenuListAction {
  List menuList;

  SetMenuListAction(this.menuList);
}

class SetCurrentIndexAction {
  int index;

  SetCurrentIndexAction(this.index);
}

主要逻辑:

void main() {
  final store = Store<AppState>(
    appReducer,
    initialState: AppState(menuList: [
      {
        'picUrl': 'http://pic3.16pic.com/00/55/42/16pic_5542988_b.jpg',
        'description': 'this is the first image'
      },
      {
        'picUrl': 'http://photo.16pic.com/00/38/88/16pic_3888084_b.jpg',
        'description': 'this is the second image'
      },
      {
        'picUrl':
            'http://img4.imgtn.bdimg.com/it/u=3434394339,2114652299&fm=214&gp=0.jpg',
        'description': 'this is the third image'
      },
      {
        'picUrl': 'http://pic1.win4000.com/pic/2/07/8c57e143b1.jpg',
        'description': 'this is the fourth image'
      },
    ], currentIndex: 0),
  );

  runApp(App(
    store: store,
  ));
}

// App
class App extends StatelessWidget {
  final Store<AppState> store;

  const App({Key key, this.store}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return StoreProvider(
      store: store,
      child: MaterialApp(title: 'Flutter redux example', home: MyDetail()),
    );
  }
}

class MyDetail extends StatefulWidget {
  @override
  _MyDetailState createState() => _MyDetailState();
}

class _MyDetailState extends State<MyDetail> with TickerProviderStateMixin {
  PageController _controller;

  @override
  void initState() {
    _controller = PageController(initialPage: 0);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return StoreConnector<AppState, int>(
      converter: (store) => store.state.currentIndex,
      onDidChange: (newIdx) {
        //this won't work because the _controller hasn't been attached to PageView
        _controller.jumpToPage(newIdx);
      },
      builder: (BuildContext context, int idx) {
        return StoreConnector<AppState, List>(
          converter: (store) => store.state.menuList,
          onDidChange: (newList) {
            //maybe do something further
          },
          builder: (BuildContext context, List menus) {
            return Container(
              color: Colors.white,
              child: Column(
                children: <Widget>[
                  //pageview
                  Expanded(
                    child: PageView(
                      children: menus.map((item) {
                        return Column(
                          children: <Widget>[
                            Image.network(item['picUrl']),
                            Text(
                              item['description'],
                              style: TextStyle(fontSize: 24.0),
                            )
                          ],
                        );
                      }).toList(),
                      onPageChanged: (int index) {
                        StoreProvider.of<AppState>(context)
                            .dispatch(SetCurrentIndexAction(index));
                      },
                      physics: BouncingScrollPhysics(),
                    ),
                  ),
                  //indicators
                  Container(
                    margin: EdgeInsets.only(bottom: 50.0),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: menus
                          .asMap()
                          .map((i, item) => MapEntry(
                              i,
                              GestureDetector(
                                onTap: () {
                                  //this won't work either maybe because the widgets is rebuilding
                                  _controller.jumpToPage(i);
                                  StoreProvider.of<AppState>(context)
                                      .dispatch(SetCurrentIndexAction(i));
                                },
                                child: Container(
                                  width: 10.0,
                                  height: 10.0,
                                  color: i == idx
                                      ? Colors.purpleAccent
                                      : Colors.blue,
                                  margin: EdgeInsets.only(right: 10.0),
                                ),
                              )))
                          .values
                          .toList(),
                    ),
                  )
                ],
              ),
            );
          },
        );
      },
    );
  }
}

抱歉,代码太长了,但我认为这可能有助于理解我的问题:

  1. 当我点击指示器时,我想同步PageView,即_controller.jumpToPage(i),但它会显示错误。那么如何进行这项工作呢?
  2. 我可以在另一个屏幕上更改currentIndex,如何同步PageView?
  3. 有什么方法可以观察状态变化(单独,而不是整个状态)并做些什么?

调试您的代码后,我发现您在 PageView 中缺少 controller: _controller,这应该可以解决它:

              Expanded(
                child: PageView(
                  controller: _controller,
                  children: menus.map((item) {
                    return Column(
                      children: <Widget>[
                        Image.network(item['picUrl']),
                        Text(
                          item['description'],
                          style: TextStyle(fontSize: 24.0),
                        )
                      ],
                    );
                  }).toList(),
                  onPageChanged: (int index) {
                    StoreProvider.of<AppState>(context)
                        .dispatch(SetCurrentIndexAction(index));
                  },
                  physics: BouncingScrollPhysics(),
                ),
              ),