如何在Firestore中使用StreamBuilder?

huangapple go评论117阅读模式
英文:

How can i use Streambuilder with firestore?

问题

如何使用最新的Firestore数据更新我的数据?
这是我迄今为止的代码。


class Captain extends StatefulWidget {
  const Captain({
    Key? key,
  }) : super(key: key);
  @override
  _CaptainState createState() => _CaptainState();
}

class _CaptainState extends State<Captain> {
  PlutoGridStateManager? _stateManager; // 管理PlutoGrid的状态。
  List<PlutoColumn>? columns;
  List<PlutoRow>? plutoRows;
  List<Map<String, dynamic>>? captainData;
  @override
  void initState() {
    super.initState();
  }

  void _updateGrid() async {
    // final captainData =
    //     Provider.of<FirebaseProvider>(context, listen: false).captainSnapShot;
    captainData = await FirebaseServices.getCaptainData();
    final keys = [
      'S/N',
      'NAME',
      'CODE',
      '42 CLEARANCE',
      'Surkhet/ATR42/72',
      'Tumlingtar/ATR42',
      'Pokhara/72',
      'Simara/72',
    ];
    columns = keys.map((key) {
      return PlutoColumn(
        title: key.toUpperCase(),
        field: key,
        type: PlutoColumnType.text(),
        //width: 200,
      );
      // }
    }).toList();
    captainData!.sort((a, b) => int.parse(a['S/N']).compareTo(int.parse(
        b['S/N']))); // 按'S/N'列对_captainData列表进行排序。
    final plutoRows = captainData!.map((captain) {
      final cells = captain.map((key, value) {
        if (key == '42 CLEARANCE' ||
            key == 'Surkhet/ATR42/72' ||
            key == 'Tumlingtar/ATR42' ||
            key == 'Pokhara/72' ||
            key == 'Simara/72') {
          // 如果列名是需要下拉列表的五列之一,则创建一个具有值设置为'CLEARED'的PlutoCell对象。
          return MapEntry(
              key,
              PlutoCell(
                  value:
                      value)); // 将单元格的初始值设置为'CLEARED'。
        } else {
          // 如果列名不是需要下拉列表的五列之一,则创建一个具有值设置为_captainData列表中相应值的PlutoCell对象。
          return MapEntry(
              key,
              PlutoCell(
                  value: value ??
                      '')); // 将单元格的初始值设置为_captainData列表中的相应值。
        }
      });
      // 使用单元格列表创建PlutoRow对象。
      return PlutoRow(cells: cells);
    }).toList();
    PlutoGridStateManager.initializeRowsAsync(
      columns!,
      plutoRows,
    ).then((value) {
      // _stateManager!.refRows.addAll(FilteredList(initialList: value));
      _stateManager!.insertColumns(0, columns!);
      _stateManager!.appendRows(plutoRows);
      _stateManager!.notifyListeners();
    });
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: MediaQuery.of(context).size.width,
      height: MediaQuery.of(context).size.height,
      child: PlutoGrid(
        configuration: const PlutoGridConfiguration(
          columnSize: PlutoGridColumnSizeConfig(
              resizeMode: PlutoResizeMode.pushAndPull),
        ),
        columns: [], // 空列列表。
        rows: [], // 空行列表。
        onSelected: (PlutoGridOnSelectedEvent event) {
          final PlutoRow row = _stateManager!.rows.elementAt(event.rowIdx!);
          final String userId = row.cells['NAME']!.value.toString();
          if (event.cell!.column.field == 'S/N' ||
              event.cell!.column.field == 'NAME' ||
              event.cell!.column.field == 'CODE') {
          } else {
            openDetail(event.cell, event.cell!.column.field, userId);
          }
        },
        mode: PlutoGridMode.selectWithOneTap,
        onChanged: (PlutoGridOnChangedEvent event) {},
        onLoaded: (PlutoGridOnLoadedEvent event) {
          _stateManager = event
              .stateManager; // 使用PlutoGrid的新状态更新_stateManager对象。
          _updateGrid();
        },
      ),
    );
  }
英文:

How can I update my data with recent data from firestore ?
this is my code so far


class Captain extends StatefulWidget {
  const Captain({
    Key? key,
  }) : super(key: key);
  @override
  _CaptainState createState() => _CaptainState();
}

class _CaptainState extends State<Captain> {
  PlutoGridStateManager? _stateManager; // Manages the state of the PlutoGrid.
  List<PlutoColumn>? columns;
  List<PlutoRow>? plutoRows;
  List<Map<String, dynamic>>? captainData;
  @override
  void initState() {
    super.initState();
  }

