Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GetX 5 Migrate Guide (Draft). #2966

Open
jonataslaw opened this issue Nov 16, 2023 · 34 comments
Open

GetX 5 Migrate Guide (Draft). #2966

jonataslaw opened this issue Nov 16, 2023 · 34 comments
Assignees

Comments

@jonataslaw
Copy link
Owner

jonataslaw commented Nov 16, 2023

This is a guide that aims to provide assistance with changes and break changes that occurred in version 5.
You can use this issue for immediate support if you experience any problems.

1. Bindings

We are adding some scope to the bindings. This is important, because when we use Flutter web and navigate directly through the url to the address: /products/home for example, we expect the /products bings to be loaded. In version 4 this may generate unwanted red screens. In version 5, we have a parent and child relationship between GetPages, and between Bindings.

You will probably be able to make your code start without errors (just with a deprecated warning), but if you want to update your code to the new standard, just change the "void" function to a Bind List.

Previous:

class Foo extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut(() => Bar());
  }
}

Now:

class Foo extends Bindings {
  @override
  List<Bind> dependencies() => [
    Bind.lazyPut(() => Bar());
  ]
}

2. Immutable state manager.

Although not very well known, GetX has an immutable data manager. In version 5 it has a completely new look.

Previously we could change the immutable state and its status as follows:

 change(data, status: RxStatus.success());

Now, you don't need pass a status, rather than, you can inherit a state class:

 change(SuccessStatus(data));

Or, if you prefer, you can use the GetState classe to get all available states:

 change(GetStatus.success(data));

Or a better and clean way:

setSuccess(data)

It's important to remember, this is for if you want to manage each state individually, but GetX can take care of all of this for you through the futurize function. It allows all statuses, error, loading, and success to be done automatically, and best of all, you need just one line of code:

onInit(){
   futurize(youAsyncFunction);
}

3. Navigator 2:

GetX 5 only uses Navigator 2 under the hood, so you no longer need to use something like: Get.rootDelegate.toNamed to access navigator 2. Get.toNamed will do that.
It is important to remember that now everything that applies to Flutter's Navigator 2 applies to GetX. WillPopScope no longer works, should not be used, and BackButtonListener is the new method that does the work.

If you need a custom RootDelegate, is a good idea to extend GetDelegate.

4. Get.back

