Flutter的setState和插件redux

484 阅读2分钟

杠精求放过

redux是全局状态管理插件,但是它也可以解决build在setState以后调用问题;

  • 这里有一个疑问,Redux是最顶层传入的,那么层层遍历找到这个值是否也很耗费性能;

setState和redux

setState每次使用都会重新渲染整个页面

//在一个使用flutter create .创建的模板项目中
//我们在_MyHomePageState的Widget build里面加一个print
class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    //你会发现当你每次点击悬浮按钮的时候都会打印'build runing ?'
    print('build runing ?');
    return Scaffold(...
    );
  }
}

void _increment() {
  setState(){
    //这个玩意每次执行完成以后
    //flutter都要去重新执行build
    //数据量小一点也还ok
    //如果数据量很大,那无疑这个就是噩梦了
    _counter ++
  }
}

刚开始我还不知道咋解决这个问题,我想先试试redux

dependencies:
  flutter:
    sdk: flutter


  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.2
  flutter_redux: ^0.7.0

然后

// 定义store
class AppStore {
  int count = 0;

  AppStore.initCount() {
    this.count = 0;
  }

  AppStore(this.count);
}

// 定义actions
enum AppActions { Increment }
// 定义reducer
AppStore reducer(AppStore store, dynamic actions) {
  print('store runing reducer');
  switch (actions['type']) {
    case AppActions.Increment:
      //定义count++也就是_increment
      store.count++;
      return store;
    default:
      return store;
  }
}

顶层入口传入Store

void main() {
  // 初始化 store
  final Store store =
      Store<AppStore>(reducer, initialState: AppStore.initCount());
  // store作为参数要放到application的最顶层
  runApp(MyApp(store: store));
}

StoreProvider包裹MaterialApp

class MyApp extends StatelessWidget {
  final Store<AppStore> store;

  const MyApp({Key key, this.store}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    // 整个application的最顶层是StoreProvider
    return StoreProvider(
        store: store,
        child: MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: MyHomePage(title: 'Flutter Demo Home Page'),
        ));
  }
}

修改floatingActionButton Widget

// 使用store里面的reducer
floatingActionButton: StoreConnector<AppStore, Function>(
// 这里箭头函数要注意
// dispatch 调用reducer
// 参数就是action ,上面定义了action的类型是dynamic
// 所以这里理论上是可以传入任意的值
// 但是我习惯用map类型
// 这里map里可以定义两个key
// 一个是type,也就是action
// 一个是data,也就是要传入的数据

// 在flutter_redux中converter的返回值作为builder的第二个参数
// 而这个参数可以是state也可以是reducer
converter: (store) => () => store.dispatch({
    "type": AppActions.Increment, /*"data":""*/
}),
builder: (context, callback) {
  return FloatingActionButton(
    onPressed: callback,
    tooltip: 'Increment',
    child: Icon(Icons.add),
  );
}),

修改Text Widget:

// 使用store.state.count
// 注意这里的类型<AppStore, String>
StoreConnector<AppStore, String>(converter: (store) {
    return store.state.count.toString();
  },
  builder: (context, count) {
    return Text(
      '$count',
      style: Theme.of(context).textTheme.headline4,
    );
}),
store里面的print('store runing reducer');

然后你就会发现build这玩意不再打印

最后放一张图