arraysflutterflutter-hooks

deleting an element always delete the last one in flutter


List storedWishes = [
      {
        'title': 'Phone',
        'description': 'a phone would be nice',
        'price': 200.00,
        'icon': Icon(Icons.phone)
      },
      {
        'title': 'monitor',
        'description': 'need it for a 2 screen setup',
        'price': 350.00,
        'icon': Icon(Icons.tv)
      },
      {
        'title': 'headphones',
        'description': 'need some high quality sound',
        'price': 100.00,
        'icon': Icon(Icons.headset)
      },
    ];
    final wishes = useState(storedWishes);

    return MaterialApp(
        home: Scaffold(
            appBar: AppBar(
              title: const Text('iWant'),
            ),
            body: Column(
              //map the wishes to a list of wish widgets
              children: wishes.value
                  .map((wish) => Wish(
                        title: wish['title'] as String,
                        description: wish['description'] as String,
                        price: wish['price'] as double,
                        icon: wish['icon'],
                        onDelete: () {
                          wishes.value.remove(wish)
                          wishes.notifyListeners();
                        },
                      ))
                  .toList(),
            )));

wish.dart code:

import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';

class Wish extends HookWidget {
  const Wish(
      {Key? key,
      this.title = 'default title',
      this.description = 'default description',
      this.price = 0.00,
      this.icon = const Icon(Icons.star),
      this.onDelete})
      : super(key: key);
  final String title;
  final String description;
  final double price;
  final dynamic icon;
  final VoidCallback? onDelete;
  @override
  Widget build(BuildContext context) {
    var wishes = useState({
      'title': title,
      'description': description,
      'price': price,
      'image': icon
    });
    return Card(
        child: Row(children: [
      wishes.value['image'] as Icon,
      Expanded(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(wishes.value['title'] as String),
            Text(wishes.value['description'] as String),
          ],
        ),
      ),
      Text((wishes.value['price'].toString()) + '\$'),
      Column(
        children: [
          Icon(Icons.edit),
          IconButton(
            onPressed: () {
              onDelete!();
            },
            icon: Icon(Icons.delete),
          )
        ],
      ),
    ]));
  }
}
    //   child: Card(
    //       child: Row(children: [
    //     ,
    //     Column(
    //       crossAxisAlignment: CrossAxisAlignment.start,
    //       children: [
    //         Text('Product name'),
    //         Text('Product description'),
    //       ],
    //     ),
    //     Column(
    //       crossAxisAlignment: CrossAxisAlignment.end,
    //       children: [
    //         Text('Price:'),
    //         Text('21\$'),
    //       ],
    //     ),
    //   ])),
    // );

clicking the delete button always removes last element when i click on delete of any other element

edit1: i've debugPrinted the array after clicking on delete icon and the array is edited correctly but the wrong widget get removed from the screen

here's a video: https://drive.google.com/file/d/1bEjHh4utynZk3QzSWw5gWv__YcpqKkb2/view?usp=sharing

edit2: I've removed hooks from the wish widget and that seems to work properly now ? anyway thanks for the help :)


Solution

  • I don't know why it's not working for you, but it works fine for me. Since I don't know what your Wish class looks like I made it like this:

    import 'package:flutter/material.dart';
    import 'package:flutter_hooks/flutter_hooks.dart';
        
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends HookWidget {
      @override
      Widget build(BuildContext context) {
    
    
    List storedWishes = [
          {
            'title': 'Phone',
            'description': 'a phone would be nice',
            'price': 200.00,
            'icon': Icon(Icons.phone)
          },
          {
            'title': 'monitor',
            'description': 'need it for a 2 screen setup',
            'price': 350.00,
            'icon': Icon(Icons.tv)
          },
          {
            'title': 'headphones',
            'description': 'need some high quality sound',
            'price': 100.00,
            'icon': Icon(Icons.headset)
          },
        ];
        final wishes = useState(storedWishes);
    
        return MaterialApp(
            home: Scaffold(
                appBar: AppBar(
                  title: const Text('iWant'),
                ),
                body: Column(
                  //map the wishes to a list of wish widgets
                  children: wishes.value
                      .map((wish) => TextButton(
                            child: Text(wish['title'] as String),
                            onPressed: () {
                              wishes.value.remove(wish);
                              wishes.notifyListeners();
                            },
                          ))
                      .toList(),
                )));
      }
    }
    

    And it works correctly like this.

    Edit: I could reproduce your issue using your Wish code. I'm actually not familiar with HookWidget, but changing the code to this seems to fix it. I don't know what useState is exactly used for but leaving it out fixes it. you can even let Wish then extend just StatelessWidget instead of HookWidget

    class Wish extends StatelessWidget {
      const Wish(
          {Key? key,
          this.title = 'default title',
          this.description = 'default description',
          this.price = 0.00,
          this.icon = const Icon(Icons.star),
          this.onDelete})
          : super(key: key);
      final String title;
      final String description;
      final double price;
      final dynamic icon;
      final VoidCallback? onDelete;
      @override
      Widget build(BuildContext context) {
        return Card(
            child: Row(children: [
          icon,
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(title),
                Text(description),
              ],
            ),
          ),
          Text((price.toString()) + '\$'),
          Column(
            children: [
              Icon(Icons.edit),
              IconButton(
                onPressed: onDelete,
                icon: Icon(Icons.delete),
              )
            ],
          ),
        ]));
      }
    }