Get.back is used everywhere. This was like that until GetX 4, you could close snackbars, dialogs, pages, everything. However, at the same time as this seemed magical, it had a problem: it was not possible to know what that method was closing, and that was bad. When I created this, I thought it was great, but as I matured as a programmer, I started to prefer security over anything else.
From now on, Get.back() only returns one page in the Stack (as its name suggests).
Get.close() no longer returns a certain number of pages in the stack (that didn't even make sense given the name), it now closes Overlays (snackbars, dialogs, bottomsheets, etc). The function name is now self-descriptive. Do you want to close something? Use Get.close(), do you want to go back to a previous page? Use Get.back().
Furthermore, in GetX we can do something incredible, which is to close only the overlay we want (I'm not sure if this can be done with Flutter Vanilla, as I had to make deep modifications to it). I worked on some apps, and I've used many apps in Flutter, which has a chronic problem, when you open an overlay on top of another, you can only close the last one or none at all. Navigator.pop(context) has no idea what it's doing, just like Get.back() did. Now you can use Get.closeSnackbar() and that's it, only your snackbar will be closed. The same goes for dialogs, bottomsheets, etc.

However, GetX 5 is much better than GetX 4 in everything. I strongly recommend you migrate. There are more than 500 bug fixes, new features, and a framework rebuilt from scratch.
However, it could be challenging on large projects to redo everything from scratch, so I added some functions that maintain the previous behavior (as far as possible). Get.backLegacy() has the same behavior as Get.back() from version 4, so if you want to test version 5 now, and have no Nested routes, no StateMixin classes (where breaking changes occurred), you can simply replace o Get.back() by Get.backLegacy(). Test your app thoroughly after that, and if you have any bugs, I'll be happy to do an emergency update. It worked for me in my production applications, I hope it works for you.

5. BuildContext

Something new: The Observer(builder: (context){}) widget can be used to get the context (since Obx doesn't do it), and GetX 5 also has a SuperInheritedWidget. BuildContext is there for anyone who wants to use it, and the shortcuts (Obx, GetX) will be kept as is. GetBuilder will also be maintained, for compatibility reasons, but perhaps I will add some version of it with BuildContext.

There are many new Widgets, which are part of the refactoring. The responsibilities were better divided, merging GetBuilder with reactive programming under the hood (it doesn't change anything for you, but I eliminated a ton of code)

@jonataslaw jonataslaw self-assigned this Nov 16, 2023
@jonataslaw jonataslaw mentioned this issue Nov 16, 2023
@acquytrenthienduong
Copy link

can you migrate example project to GetX version 5 when new version released?

@laterdayi
Copy link

There is a nice syntax in riverpod. Is it available in getx5 getbuilder?

final boredSuggestion = ref.watch(boredSuggestionProvider);
    // Perform a switch-case on the result to handle loading/error states
    return switch (boredSuggestion) {
      AsyncData(:final value) => Text('data: $value'),
      AsyncError(:final error) => Text('error: $error'),
      _ => const Text('loading'),
    };
  }

@laterdayi
Copy link

laterdayi commented Nov 17, 2023

Now Get.close() no longer returns a certain number of pages in the stack. How should we roll back several pages in get5, A>B>C>D>E, and how to go back to B or C from E?

@jonataslaw
Copy link
Owner Author

Now Get.close() no longer returns a certain number of pages in the stack. How should we roll back several pages in get5, A>B>C>D>E, and how to go back to B or C from E?

Get.back(times:3)

Everything is still there, the difference now you should think of as version 5. If you are closing something, the name will always be "close", if you are returning, the name will always be "back".

@laterdayi
Copy link

Oh, I understand, closing the bottom sheet snackbar... will become close, and returning to the page will become back, which is more semantic.

@jonataslaw
Copy link
Owner Author

jonataslaw commented Nov 17, 2023

There is a nice syntax in riverpod. Is it available in getx5 getbuilder?

final boredSuggestion = ref.watch(boredSuggestionProvider);
    // Perform a switch-case on the result to handle loading/error states
    return switch (boredSuggestion) {
      AsyncData(:final value) => Text('data: $value'),
      AsyncError(:final error) => Text('error: $error'),
      _ => const Text('loading'),
    };
  }

In fact, this looks a lot like the StateMixin syntax, from version 3 that was released about 3 years ago.
I don't know about using the dart 3 switch, but you can always with GetX observe a state and have the loading, success, error, etc. state. In fact, futurize does all this too. Look at StateMixin docs.
But, FYI, here is a sample of the code.

class HomeController extends GetxController with StateMixin<String>{
  void onInit(){
     futurize(yourAsyncMethod)
  }
}

in your view

class Yourview extends GetView<HomeController> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: controller.obx(
        (state)=>Text(state.name),

        // here you can put your custom loading indicator, but
        // by default would be Center(child:CircularProgressIndicator())
        onLoading: CustomLoadingIndicator(),
        onEmpty: Text('No data found'),

        // here also you can set your own error widget, but by
        // default will be an Center(child:Text(error))
        onError: (error)=>Text(error),
      ),
    );
}

@laterdayi
Copy link

Is it convenient to ask the specific release date of getx5? I am very much looking forward to it and using it in the project,After the release of getx5, will you watch the dynamic and fix it urgently? If so, I will refactor my current project to choose getx5

@jonataslaw
Copy link
Owner Author

Is it convenient to ask the specific release date of getx5? I am very much looking forward to it and using it in the project,After the release of getx5, will you watch the dynamic and fix it urgently? If so, I will refactor my current project to choose getx5

I recommend you test the latest release candidate. If there is nothing that completely breaks any user's code, it will be released tomorrow. I mentioned this in the other post.
For my projects, everything is fine, but as each person uses GetX in a different way, I would like to know if GetX 5 will work well without so many modifications in most projects. However, I will spend the entire weekend online, so if any problems occur, I will update it immediately.

@laterdayi
Copy link

Okay, I'll give it a try. I saw it discussed before that getx5 will be subcontracted. Is there any documentation on this, or is there a specific name for each package?

@laterdayi
Copy link

Hopefully, the authors will document the migration considerations in as much detail as possible while providing the ability to split getx into multiple packages

@esentis
Copy link

esentis commented Nov 17, 2023

@jonataslaw Great news of clearing out the Get.back concept. Also since we have the closeAllSnackbars method & closeCurrentSnackbar, can we get closeAllDialogs - closeCurrentDialog & closeAllModalSheets - closeCurrentModalSheeet methods ?

Will make the code much clearer alongiside with Get.isDialogOpen & Get.isBottomSheetOpen checks.

@jonataslaw
Copy link
Owner Author

Are you using nested navigation?
Are you initializing the code using GetBuilder?

@jonataslaw
Copy link
Owner Author

I'm going to try to redo this animation, deactivating the cupertino animation on the previous page.

