【问题标题】:how to use setState inside another class?如何在另一个类中使用 setState?
【发布时间】:2019-06-27 00:33:17
【问题描述】:

我在设置变量状态时遇到问题,因为我正在使用stateful 小部件之外的其他类。
buildActions 方法内的第 115 行我想设置 _selectedStores = selectedStores;。我该如何设置状态?
我尝试使用callback,但没有成功。

import 'package:flutter/material.dart';

class SearchDemo extends StatefulWidget {
  @override
  _SearchDemoState createState() => _SearchDemoState();
}

class _SearchDemoState extends State<SearchDemo> {
  final _SearchDemoSearchDelegate _delegate = _SearchDemoSearchDelegate();
  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();

  String _lastSearchSelected;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(
        title: const Text('Search Demo'),
        actions: <Widget>[
          IconButton(
            tooltip: 'Search',
            icon: const Icon(Icons.search),
            onPressed: () async {
              final String selected = await showSearch<String>(
                context: context,
                delegate: _delegate,
              );
              if (selected != null && selected != _lastSearchSelected) {
                setState(() {
                  _lastSearchSelected = selected;
                });
              }
            },
          ),
        ],
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Last search: ${_lastSearchSelected ?? 'NONE'}.'),
          ],
        ),
      ),
    );
  }
}

class Stores {
  int id;
  String name;

  Stores(this.id, this.name);

  static List<Stores> getStores() {
    return <Stores>[
      Stores(1, 'Amazon'),
      Stores(2, 'Flipkart'),
      Stores(3, 'Snapdeal'),
    ];
  }
}

class _SearchDemoSearchDelegate extends SearchDelegate<String> {
  List<Stores> _stores = Stores.getStores();
  List<DropdownMenuItem<Stores>> _dropdownMenuItems;
  Stores _selectedStores;

  List<DropdownMenuItem<Stores>> buildDropdownMenuItems(List stores) {
    List<DropdownMenuItem<Stores>> items = List();
    for (Stores stores in stores) {
      items.add(
        DropdownMenuItem(
          value: stores,
          child: Text(stores.name),
        ),
      );
    }
    return items;
  }

  @override
  Widget buildLeading(BuildContext context) {
    return IconButton(
      tooltip: 'Back',
      icon: AnimatedIcon(
        icon: AnimatedIcons.menu_arrow,
        progress: transitionAnimation,
      ),
      onPressed: () {
        close(context, null);
      },
    );
  }

  @override
  Widget buildSuggestions(BuildContext context) {
    return _SuggestionList(
      query: query,
      onSelected: (String suggestion) {
        print(suggestion);
      },
    );
  }

  @override
  Widget buildResults(BuildContext context) {}

  @override
  List<Widget> buildActions(BuildContext context) {
    _dropdownMenuItems = buildDropdownMenuItems(_stores);
    _selectedStores = _dropdownMenuItems[0].value;
    void onChangeDropdownItem(Stores selectedStores) {
      setState(() {
        _selectedStores = selectedStores;
      });
    }

    return <Widget>[
      query.isEmpty
          ? Container(
              padding: const EdgeInsets.only(right: 5.0, top: 5.0),
              child: DropdownButtonHideUnderline(
                child: DropdownButton(
                  elevation: 0,
                  value: _selectedStores,
                  items: _dropdownMenuItems,
                  onChanged: onChangeDropdownItem,
                ),
              ),
            )
          : IconButton(
              tooltip: 'Clear',
              icon: const Icon(Icons.clear),
              onPressed: () {
                query = '';
              },
            ),
    ];
  }
}

List<String> getHistory() {
  //Get Last Searched products from device storage *Pending*
  final List<String> _history = <String>[
    "iPhone X 64GB Silver",
    "Galaxy S10+ White",
    "Apple Watch Series 3",
    "Samson C01UPRO",
    "Cooler Master masterbox 5"
  ];
  return _history;
}

class _SuggestionList extends StatelessWidget {
  const _SuggestionList({this.query, this.onSelected});

  final String query;
  final ValueChanged<String> onSelected;

  @override
  Widget build(BuildContext context) {
    //Get Data From API *Pending*
    final List<String> _data = <String>[
      "iPhone X 64GB Silver",
      "Galaxy S10+ White",
      "Apple Watch Series 3",
      "Samson C01UPRO",
      "Cooler Master Masterbox 5"
    ];
    final List<String> suggestions = query.isEmpty
        ? getHistory()
        : _data
            .where((p) => p.toLowerCase().contains(query.toLowerCase()))
            .toList();
    return ListView.builder(
      itemCount: suggestions.length,
      itemBuilder: (BuildContext context, int i) {
        final String suggestion = suggestions[i];
        return ListTile(
          leading: query.isEmpty ? const Icon(Icons.history) : const Icon(null),
          title: Text(suggestion),
          onTap: () {
            onSelected(suggestion);
          },
        );
      },
    );
  }
}

【问题讨论】:

    标签: flutter dart


    【解决方案1】:

    setState 方法只是StatefulWidgets 的一部分,不应传递该信息。不推荐,也不是一个好的开发实践。你能做到吗?是的,像这样:

    class OtherClass {
      final State state;
    
      OtherClass(this.state);
    }
    
    class Home extends StatefulWidget {
      @override
      _HomeState createState() => _HomeState();
    }
    
    class _HomeState extends State<Home> {
    
      @override
      void initState() {
        super.initState();
    
        OtherClass(this);
      }
    }
    

    但是,我再一次不推荐这个。您应该使用某种FutureStream 将您的数据发送到您的StatefulWidget,然后在那里使用您的setState,它应该在哪里。

    【讨论】:

    • 感谢您的信息,如果没有,那么在搜索栏中实现 DropdownButton 的正确方法是什么?
    • 使用类似 InheritedWidget 或更好的 Provider 包装器来连接模型更新和视图更新。
    猜你喜欢
    • 2021-08-03
    • 1970-01-01
    • 2019-01-18
    • 1970-01-01
    • 2019-07-14
    • 2021-10-10
    • 2021-05-21
    • 2021-05-04
    • 2016-04-13
    相关资源
    最近更新 更多