0

for example: I have a list, when I modify an item in the list, only the modified item is rebuilt, when I append an item, the list rebuilds the newly added item, not all items in the entire list are rebuilt. When I toggle the selection, I also want to just rebuild the item that needs to be changed.

Click on the image to view the demo

environment:
 sdk: ^3.7.0
provider: ^6.1.4
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'dart:math' as math;
class TabsProvider with ChangeNotifier {
 int _checkedId = 1;
 final List<TabItem> _items = [
 TabItem(id: 1, title: 'Tab 1'),
 TabItem(id: 2, title: 'Tab 2'),
 TabItem(id: 3, title: 'Tab 3'),
 ];
 List<TabItem> get items => List.unmodifiable(_items);
 int get currentCheckedId => _checkedId;
 changeCheckedId(int id) {
 _checkedId = id;
 notifyListeners();
 }
 appendItem(TabItem item) {
 _items.add(item);
 notifyListeners();
 }
 itemIncreasing(int id) {
 final index = _items.indexWhere((element) => element.id == id);
 if (index != -1) {
 // 创建新的 item 实例以确保触发更新
 _items[index] = TabItem(
 id: _items[index].id,
 title: _items[index].title,
 total: _items[index].total + 1,
 );
 notifyListeners(); // 确保调用这个方法
 }
 }
 removeItem(int id) {
 _items.removeWhere((element) => element.id == id);
 notifyListeners();
 }
}
// ignore: camel_case_types
class otherDemoIndexRoute extends StatefulWidget {
 const otherDemoIndexRoute({super.key});
 @override
 State<otherDemoIndexRoute> createState() => _otherDemoIndexRouteState();
}
// ignore: camel_case_types
class _otherDemoIndexRouteState extends State<otherDemoIndexRoute> {
 // 创建两个控制器实例
 @override
 void initState() {
 super.initState();
 }
 @override
 Widget build(BuildContext context) {
 print('主入口');
 return Scaffold(
 appBar: AppBar(title: Text('provider 管理集合实例')),
 body: ChangeNotifierProvider(
 create: (context) => TabsProvider(),
 child: SingleChildScrollView(
 padding: const EdgeInsets.all(16.0),
 child: Tabs(),
 ),
 ),
 );
 }
}
class Tabs extends StatefulWidget {
 const Tabs({super.key});
 @override
 State<Tabs> createState() => _TabsState();
}
class _TabsState extends State<Tabs> {
 @override
 Widget build(BuildContext context) {
 return Column(
 children: [
 Center(
 child: Selector<TabsProvider, int>(
 selector: (context, provider) => provider.currentCheckedId,
 builder: (context, currId, child) {
 var text = 'The current selection is:${currId.toString()}';
 print(text);
 return Text(text);
 },
 ),
 ),
 Selector<TabsProvider, List<TabItem>>(
 selector: (context, provider) => provider.items,
 // shouldRebuild: (previous, next) {
 // return previous.length != next.length;
 // },
 builder: (context, tabList, child) {
 print('build——selector');
 List<Widget> widgets = [];
 for (var item in tabList) {
 widgets.add(_buildTabItem(context, item));
 }
 return Wrap(spacing: 10, children: [...widgets]);
 },
 ),
 Wrap(
 spacing: 10,
 children: [
 TextButton(
 onPressed: () {
 var tabsProvider = context.read<TabsProvider>();
 var list = tabsProvider.items.map((item) => item.id).toList();
 int maxValue = list.reduce(
 (value, element) => math.max(value, element),
 );
 tabsProvider.appendItem(
 TabItem(id: maxValue + 1, title: 'title${maxValue + 1}'),
 );
 },
 child: Text('Add item'),
 ),
 TextButton(
 onPressed: () {
 context.read<TabsProvider>().itemIncreasing(1);
 },
 child: Text('Fisrt item +1'),
 ),
 ],
 ),
 ],
 );
 }
 /// 构建TabItem组件
 Widget _buildTabItem(BuildContext context, TabItem item) {
 final tabsProvider = context.read<TabsProvider>();
 return Selector<TabsProvider, int>(
 selector: (context, provider) => provider.currentCheckedId,
 builder: (context, currId, child) {
 print('build_tabitem');
 return Material(
 color: currId == item.id ? Colors.red[100] : Colors.transparent,
 borderRadius: BorderRadius.all(Radius.circular(8.0)),
 child: InkWell(
 mouseCursor: SystemMouseCursors.click, //forbidden 禁止点击效果
 onTap: () {
 tabsProvider.changeCheckedId(item.id);
 },
 child: Container(
 padding: const EdgeInsets.all(8.0),
 decoration: BoxDecoration(
 border: Border.all(color: Colors.blue),
 borderRadius: BorderRadius.circular(8.0),
 ),
 child: Row(
 mainAxisSize: MainAxisSize.min,
 children: [
 Text(
 '${item.title}--${item.total}',
 style: const TextStyle(color: Colors.black),
 ),
 ],
 ),
 ),
 ),
 );
 },
 );
 }
}
class TabItem {
 int id;
 String title;
 int total;
 TabItem({required this.id, required this.title, this.total = 0});
}

How can I switch items, change items, or add new items, and only rebuild the corresponding items, instead of the entire tabs component?

2
  • '''How can I switch items, change items, or add new items, and only rebuild the corresponding items, instead of the entire tabs component?''' - check ValueListenableBuilder Commented May 9, 2025 at 4:12
  • Thank you for your help. I'll give it a try! Commented May 9, 2025 at 6:10

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.