在 Flutter 中使用 Hook Widget 强制构建小部件树

问题描述

我有一个页面,它动态地接受未来列表和回调以获取未来列表以接收数据并能够在刷新时刷新它。简化版本如下所示:

class ListSearchPage<T> extends StatefulWidget {

  final Future<List<T>> itemsFuture;
  final ValueGetter<Future<List<T>>> getItemsFuture;

  const ListSearchPage({Key key,this.getItemsFuture,this.itemsFuture})
      : super(key: key);

  @override
  _ListSearchPageState createState() => _ListSearchPageState();
}


class _ListSearchPageState<T> extends State<ListSearchPage> {
  Future<List<T>> itemsFuture;
  TextEditingController _controller;

  @override
  void initState() {
    itemsFuture = widget.itemsFuture;
    _controller = TextEditingController();
    super.initState();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
              future:
                  itemsFuture != null ? itemsFuture : widget.getItemsFuture(),builder: (context,snapshot) {

                   return RefreshIndicator(
                     onRefresh: () async {
                        setState(() {
                          itemsFuture = null;
                          _controller.text = '';
                        });
                      },child: ...
                   );
                });
    }
}

所以第一次,页面加载时已经加载了未来。当用户刷新时,我将未来标记为 null,以便调用回调并重新获取数据。

我现在正在尝试在整个应用程序中实现 flutter_hooks,并且我已将此小部件重构为如下所示(简化版):


class ListSearchPage<T> extends HookWidget {
  
  final Future<List<T>> itemsFuture;
  final ValueGetter<Future<List<T>>> getItemsFuture;

  const ListSearchPage({Key key,this.itemsFuture})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    final itemsFutureNotifier = useState(this.itemsFuture);
    final TextEditingController _controller = useTextEditingController();
    return FutureBuilder(
              future:
              itemsFutureNotifier.value != null ? itemsFutureNotifier.value : getItemsFuture(),snapshot) {
                   return RefreshIndicator(
                     onRefresh: () async {
                        itemsFutureNotifier.value = null;
                        _controller.text = '';
                      },child: ...
                   );
                });
    }

}

这是第一次有效,但是此后该值继续分配为 null,因此值通知程序不会收到有关更改的通知。在这种情况下,如何强制小部件像以前一样重建?作为奖励,您是否看到了更好的解决方案?

提前致谢。

更新

这是itemsFuture

final future = useMemoized(() => repository.fetchData());

这是getItemsFuture

() => repository.fetchData()

它背后的想法是在打开搜索页面之前获取数据。在我的用例中有效。

我已经找到了解决我的问题的方法,但我不会将其作为答案发布,因为我不认为它是干净的,我宁愿看看是否有人找到了正确的方法。

目前的解决方案

@override
  Widget build(BuildContext context) {
    // feels like a dirty solution for rebuilding on refresh
    final counterNotifier = useState(0);
    final itemsFutureNotifier = useState(this.itemsFuture);
    final TextEditingController _controller = useTextEditingController();

 return ValueListenableBuilder(
            valueListenable: counterNotifier,value,child) {
return FutureBuilder(
              future:
              itemsFutureNotifier.value != null ? itemsFutureNotifier.value : getItemsFuture(),snapshot) {
                   return RefreshIndicator(
                     onRefresh: () async {
                        counterNotifier.value++;
                        itemsFutureNotifier.value = null;
                        _controller.text = '';
                      },child: ...
                   );
                });
});

如您所见,我现在有一个计数器通知程序,它将实际重建 ValueListenableBuilder 并使 FutureBuilder 获取数据

解决方法

我认为 itemsFuture 没有必要设置为 null(因为它可以是 useState 中的初始语句)。

@override
Widget build(BuildContext context) {
  final fetchData = useState(itemsFuture ?? getItemsFuture());

  return Scaffold(
    body: FutureBuilder(
      future: fetchData.value,builder: (context,snapshot) {
        return RefreshIndicator(
          onRefresh: () async {
            fetchData.value = getItemsFuture();
          },child: ...
        );
      },),);
}

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...