Sheraz Ali
Sheraz Ali

Reputation: 1

The improper use of a GetX has been detected when using RxList

I have created an observable list and then storing data in the list from the api as below

class FeedsController extends GetxController {
  final Rx<List<Stories>> _stories = Rx<List<Stories>>([]);

  @override
  void onInit() {
    super.onInit();
    getActiveStories();
  }

  List<Stories> get getStories {
    return _stories.value;
  }

  Future<List<Stories>> getActiveStories() async {
    var url = Uri.parse(storiesURL);
    Map<String, Object> params = {'apikey': apiKey, 'userid': "8"};

    await http.post(url, body: params).then((value) {
      StoriesResponse storiesResponse = storiesResponseFromJson(value.body);
      _stories.value = storiesResponse.stories;
    }).onError((error, stackTrace) {
      debugPrint('Error occurred while fetching stories response: ${error.toString()}');
    });

    return _stories.value;
  }
}

Here is the code for displaying the Stories List

class _ActiveStoriesListState extends State<ActiveStoriesList> {
  List<Story> _currentUserStories = [];

  final FeedsController _feedsController = Get.find();

  @override
  void initState() {
    Future.delayed(Duration.zero, fetchUserStories);
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [ 
        Text('Active Stories',
          style: titleLargeTextStyle.copyWith(fontSize: 22, fontWeight: FontWeight.w600),),
        const SizedBox(height: 10),
        SizedBox(
            height: 100,
            child: Obx(
              () => ListView.builder(
                shrinkWrap: true,
                scrollDirection: Axis.horizontal,
                itemBuilder: (ctx, index) =>
                    ActiveStoriesWidget(story: _currentUserStories[index]),
                itemCount: _currentUserStories.length,
              ),
            )),
      ],
    );
  }

  void fetchUserStories() async {
    List<Stories> stories = _feedsController.getStories;
    stories = stories.where((story) => story.userId == '8').toList();
    _currentUserStories = stories[0].story;
    debugPrint('Active Stories Page: ${_currentUserStories.length}');
  }
}

Solutions I have tried is that make only ListView observable (that didn't work), making ListView parent child Observable that also didn't work. I'm unable to understand where I'm missing. Below is the exception

Exception Screenshot

sample json data

{ "status": 200, "success": [ { "user_id": "4", "first_name": "Abu", "profileImage": "jayspur.com/RallyApp/public/uploads/userImages/…", "story": [ { "story": "jayspur.com/RallyApp/public/uploads/userStories/…", "addeddate": "2023-02-08 09:58:11" } ] } ] }

Upvotes: 0

Views: 371

Answers (1)

Cavin Macwan
Cavin Macwan

Reputation: 1253

You are getting this error because you are not using any observable list inside your ListView.builder.

But before that you should convert your StatefullWidget to a StatelessWidget because in GetX, we don't need any StatefullWidget.

You can try the following code.

Controller

class FeedsController extends GetxController {
  final Rx<List<Stories>> _stories = Rx<List<Stories>>([]);
  List<Stories> currUserstories = [];

  RxBool isLoading = false.obs;
  @override
  void onInit() {
    super.onInit();
    getActiveStories();
  }

  List<Stories> get getStories {
    return _stories.value;
  }

  Future<List<Stories>> getActiveStories() async {
    isLoading.value = true;
    var url = Uri.parse("storiesURL");
    Map<String, Object> params = {'apikey': apiKey, 'userid': "8"};

    await http.post(url, body: params).then((value) {
      StoriesResponse storiesResponse = storiesResponseFromJson(value.body);
      _stories.value = storiesResponse.stories;
      _stories.value =
          _stories.value.where((story) => story.userId == '8').toList();
      currUserstories = _stories.value[0];
    }).onError((error, stackTrace) {
      debugPrint(
          'Error occurred while fetching stories response: ${error.toString()}');
    });

    isLoading.value = false;
    return _stories.value;
  }
}

View file:

class ActiveStoriesList extends StatelessWidget {
  ActiveStoriesList({super.key});

  final FeedsController _feedsController = Get.find();

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          'Active Stories',
          style: titleLargeTextStyle.copyWith(
              fontSize: 22, fontWeight: FontWeight.w600),
        ),
        const SizedBox(height: 10),
        SizedBox(
            height: 100,
            child: Obx(
              () => _feedsController.isLoading.value
                  ? const Center(
                      child: CircularProgressIndicator(),
                    )
                  : ListView.builder(
                      shrinkWrap: true,
                      scrollDirection: Axis.horizontal,
                      itemBuilder: (ctx, index) => ActiveStoriesWidget(
                          story: _feedsController.currUserstories[index]),
                      itemCount: _feedsController.currUserstories.length,
                    ),
            )),
      ],
    );
  }
}

You might have to tweak the code a bit but the core concept it you should do all your work inside the controller and only fetch the data in view file.

Also, you should only use the lifecycle which controller provides. Eg. onInit instead of initState.

If this dosen't work, try to modify your controller file such that you get the value in the list as you want in the controller file itself and you the list which was preseneted in controller in your view file.

Hope it helps.

Upvotes: 1

Related Questions