About your controller being disposed, this is strange, since inserting a middleware does practically the same thing that GetX does by default, however, there could be someone stealing the owner of the route. Is there a bottomsheet? Dialogue? Where is this happening on this route?
Well, if you have time, we can do a discord call to check this out and you can share your screen, because this is very unusual.

@laterdayi
Copy link

@jonataslaw How is the function of getx5 split into multiple feature packs

@herowws
Copy link

herowws commented Nov 22, 2023

@jonataslaw Separate GetxController and GetBuilder from GetX without needing anything else

@herowws
Copy link

herowws commented Nov 22, 2023

@jonataslaw Separate GetxController and GetBuilder from GetX without needing anything else

Create a standalone plugin by separating GetxController and GetBuilder from GetX without requiring any routing, animations, GetMaterialApp, or any other dependencies

@rologr35
Copy link

@jonataslaw Hello, thanks for this update. I recently update my code to v5. Now I have a situation where I need nested navigation but navigation between pages it's not working, the only page generated is the initialRoute declared in the Navigator widget. I see several changes in the code regarding this, specially that now the keys are a list of GetDelegate. The id is being saved correctly and then toNamed is exectude with the resulting delegate but debugging I realized route is null here in get_router_delegate.dart:
final route = _getRouteDecoder(args);
So the push is never executed.
Also I would like to know if there is a way to send arguments to the initial route, I tried overriding the RouteSettings in onGenerateRoute function but I still receiving null arguments in the child. Thanks in advance

@loic-hamdi
Copy link

loic-hamdi commented Nov 25, 2023

1. Bindings

We are adding some scope to the bindings. This is important, because when we use Flutter web and navigate directly through the url to the address: /products/home for example, we expect the /products bings to be loaded. In version 4 this may generate unwanted red screens. In version 5, we have a parent and child relationship between GetPages, and between Bindings.

You will probably be able to make your code start without errors (just with a deprecated warning), but if you want to update your code to the new standard, just change the "void" function to a Bind List.

Previous:

class Foo extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut(() => Bar());
  }
}

Now:

class Foo extends Bindings {
  @override
  List<Bind> dependencies() => [
    Bind.lazyPut(() => Bar());
  ]
}

The example for the new binding is incorrect

It should be:

class Foo extends Binding {
  @override
  List<Bind> dependencies() => [Bind.lazyPut(() => Bar())];
}

@fuxianwei
Copy link

The latest get 5 uses update to update objects to report errors, such as:

class User { String name, last; int age; User({required this.name, required this.last, required this.age}); }

final user = User(name: 'John', last: 'Doe', age: 33).obs;

user.update((value) { value?.name='Roi'; });

Then an error message is displayed

The body might complete normally, causing 'null' to be returned, but the return type, 'User', is a potentially non-nullable type.

How can I correct the code in get 5 and fix this problem
截屏2023-11-29 14 13 08

@Dabbit-Chan
Copy link

As I custom the RouteDelegate, why can't I cutsom the GetNavigator in RouteDelegate? I need a custom onGenerateRoute.

@bkhezry
Copy link

bkhezry commented Dec 13, 2023

Can you provide instructions on how to migrate the binding controller syntax in Getx 5?

Get.to(
      () => const SecondScreen(),
      binding: BindingsBuilder(() {
        Get.lazyPut(() => SecondController());
      }),
    );

@loic-hamdi
Copy link

Can you provide instructions on how to migrate the binding controller syntax in Getx 5?

Get.to(
      () => const SecondScreen(),
      binding: BindingsBuilder(() {
        Get.lazyPut(() => SecondController());
      }),
    );

Please see #2966 (comment)

@woywie87
Copy link

woywie87 commented Jan 3, 2024

@jonataslaw
Hi, thank You for guide.
How can I use Get.to(SecondPage()) ?
In version 5, I getthis message "The argument type 'SecondPage' can't be assigned to the parameter type 'Widget Function()"

@Dabbit-Chan
Copy link

Dabbit-Chan commented Jan 4, 2024

@jonataslaw
Hi, thank You for guide.
How can I use Get.to(SecondPage()) ?
In version 5, I getthis message "The argument type 'SecondPage' can't be assigned to the parameter type 'Widget Function()"

Get.to(() => SecondPage())

@KayesAshfaQ
Copy link

Is it possible to do deep linking only with getx routing? (without any packages like unilink)

@inyong1
Copy link

inyong1 commented Jan 22, 2024

@jonataslaw
getx 5 routing for flutter web working well in run debug, but not working after release compile