  void _updateGrid() async {
    // final captainData =
    //     Provider.of<FirebaseProvider>(context, listen: false).captainSnapShot;
    captainData = await FirebaseServices.getCaptainData();
    final keys = [
      'S/N',
      'NAME',
      'CODE',
      '42 CLEARANCE',
      'Surkhet/ATR42/72',
      'Tumlingtar/ATR42',
      'Pokhara/72',
      'Simara/72',
    ];
    columns = keys.map((key) {
      return PlutoColumn(
        title: key.toUpperCase(),
        field: key,
        type: PlutoColumnType.text(),
        //width: 200,
      );
      // }
    }).toList();
    captainData!.sort((a, b) => int.parse(a['S/N']).compareTo(int.parse(
        b['S/N']))); // Sorts the _captainData list by the 'S/N' column.
    final plutoRows = captainData!.map((captain) {
      final cells = captain.map((key, value) {
        if (key == '42 CLEARANCE' ||
            key == 'Surkhet/ATR42/72' ||
            key == 'Tumlingtar/ATR42' ||
            key == 'Pokhara/72' ||
            key == 'Simara/72') {
          // If the column name is one of the five columns that require a dropdown list, a PlutoCell object is created with the value set to 'CLEARED'.
          return MapEntry(
              key,
              PlutoCell(
                  value:
                      value)); // Sets the initial value of the cell to 'CLEARED'.
        } else {
          // If the column name is not one of the five columns that require a dropdown list, a PlutoCell object is created with the value set to the corresponding value in the _captainData list.
          return MapEntry(
              key,
              PlutoCell(
                  value: value ??
                      '')); // Sets the initial value of the cell to the corresponding value in the _captainData list.
        }
      });
      // A PlutoRow object is created with the cells list.
      return PlutoRow(cells: cells);
    }).toList();
    PlutoGridStateManager.initializeRowsAsync(
      columns!,
      plutoRows,
    ).then((value) {
      // _stateManager!.refRows.addAll(FilteredList(initialList: value));
      _stateManager!.insertColumns(0, columns!);
      _stateManager!.appendRows(plutoRows);
      _stateManager!.notifyListeners();
    });
  }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: MediaQuery.of(context).size.width,
      height: MediaQuery.of(context).size.height,
      child: PlutoGrid(
        configuration: const PlutoGridConfiguration(
          columnSize: PlutoGridColumnSizeConfig(
              resizeMode: PlutoResizeMode.pushAndPull),
        ),
        columns: [], // Empty list of columns.
        rows: [], // Empty list of rows.
        onSelected: (PlutoGridOnSelectedEvent event) {
          final PlutoRow row = _stateManager!.rows.elementAt(event.rowIdx!);
          final String userId = row.cells['NAME']!.value.toString();
          if (event.cell!.column.field == 'S/N' ||
              event.cell!.column.field == 'NAME' ||
              event.cell!.column.field == 'CODE') {
          } else {
            openDetail(event.cell, event.cell!.column.field, userId);
          }
        },
        mode: PlutoGridMode.selectWithOneTap,
        onChanged: (PlutoGridOnChangedEvent event) {},
        onLoaded: (PlutoGridOnLoadedEvent event) {
          _stateManager = event
              .stateManager; // Updates the _stateManager object with the new state of the PlutoGrid.
          _updateGrid();
        },
      ),
    );
  }

I tried something like this but i don't receive any realtime updates ?


@override
Widget build(BuildContext context) {
final CollectionReference captainCollection =
FirebaseFirestore.instance.collection('CAPTAIN_DATA');
return SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: StreamBuilder<QuerySnapshot>(
stream: captainCollection.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Text('Loading...');
}
if (snapshot.hasData) {
//print all the data received
snapshot.data!.docs.forEach((element) {
print(element.data());
});
_updateGrid();
}
return PlutoGrid(
configuration: const PlutoGridConfiguration(
columnSize: PlutoGridColumnSizeConfig(
resizeMode: PlutoResizeMode.pushAndPull),
),
columns: [], // Empty list of columns.
rows: [], // Empty list of rows.
onSelected: (PlutoGridOnSelectedEvent event) {
final PlutoRow row =
_stateManager!.rows.elementAt(event.rowIdx!);
final String userId = row.cells['NAME']!.value.toString();
if (event.cell!.column.field == 'S/N' ||
event.cell!.column.field == 'NAME' ||
event.cell!.column.field == 'CODE') {
} else {
openDetail(event.cell, event.cell!.column.field, userId);
}
},
mode: PlutoGridMode.selectWithOneTap,
onChanged: (PlutoGridOnChangedEvent event) {},
onLoaded: (PlutoGridOnLoadedEvent event) {
_stateManager = event
.stateManager; // Updates the _stateManager object with the new state of the PlutoGrid.
_updateGrid();
},
);
}),
);
}

Any help is appriciated. one more question , do i need to get all the data if just one column is updated? how to handle minor changes by getting the value of only something that has changed not the whole database ?

答案1

得分: 1

以下是翻译好的部分:

你尝试使用的代码将不会接收到任何实时更新,因为你没有监听快照(snapshot.documentChanges)流。这个流将为集合中添加、更新或删除的每个文档都触发一个事件。你可以使用这个流来使用最新的Firestore数据更新你的用户界面。

以下是你可以使用的代码来监听快照(snapshot.documentChanges)流:

final CollectionReference captainCollection =
    FirebaseFirestore.instance.collection('CAPTAIN_DATA');

