Getx: How can i use refresh indicator without stateful widget

Created on 14 Nov 2020  路  9Comments  路  Source: jonataslaw/getx

How can i use refresh indicator without stateful widget using getx or provider , i use it in my code but when i update my api data and refresh from my app and it's not showing new updated data inside futurebuilder listview after refresh

give me some solution code for refresh data using stateless widget and provider

Thanks In advance

Most helpful comment

@alvincast, this is the "magic" of GetX. I'm just kidding.
I am a contributor to this framework, but @jonataslaw is responsible for this feature. I confess that it also took me a while to understand how StateMixin works so amazingly.
Regarding your question, I linked to a list because my API returns a list. If my API returned only one city, I would link with CityModel only: StateMixin<CityModel>.
I will try to explain StateMixin in a simple way:
First, this:

class CityController extends GetxController with StateMixin<List<CityModel>> {
  // ...
} 

It is the same as:

class CityController extends GetxController {
  final list = List<CityModel>>().obs;
  //...
}

So you don't need to create an obs. StateMixin creates internally for you.

Second, this:

dio.get(url).then((result) {
  List<CityModel> data = CityModel.listFromJson(result.data);
  change(data, status: RxStatus.success());
}

it is the same as:

final loading = false.obs;
//...
loading.value = true;
dio.get(url).then((result) {
  List<CityModel> data = CityModel.listFromJson(result.data);
  list.assignAll(data);
  loading.value = false;
}

that is, you no longer need a boolean variable to control the loading of your API and change updates List<CityModel> automatically.

Finally, in View, the new widget obx (not to be confused withObx), which is injected into the controller by StateMixin, listens to all changes made by change

All 9 comments

Hi @tonmooy, you can use the new GetX mixin called StateMixin. See an example below:

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

void main() {
  runApp(GetMaterialApp(
    initialRoute: '/home',
    getPages: [
      GetPage(
        name: '/home',
        page: () => HomePage(),
      ),
      GetPage(
        name: '/city',
        page: () => CityPage(),
        binding: CityBinding(),
      ),
    ],
  ));
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('HOME')),
      body: Center(
        child: RaisedButton(
          onPressed: () => Get.toNamed('/city'),
          child: Text('Go to Cities'),
        ),
      ),
    );
  }
}

class CityBinding extends Bindings {
  @override
  void dependencies() {
    Get.put(Dio());
    Get.put(CityController(dio: Get.find()));
  }
}

class CityModel {
  CityModel({
    this.abbreviation,
    this.name,
  });

  String abbreviation;
  String name;

  factory CityModel.fromJson(Map<String, dynamic> json) => CityModel(
        abbreviation: json["sigla"],
        name: json["nome"],
      );

  static List<CityModel> listFromJson(list) =>
      List<CityModel>.from(list.map((x) => CityModel.fromJson(x)));
}

class CityController extends GetxController with StateMixin<List<CityModel>> {
  final Dio dio;

  CityController({this.dio});

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

  findAllCities() {
    const String url = 'https://servicodados.ibge.gov.br/api/v1/localidades/estados';

    dio.get(url).then((result) {
      List<CityModel> data = CityModel.listFromJson(result.data);
      change(data, status: RxStatus.success());
    }, onError: (err) {
      change(null, status: RxStatus.error(err.toString()));
    });
  }
}

class CityPage extends GetView<CityController> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Cities')),
      body: Container(
        child: controller.obx(
          (state) => ListView.builder(
            itemCount: state.length,
            itemBuilder: (context, index) {
              return Text(state[index].name);
            },
          ),
          onLoading: Center(child: CircularProgressIndicator()), // optional
          onError: (error) => Center(                            // optional
            child: Text('Error: $error',
              style: TextStyle(fontSize: 18),
              textAlign: TextAlign.center,
            ),
          ),
        ),
      ),
    );
  }
}

@eduardoflorence i am reading the example about the proper use of stateMixin but why you link the mixin with the list... StateMixin> and when it became in a observable variable? maybe u can give us more explanation about it in documentation with some examples (streams and most recently GetStream)

@alvincast, this is the "magic" of GetX. I'm just kidding.
I am a contributor to this framework, but @jonataslaw is responsible for this feature. I confess that it also took me a while to understand how StateMixin works so amazingly.
Regarding your question, I linked to a list because my API returns a list. If my API returned only one city, I would link with CityModel only: StateMixin<CityModel>.
I will try to explain StateMixin in a simple way:
First, this:

class CityController extends GetxController with StateMixin<List<CityModel>> {
  // ...
} 

It is the same as:

class CityController extends GetxController {
  final list = List<CityModel>>().obs;
  //...
}

So you don't need to create an obs. StateMixin creates internally for you.

Second, this:

dio.get(url).then((result) {
  List<CityModel> data = CityModel.listFromJson(result.data);
  change(data, status: RxStatus.success());
}

it is the same as:

final loading = false.obs;
//...
loading.value = true;
dio.get(url).then((result) {
  List<CityModel> data = CityModel.listFromJson(result.data);
  list.assignAll(data);
  loading.value = false;
}

that is, you no longer need a boolean variable to control the loading of your API and change updates List<CityModel> automatically.

Finally, in View, the new widget obx (not to be confused withObx), which is injected into the controller by StateMixin, listens to all changes made by change

thanks a lot maybe jonatas change the name of the new widget "obx" that can be confused for something like obxStateMix(?, now i can use StateMixin and declare multiples observables inside that controller so how it will work the obx? because as i see in your example controller.obx(
(state) => ListView.builder(
itemCount: state.length,
itemBuilder: (context, index) {
return Text(state[index].name);
},
),
...
the state is take as a list.,.(maybe for this StateMixin> ) but as i said in case u have multiples observables... thanks for ur answer

As far as I could understand, StateMixin should be used for use cases where we need to control only one state that will be obtained asynchronously (API query, for example) and for multiple observables continue using GetxController and GetX/GetBuilder/Obx.

thanks for the explanation

@alvincast and @tonmooy. can we close this issue?

yep

There are many cases where we need to call multiple API call in a single screen, but can't find any way to use multiple StateMixin in a single Controller.

Was this page helpful?
0 / 5 - 0 ratings