jonataslaw / getx

Open screens/snackbars/dialogs/bottomSheets without context, manage states and inject dependencies easily with Get.
MIT License
10.34k stars 1.62k forks source link

Obx with RxList causes error: improper use of a GetX #1468

Closed dreamer2q closed 3 years ago

dreamer2q commented 3 years ago

ATTENTION: DO NOT USE THIS FIELD TO ASK SUPPORT QUESTIONS. USE THE PLATFORM CHANNELS FOR THIS. THIS SPACE IS DEDICATED ONLY FOR BUGS DESCRIPTION. Fill in the template. Issues that do not respect the model will be closed.

Describe the bug

Using Obx with RxList<T> throws error indicating the improper use of a GetX.

Reproduction code NOTE: THIS IS MANDATORY, IF YOUR ISSUE DOES NOT CONTAIN IT, IT WILL BE CLOSED PRELIMINARY)

example:

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Getx RxList Bug Report',
      home: ObxWithRxList(),
    );
  }
}

class ObxWithRxList extends StatelessWidget {
  ObxWithRxList({
    Key? key,
  }) : super(key: key);

  final images = RxList<String>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('ListView With RxList'),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {
          images.add('${images.length}');
        },
      ),
      body: Obx(
        () => SingleChildScrollView(
          child: ListBuilder(
            data: images,
            builder: (_, i) {
              return ListTile(
                title: Text('ListTile $i'),
              );
            },
          ),
        ),
      ),
    );
  }
}

class ListBuilder<T> extends StatelessWidget {
  const ListBuilder({
    Key? key,
    required this.data,
    required this.builder,
  }) : super(key: key);

  final List<T> data;
  final IndexedWidgetBuilder builder;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: List.generate(
        data.length,
        (i) => builder(context, i),
      ).toList(),
    );
  }
}

To Reproduce

Run code above, and see the error displayed on Screen or Console logs.

Expected behavior

No error occurs

Screenshots

Flutter Version: Enter the version of the Flutter you are using

Flutter 2.2.0 stable channel

Getx Version: Enter the version of the Getx you are using

get: 4.1.4

Describe on which device you found the bug:

Any device that flutter supports

Minimal reproduce code

See above.

dreamer2q commented 3 years ago

Obx seems a really magic to me compared with ValueListenableBuilder

jonataslaw commented 3 years ago

Hi, I think you didn't understand what is written on the red screen. GetX is warning you that you are encompassing more widgets than you should, and these widgets are being rebuilt unnecessarily, so it issues a throw for you to use your code in the best possible way. Your code should be:

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

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Getx RxList Bug Report',
      home: ObxWithRxList(),
    );
  }
}

class ObxWithRxList extends StatelessWidget {
  ObxWithRxList({
    Key? key,
  }) : super(key: key);

  final images = RxList<String>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('ListView With RxList'),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {
          images.add('${images.length}');
        },
      ),
      body: SingleChildScrollView(
        child: ListBuilder(
          data: images,
          builder: (_, i) {
            return ListTile(
              title: Text('ListTile $i'),
            );
          },
        ),
      ),
    );
  }
}

class ListBuilder<T> extends StatelessWidget {
  const ListBuilder({
    Key? key,
    required this.data,
    required this.builder,
  }) : super(key: key);

  final List<T> data;
  final IndexedWidgetBuilder builder;

  @override
  Widget build(BuildContext context) {
    return Obx(() => Column(
          children: List.generate(
            data.length,
            (i) => builder(context, i),
          ).toList(),
        ));
  }
}
dreamer2q commented 3 years ago

Oh, GetX seems to smart for me. In my case, the ListBuilder (actually it's DragSortView) is just from pub.dev and I should not modify the code since its a package.

roipeker commented 3 years ago

Ok @dreamer2q , seems like there's no issue here, so i will close this one.

If you have any further questions, or need getx related help, please check the other communication channels.

jonataslaw commented 3 years ago

Oh, GetX seems to smart for me. In my case, the ListBuilder (actually it's DragSortView) is just from pub.dev and I should not modify the code since its a package.

If you can not modify the file, can to use "toList()" function. It's a hack:

Obx(
        () => SingleChildScrollView(
          child: ListBuilder(
            data: images.toList(),
            builder: (_, i) {
              return ListTile(
                title: Text('ListTile $i'),
              );
            },
          ),
        ),
dreamer2q commented 3 years ago

Good to know, before you TELL about it, I used images.value to solve this. But images.toList() is obviously a better way.

Thanks.