return StreamBuilder<QuerySnapshot>(
  stream: captainCollection.snapshots(),
  builder: (context, snapshot) {
    if (snapshot.hasError) {
      return const Text('出现了错误');
    }

    if (snapshot.connectionState == ConnectionState.waiting) {
      return const Text('加载中...');
    }

    if (snapshot.hasData) {
      // 监听文档变化
      snapshot.docChanges.forEach((change) {
        if (change.type == DocumentChangeType.added) {
          // 添加了新文档
          print('添加了新文档: ${change.doc.id}');
        } else if (change.type == DocumentChangeType.modified) {
          // 修改了现有文档
          print('修改了现有文档: ${change.doc.id}');
        } else if (change.type == DocumentChangeType.removed) {
          // 删除了现有文档
          print('删除了现有文档: ${change.doc.id}');
        }
      });

      // 使用最新数据更新用户界面
      _updateGrid();
    }

    return PlutoGrid(
      configuration: const PlutoGridConfiguration(
        columnSize: PlutoGridColumnSizeConfig(
            resizeMode: PlutoResizeMode.pushAndPull),
      ),
      columns: [], // 空的列列表
      rows: [], // 空的行列表
      onSelected: (PlutoGridOnSelectedEvent event) {
        final PlutoRow row =
            _stateManager!.rows.elementAt(event.rowIdx!);
        final String userId = row.cells['NAME']!.value.toString();
        if (event.cell!.column.field == 'S/N' ||
            event.cell!.column.field == 'NAME' ||
            event.cell!.column.field == 'CODE') {
        } else {
          openDetail(event.cell, event.cell!.column.field, userId);
        }
      },
      mode: PlutoGridMode.selectWithOneTap,
      onChanged: (PlutoGridOnChangedEvent event) {},
      onLoaded: (PlutoGridOnLoadedEvent event) {
        _stateManager = event
            .stateManager; // 使用PlutoGrid的新状态更新_stateManager对象。
        _updateGrid();
      },
    );
  },
);

第二部分关于处理小的更改,只获取已更改的值,你可以使用snapshot.docChanges.where()方法。

你可以使用以下代码来过滤流,只包括 NAME 字段已被修改的文档更改:

snapshot.docChanges.where((change) => change.doc.data['NAME'] != null);

这段代码只会为 NAME 字段不为 null 的文档更改触发事件。然后,你可以使用这个经过筛选的流来使用 NAME 字段的最新数据更新你的用户界面。
英文:
The code you tried to use will not receive any real-time updates because you are not listening to the snapshot.documentChanges stream. This stream will emit an event for every document that is added, updated, or deleted in the collection. You can use this stream to update your UI with the latest data from Firestore.
Here is the code that you can use to listen to the snapshot.documentChanges stream:
final CollectionReference captainCollection =
FirebaseFirestore.instance.collection(&#39;CAPTAIN_DATA&#39;);
return StreamBuilder&lt;QuerySnapshot&gt;(
stream: captainCollection.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Text(&#39;Something went wrong&#39;);
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Text(&#39;Loading...&#39;);
}
if (snapshot.hasData) {
// Listen to document changes
snapshot.docChanges.forEach((change) {
if (change.type == DocumentChangeType.added) {
// A new document was added
print(&#39;A new document was added: ${change.doc.id}&#39;);
} else if (change.type == DocumentChangeType.modified) {
// An existing document was modified
print(&#39;An existing document was modified: ${change.doc.id}&#39;);
} else if (change.type == DocumentChangeType.removed) {
// An existing document was removed
print(&#39;An existing document was removed: ${change.doc.id}&#39;);
}
});
// Update the UI with the latest data
_updateGrid();
}
return PlutoGrid(
configuration: const PlutoGridConfiguration(
columnSize: PlutoGridColumnSizeConfig(
resizeMode: PlutoResizeMode.pushAndPull),
),
columns: [], // Empty list of columns.
rows: [], // Empty list of rows.
onSelected: (PlutoGridOnSelectedEvent event) {
final PlutoRow row =
_stateManager!.rows.elementAt(event.rowIdx!);
final String userId = row.cells[&#39;NAME&#39;]!.value.toString();
if (event.cell!.column.field == &#39;S/N&#39; ||
event.cell!.column.field == &#39;NAME&#39; ||
event.cell!.column.field == &#39;CODE&#39;) {
} else {
openDetail(event.cell, event.cell!.column.field, userId);
}
},
mode: PlutoGridMode.selectWithOneTap,
onChanged: (PlutoGridOnChangedEvent event) {},
onLoaded: (PlutoGridOnLoadedEvent event) {
_stateManager = event
.stateManager; // Updates the _stateManager object with the new state of the PlutoGrid.
_updateGrid();
},
);
},
);
&amp; for the 2nd part.To handle minor changes by getting the value of only something that has changed, you can use the snapshot.docChanges.where() method.
you could use the following code to filter the stream to only include document changes where the NAME field has been modified:
snapshot.docChanges.where((change) =&gt; change.doc.data[&#39;NAME&#39;] != null);
This code will only emit events for document changes where the NAME field is not null. You can then use this filtered stream to update your UI with the latest data for the NAME field.

huangapple
  • 本文由 发表于 2023年7月31日 20:45:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76803772.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定