In debug mode I can enter an url in the address bar and / or refreshing the web page. But in compile release if I refresh the web page or directly enter an url in browser address bar, it entering to 404 route (not found)

Example, here the "/home" is the default route, it's open by default.
image

And if I do refresh teh page it become notfound
image

[EDIT]
Solved. Need to configure the server to redirect all requests to index.html

@laterdayi
Copy link

image
https://pub.dev/packages/refreshed

@nugrahazzz
Copy link

nugrahazzz commented Apr 7, 2024

I used statemixin and futurize but to trigger onEmpty it doesn't work properly. For Widgets that appear in a successful position, onLoading and onError are running properly but onEmpty is not running properly even with the help of change(GetStatus.empty)... Under what conditions is onEmpty triggered? Let's say I have a List of Model, does onEmpty refer to the length of lists = 0 (.isEmpty)?

Could you please provide a simple example for onEmpty.

or change code for method futurize

void futurize(Future<T> Function() body,
      {T? initialData, String? errorMessage, bool useEmpty = true}) {
    final compute = body;
    _value ??= initialData;
    compute().then((newValue) {
      if (newValue == null && useEmpty) {
        status = GetStatus<T>.loading();
      } else {
        if( newValue!._isEmpty()){
          status = GetStatus<T>.empty();
        } else {
          status = GetStatus<T>.success(newValue);

        }
      }

      refresh();
    }, onError: (err) {
      status = GetStatus.error(errorMessage ?? err.toString());
      refresh();
    });
  }

@DizzyDuan
Copy link

Getx 5 swiping left to close the page conflicts with the photo_view plug-in

@ettaegbe
Copy link

ettaegbe commented May 2, 2024

The latest get 5 uses update to update objects to report errors, such as:

class User { String name, last; int age; User({required this.name, required this.last, required this.age}); }

final user = User(name: 'John', last: 'Doe', age: 33).obs;

user.update((value) { value?.name='Roi'; });

Then an error message is displayed

The body might complete normally, causing 'null' to be returned, but the return type, 'User', is a potentially non-nullable type.

How can I correct the code in get 5 and fix this problem 截屏2023-11-29 14 13 08

How did you fix this?

@bigbott
Copy link

bigbott commented Jul 7, 2024

I have migrated my (small) projects to 5.0.
Here is what I have found so far: https://medium.com/@yurinovicow/flutter-getx-5-0-breaking-changes-28f381931c96

@bigbott
Copy link

bigbott commented Jul 7, 2024

The latest get 5 uses update to update objects to report errors, such as:
class User { String name, last; int age; User({required this.name, required this.last, required this.age}); }
final user = User(name: 'John', last: 'Doe', age: 33).obs;
user.update((value) { value?.name='Roi'; });
Then an error message is displayed
The body might complete normally, causing 'null' to be returned, but the return type, 'User', is a potentially non-nullable type.
How can I correct the code in get 5 and fix this problem 截屏2023-11-29 14 13 08

How did you fix this?

https://medium.com/@yurinovicow/flutter-getx-5-0-breaking-changes-28f381931c96

@adrian273
Copy link

1. Bindings

We are adding some scope to the bindings. This is important, because when we use Flutter web and navigate directly through the url to the address: /products/home for example, we expect the /products bings to be loaded. In version 4 this may generate unwanted red screens. In version 5, we have a parent and child relationship between GetPages, and between Bindings.
You will probably be able to make your code start without errors (just with a deprecated warning), but if you want to update your code to the new standard, just change the "void" function to a Bind List.
Previous:

class Foo extends Bindings {
  @override
  void dependencies() {
    Get.lazyPut(() => Bar());
  }
}

Now:

class Foo extends Bindings {
  @override
  List<Bind> dependencies() => [
    Bind.lazyPut(() => Bar());
  ]
}

The example for the new binding is incorrect

It should be:

class Foo extends Binding {
  @override
  List<Bind> dependencies() => [Bind.lazyPut(() => Bar())];
}

Thanks!

@kanghk21
Copy link

kanghk21 commented Aug 8, 2024

Can you provide instructions on how to migrate the binding controller syntax in Getx 5?

Get.to(
      () => const SecondScreen(),
      binding: BindingsBuilder(() {
        Get.lazyPut(() => SecondController());
      }),
    );

Please see #2966 (comment)

@adrian273
I couldn't understand. Could you share the code for my code? Thanks.

     binding: BindingsBuilder(() {
                  Get.isRegistered<FirstController>()
                      ? Get.delete<FirstController>()
                      : null;
                  Get.put(SecondController());
                })),

@jonataslaw jonataslaw pinned this issue Aug 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests