Flutter: Widget hooks

Created on 12 Dec 2018  ·  100Comments  ·  Source: flutter/flutter

React team recently announced hooks: https://medium.com/@dan_abramov/making-sense-of-react-hooks-fdbde8803889. Due to how similar Flutter is with React, it would probably be interesting to see if these fits to Flutter too.

The definition:

Hooks are very similar to the State of StatefulWidget with one main difference: We can have as many hooks as we like on a widget.
Hooks have access to all the life-cycles that a State have (or a modified version).

Hooks can be used on any given widget. Contrarily to State which can be used only for one specific widget type.

Hooks are different from super mixins because they cannot generate conflicts. Hooks are _entirely_ independent and unrelated to the widget.
This means that a Hook can be used to store values and publicly expose it without fear of conflicts. It also means that we can reuse the same Hook multiple times, contrarily to mixins.

The principle:

Hooks are basically stored within the Element in an Array. They are accessible only from within the build method of a widget. And hooks should be accessed unconditionally, example:

DO:

Widget build(BuildContext context) {
  Hook.use(MyHook());
}

DON'T:

Widget build(BuildContext context) {
  if (condition) {
    Hook.use(MyHook());
  }
}

This restriction may seem very limiting, but it is because hooks are stored by their index. Not their type nor name.
This allows reusing the same hook as many time as desired, without any collision.

The use case

The most useful part of Hooks is that they allow extracting life-cycle logic into a reusable component.

One typical issue with Flutter widgets is disposable objects such as AnimationController.
They usually require both an initState and a dispose override. But at the same time cannot be extracted into a mixin for maintainability reasons.

This leads to a common code-snipper: stanim

class Example extends StatefulWidget {
  @override
  ExampleState createState() => ExampleState();
}

class ExampleState extends State<Example>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this, duration: const Duration(seconds: 1));
  }

  @override
  void dispose() {
    super.dispose();
    _controller.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(

    );
  }
}

Hooks solves this issue by extracting the life-cycle logic. This leads to a potentially _much_ smaller code:

class Example extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    AnimationController controller = useAnimationController(duration: const Duration(seconds: 1));
    return Container(

    );
  }
}

A naive implementation of such hook could be the following function:

AnimationController useAnimationController({Duration duration}) {
  // use another hook to obtain a TickerProvider
  final tickerProvider = useTickerProvider();

  // create an AnimationController once
  final animationController = useMemoized<AnimationController>(
    () => AnimationController(vsync: tickerProvider, duration: duration)
  );
  // register `dispose` method to be closed on widget removal
  useEffect(() => animationController.dispose, [animationController]), 

   // synchronize the arguments
  useValueChanged(duration, (_, __) {
    animationController.duration = duration;
  });

  return animationController;
}

useAnimationController is one of those "Hook".

Where a naive implementation of such hook would be the following:

That code should look similar to somebody used to State class. But this has a few interesting points:

  • The hook entirely takes care of the AnimationController, from creation to disposal. But also updates.
  • It can easily be extracted into a reusable package
  • It also takes care of duration updating on hot-reload as opposed to creating an AnimationController in the initState .
  • Hooks can use other hooks to build more complex logic

Drawbacks

Hooks comes with a cost. The access to a value has an overhead similar to an InheritedElement. And they also require to create a new set of short-lived objects such as closures or "Widget" like.

I have yet to run a benchmark to see the real difference though


Another issue is about hot-reload.

Adding hooks at the end of the list if fine. But since hooks work based on their order, adding hooks in the middle of existing hooks will cause a partial state reset. Example:

Going from A, B to A, C, B will reset the state of B (calling both dispose and initHook again).

Conclusion

Hooks simplifies _a lot_ the widgets world by allowing a bigger code reuse. Especially on the very common scenarios such as dispose, memoize and watching a value.

They can be used to entirely replace a StatefulWidget.

But they require a mind shift though, and the partial state reset on refactoring may be bothersome.

It is possible to extract hooks outside of Flutter by creating custom Elements. There's no need to modify the sources as of now.

But due to the specificity of hooks, it would benefit _a lot_ from a custom linter. Which external packages cannot provide at the moment.

Bonus

~A work in progress implementation is available here: https://github.com/rrousselGit/flutter_hooks (latest features are on prod-ready branch).~

~A release is planned soon as alpha. But the current implementation works to some extents.~

Available here https://pub.dartlang.org/packages/flutter_hooks#-readme-tab-

framework new feature

Most helpful comment

Just wanted to say — if anyone on the Flutter team would like to chat 1:1 about Hooks, I'd be happy to explain the historical and technical context behind why we're adopting them in React. This comment might also be interesting: https://github.com/reactjs/rfcs/pull/68#issuecomment-439314884.

All 100 comments

@Hixie @eseidelGoogle

Here's a followup to https://twitter.com/ericmander/status/1070024779015479302 with some details of what I had in mind. Just in case Flutter team wants to invest further on the topic

Hi @rrousselGit I was looking at your flutter_hooks package the other day. I am not sure what options we have for implementing them in Flutter, but I did notice that you are passing hook methods through HookContext, whereas in React, hooks are able to be created separately and used as a sort of "state mixin." The key difference is that flutter_hooks appears to require that all hook methods be built into the package, while React allows hook methods to be totally separate.

It would seem like this would be critical to matching the React spec. Do you have any thoughts on how this might be achieved?

EDIT:

HookContext has been removed and all hooks are now static methods. So the following is now outdated


My package does that for auto completion purpose, but it's not a necessity.

Instead of

context.useSomeHook()

We can have

useSomeHook(context)

This changes strictly nothing besides discoverability.

The key feature is

T HookContext.use<T>(Hook);

Which allows you to build your own hooks from there. As long as we have this method we can do everything React do.

But due to the specificity of hooks, it would benefit a lot from a custom linter. Which external packages cannot provide at the moment.

I’d recommend you upvote (and add your use case to)
https://github.com/dart-lang/linter/issues/697. It would be great if packages could provide their own custom lints.

Another issue is about hot-reload.

This one worries me. It would be sad if we degrade the hot-reload experience.

Available here https://pub.dartlang.org/packages/flutter_hooks

Can you elaborate what the advantages of baking this into the Flutter framework are over just having an external package?

About hot reload, I did integrate it and it is smooth to use.

The only real problem is #26503, which seem to require change in the tooling to fix. And I don't have the bandwidth to do it.


There are multiple small improvements that we can bring to hooks by integrating them into Flutter:

  • Some performance increase, by not depending on StatefulElement
  • Refactoring/analyzing, which is currently not possible or very limited using analyzer_plugin

But I think the biggest reason is: Hooks are part of a larger scale work on React, that is async rendering.

If Flutter ever wants to go on the Async Rendering route (and it should), it will require two things:

  • Multiple framework changes
  • Something similar to hooks

There's also the obvious community aspect. With 270 stars in a month and a spot on https://github.com/trending/dart?since=monthly without me having really advertised them -- hooks are definitely something that raise the community interest.

The goal of hooks is to change the syntax of widgets so that peoples can share lifecycle specific logic to pub.

With hooks being officially supported, this would exponentially increase the community effort.

Curious: Could you explain how you made it work for hot reload?

I extended StatefulElement instead of ComponentElement, so that I could have access to reassemble.
This allows the next build call to change the hook list while preventing normal rebuild from doing so.

Basically, if previousHook.runtimeType != newHook.runtimeType at a given index, this hook and all the following will be disposed of.

The "all the following" part is because a hook can use other hooks; so just removing one is not enough.
From a month of constant usage, it's rarely an issue.

It's actually the opposite, the hot-reload experience seems enhanced. As since everything is within build method, a hot-reload always apply the changes (as opposed to a initState). A typical example is AnimationController:

final animationController = useAnimationController(duration: const Duration(second: 1));

This hook allows a smooth hot-reload of the duration; which is something that usually requires a hot-restart.

I started to translate part of my main app to remove some boilerplate. I do not see Hooks as a feature but a full pattern. Their is many subjects that are just waiting to be implemented and would highly benefits productivity but also maintenance. I started with animation, removing controllers and would love to see Hooks for Firebase or other common cases.

It's actually the opposite, the hot-reload experience seems enhanced. As since everything is within build method, a hot-reload always apply the changes (as opposed to a initState).

👍 I also hit this realization a few weeks after I first saw Sebastian's proposal.

The "all the following" part is because a hook can use other hooks; so just removing one is not enough.

I also thought that in JS maybe a heuristic could be helpful: if hot reloading causes render (Flutter's build) to throw (e.g. due to mismatched types), we reset all Hooks state and retry. If it fails again then we fail.

I guess you don't have this problem due to strong typing? I'm not sure. What happens if you start editing with a string state Hook and then change the code to assume it's a number?

What happens if you start editing with a string state Hook and then change the code to assume it's a number?

You mean going from:

final counter = useState(0)

to:

final name = useState('foo');

?

If so, the typing system correctly detects that the type changed. This is because useState's type is actually useState<int> vs useState<String>.

JS will likely have a harder time here.

I don't really understand what this saves you. One easy-to-understand declaration, one easy-to-understand line in the initState, and one easy-to-understand line in the dispose, get replaced by a less-efficient and completely opaque line in the build method (where performance is critical). This doesn't seem like a good deal. Could you elaborate on the benefits here?

(That said, https://pub.dartlang.org/packages/flutter_hooks seems like it already implements everything here, so I'm guessing we don't need to add anything to the platform?)

Hooks are one solution to an issue React faced for years. And as Flutter takes a lot of inspiration from React, it imported these issues too.

I'm pretty bad at marketing, so I'd heavily suggest watching React Team's talk about these. Their introduction starts here https://youtu.be/dpw9EHDh2bM.

Followed by a side by side comparison of before/after from Dan Abramov (which answered here a few comments above).

The point is, everything they stay in that talk applies to Flutter too (including their blog about mixins being harmful https://reactjs.org/blog/2016/07/13/mixins-considered-harmful.html)


That said, hooks can be summed up in the following catchy sentence:

With hooks, you can 'pub get' an even greater percentage of your application

This is because hooks can be entirely extracted from the widget and published to pub for others to use. That's something currently impossible with StatefulWidget because our logic is tied to State life-cycles.

Another effect of hooks is that it changes how the code is grouped. We currently have the following:

initState() {
  a = A(widget.foo);
  b = B(widget.bar);
}

didUpdateWidget(SomeWidget old) {
  if (old.foo != widget.foo) {
    a.foo = widget.foo;
  }
  if (old.bar != widget.bar) {
    b.bar = widget.bar;
  }
}

dispose() {
  a.dispose();
  b.dispose();
}

Everything is mixed and split across multiple life-cycles. It becomes very difficult to see if we forgot to dispose/update a variable.

With hooks it becomes the following:

final a = useMemoized(() => A(foo));
useValueChanged(foo, () => a.foo = foo});
useEffect(() => a.dispose, [a]);

final b = useMemoized(() => B(bar));
useValueChanged(bar, () => b.bar = bar});
useEffect(() => b.dispose, [b]);

Everything is now regrouped. It becomes much more apparent if we forgot to dispose/update a variable or not, and we can easily extract that logic into a static function that does everything internally.

Hooks are in accordance to DRY. We write once the logic to create/update/dispose a variable. And we reuse it everywhere instead of copy-pasting it.

A visual example (in React):


Overall, while it's incredible that it's possible to implement hooks outside of Flutter repository; I don't think it should stay as it is.

It's like if Flutter provided only the Widget base class, and made StatefulWidget as an external dependency: It doesn't make sense.

Flutter is a framework, we don't want to offer just the basics

Which means we'll also want to:

  • provide hooks for all the framework aspects that would benefits from them
  • interact with the widget inspector (the current UI isn't optimized for such use-case)
  • refactoring/linter
  • provide testing utility

These requires a huge amount of work and may require multiple PR in Flutter.
It is very far from the scope of a small package maintained by one guy on his free time.

Hooks are DRY and are business logic / state mixins that promote clean colocation of code. The alternative is fragmented repetition across a codebase.

While I agree that on paper it is more opaque, the pattern is repeatable and understandable, so after a day of use it becomes transparent. It's like any other programming pattern: opaque when you start, transparent when you use it, but with Hooks the transition is almost instant.

In react, many developers think hooks makes many cases which originally relying on class components not necessary. Therefore, functional component would come to the center of stage in near future.

My naive question is whether supporting functional widget in flutter also makes sense. I understand currently functional widget is not recommended due to not linking to its own Element and lack of own BuildContext. Would be beneficial to introduce a new functional mechanism which can create the same underneath objects as class widget does?

@ivenxu This is something I created too, in another package: https://github.com/rrousselGit/functional_widget

It's a code generator that generates a class from a function, (with keys and everything) and is compatible with hooks to generate a HookWidget

The sum of both is:

@hwidget
Widget foo(BuildContext context, {Duration duration}) {
  final controller = useAninationController(duration: duration);
  useEffect(controller.forward, [controller]);

  final value = useAnination(controller);
  return Text(value.toString());
}

It makes a nice text that goes from 0 to 1 progressively.
In 6 lines of code...
Which would require more than 30 lines with usual widgets.

And I'm not counting the auto generated debugFillProperties and operator== overrides.

@rrousselGit I was aware of your work of functional widget, good stuff and thanks! However, I'm talking about native support from flutter.

By the way, how does attached debug go for the code-gen? Is that possible setting break point in foo() and examine the local variable? How's the callstack looks like?

Sometimes, functional paradigm for component/widget is much more concise than class counterpart. So I'm looking for ideas whether native supported functional widget would make any difference.

With hooks it becomes the following

I really think the "before" picture here is much clearer and easier to understand than the "after" picture. Obviously, though, that's a subjective opinion.

It's like if Flutter provided only the Widget base class, and made StatefulWidget as an external dependency: It doesn't make sense.

Doing that would actually be very much in line with Flutter's layering philosophy. The main reason we have StatefulWidget as a core first-class part of the widgets layer in the framework is that other features in the framework depend on it (e.g. GlobalKey), so we can't. But as much as possible, we do like to extract features so that they aren't in the core.

I think it makes a lot of sense to have this as a package for those people who want to use it. If there's anything we can do in the core framework to make implementing it better, more efficient, etc, then we should definitely do so.

I think this is a great project, and I'm following the package with interest.

That said, I'm not entirely clear on why this would need to be in the framework. This seems like a very useful pattern that some people will love and others will prefer not to use.

@rrousselGit I suspect you'd have a lot of success continuing to develop this as a separate package and opening issues/PRs for the core framework that would help make it succeed more. If there's something that you need exposed in the framework that isn't currently to make this work, let's tackle it. If there's a bug in the framework blocking this from working, let's make it work!

And FWIW, I say this having had a similar experience with flutter_svg - which has led to some contributions to the framework and been able to be useful to plenty of people as a package.

I've just realized:
If hooks are implemented in Flutter, a good candidate is ComponentElement.

This means that instead of having a new Widget type, it would make both StatelessWidget and StatefulWidget compatible with hooks.

This approach could allow both syntax to coexist. This could be useful considering both syntax have their pros and cons


I'm fine with hooks being outside of Flutter for now.

My only concern is that by being unofficial, this will reduce the overall usage of hooks. And therefore reduce the number of hooks available on pub.

Considering the biggest advantage of hooks is the community impact (custom hooks publishable on pub), this hurts their usefulness.

Just wanted to say — if anyone on the Flutter team would like to chat 1:1 about Hooks, I'd be happy to explain the historical and technical context behind why we're adopting them in React. This comment might also be interesting: https://github.com/reactjs/rfcs/pull/68#issuecomment-439314884.

@Hixie or @dnfield did anyone of you ever reach out to @gaearon?

As a Flutter user that also uses React a lot, I can say that hooks were a real game changer for React. I'm writing all my new code using exclusively hooks, and are porting any old classes to hooks as I work on them. The benefits of having all the code related to a specific part of your component in the same place are amazing!

I think it would be awesome if there was an effort to evaluate whether or not that paradigm would fit with Flutter ❤️

I'd missed that comment! I just reached out to them.

I must admit I don't really understand how Hooks applies to Flutter. There are some Hooks packages already if you want to experiment with it (some are mentioned in this bug above). Fundamentally, I don't really understand what problem the concept solves.

For more details on my perspective here see my earlier comments: https://github.com/flutter/flutter/issues/25280#issuecomment-455846788, https://github.com/flutter/flutter/issues/25280#issuecomment-455847134, https://github.com/flutter/flutter/issues/25280#issuecomment-456272076.

Fundamentally, I don't really understand what problem the concept solves.

Hooks are like state mixins, but without the inherent issues of mixins: no variable conflict, and can be used more than once.

Hooks can solve one of the biggest issue that Flutter has with stateful Widgets at the moment: dealing with all these controllers.

Each controller need both an initState, didUpdateWidget and dispose, that are _always_ implemented the same way.

We can't extract it to a base class/mixin because we may need more than one.
So instead we have to copy-paste the logic everywhere.
But that's not very good either. It's easy to forget a step, like overriding dispose.


The real issue with hooks is that they require a lot of work to implement.

The core framework is simple. But due to their unique behavior, they require a deep integration with the linter and refactoring tools.

And for an optimal implementation, some languages features like tupple/destructuring may be needed.

I don't feel this really addresses the comments I had above (https://github.com/flutter/flutter/issues/25280#issuecomment-455846788 and https://github.com/flutter/flutter/issues/25280#issuecomment-456272076 in particular).

Hum, @gaearon will probably explain it better then me, but from my perspective:

  • The readability argument depends on the size of the widget. On larger widgets, hooks tend to be actually _more_ readable because all the related bits are together instead of spread across lifecycles.

  • less bugs. Their declarative API makes it harder to forget to update/cleanup a state.

  • about the "why should they be core?", I like the metaphore used by Dan Abramov.
    Hooks are to widgets what electrons are to atoms.
    It doesn't make sense to exclude them, when they are primitives used to build greater things.
    It's not just about implementing hooks. The whole framework can benefit from them.
    They can be used to improve things like animations, forms, and many more.

@Hixie, have you spent time using Hooks, or are you spreadsheeting them to make a decision? I'm not sure what % of Flutter team's time is spent writing framework stuff versus writing apps for customers. I suspect people who write apps for customers will approach this question from a slightly different angle than a framework dev. Ie, how does this make me more effective and provide more value to my customers, not if it meets the same criteria as an existing solution.

I introduced flutter_hooks recently together with functional_widget in one of our new hot apps.

It vastly reduced boilerplate code and after refactoring all those messy stateful widgets into tiny functions with hooks, the codebase shrunk by roughly 70%.

From a higher level view, a functional widget with a set of hooks is like an imperative simplification of combining multiple observables using combineLatest in RX. But instead of explicitly stating all the observables in the preamble and having a function operating on them, hooks are way more flexible because you weave them into the code where you need the value.

But, in the end each such widget is like a stage in an RX stream.

I certainly don't think we should remove flutter_hooks. I just don't see what we (the Flutter team) can provide that is more valuable.

Hooks are to widgets what electrons are to atoms.

I think if we're following that metaphor that you should view Flutter as quarks, or maybe hadrons. The electrons of Hooks are a layer above.

@Hixie, have you spent time using Hooks, or are you spreadsheeting them to make a decision? I'm not sure what % of Flutter team's time is spent writing framework stuff versus writing apps for customers.

I haven't used Hooks myself. I do write apps with Flutter. I haven't found any need for anything like Hooks when doing so. As noted above, though, I don't think Hooks matches my development style (I prefer to see the boilerplate). I would definitely not want to remove Hooks from anyone who wants to use it.

I just don't see what we (the Flutter team) can provide that is more valuable.

To make hooks truly useful, they need an analyzer plugin and custom refactoring options.
Only with these do hooks truly shine.

Hooks allow a very strong static analysis that is impossible with a typical StatefulWidget.
This makes managing the local state of a widget safer/more scalable. To me, the boilerplate reduction is just a bonus.

But:

  • there's _a lot of work_, on very low-level APIs.
  • the analyzer plugin interface is not stable, lacking, almost unused, and not recommended by the team (as there's one analysis performed for each plugin)
  • flutter itself does not use the plugin API and instead implemented it directly on the server

So, as a community-maintained package, the probability of having complete tooling for hooks is very low.

I think if we're following that metaphor that you should view Flutter as quarks, or maybe hadrons. The electrons of Hooks are a layer above.

If Flutter is quarks, it's also a galaxy.

We indeed have very low-level classes like Layer.
But there's also a huge amount of high-level classes like Switch.

The entire Material and Cupertino libraries could be extracted as packages, then Navigator, and form related objects. But they aren't.
And Hooks are few layers bellow these.

Unrelated but I strongly believe Material and Cupertino should not be in the core Flutter library because it promotes a lack of good interfaces positioned somewhere between super-low-level and Material high level components. If you've ever tried making an app without Material library it's incredibly difficult.

Hooks aren’t really as much about reducing boilerplate. (We don’t mind boilerplate either.) The primary value to me is being able to encapsulate and compose stateful logic.

const [value, setValue] = useState(0)
const debouncedValue = useDebounced(value, 1000)
const interpolatedValue = useSpring(debouncedValue, {
  friction: 10,
  mass: 20
})

Being able to pipe data between them without worrying about whether they contain state or not, extract this logic into custom Hooks, or even apply the same Hook multiple times, is very expressive. And unlike Rx-like approaches, you can actually step through all the code without digging through the combinators.

To make hooks truly useful, they need an analyzer plugin and custom refactoring options.
Only with these do hooks truly shine.

I agree that we need to support this. That should be a bug filed against the Dart GitHub project, though. I would like us to move Flutter-specific lints out of the Dart codebase, certainly.

The entire Material and Cupertino libraries could be extracted as packages, then Navigator, and form related objects. But they aren't.

Yes, that's probably true as well. There's practical reasons why we don't do that (for example, it would complicate the "Hello World" which would make it harder to start using Flutter), but we could consider it nonetheless. Again, though, that's a separate issue which we should file separately if we want to consider it.

The primary value to me is being able to encapsulate and compose stateful logic.

That is indeed very valuable. It's not clear that it has to be in the core framework though.

That is indeed very valuable. It's not clear that it has to be in the core framework though.

This would allow deprecating some core State mixins.

For example AutomaticKeepAliveClientMixin is in a weird position.
We have to call super.build, which is very counter-intuitive. And that super.build returns null which will not work with non-nullable types.
But as a hook, both these issues are solved.

Similarly, we wouldn't need both SingleTickerProviderStateMixin and TickerProviderStateMixin since hooks are reusable as many times as desired.

Alternatively, hooks have an important community aspect. If they are not core, peoples are a lot less likely to create and share custom hooks.

We wouldn't actually _use_ hooks in the core framework, since IMHO they make things less readable. So having them in the core framework wouldn't help remove other code.

Alternatively, hooks have an important community aspect. If they are not core, peoples are a lot less likely to create and share custom hooks.

If hooks are good, then people will use them regardless of whether they're from the Flutter open source project or the, say, Hooks open source project.

We wouldn't actually _use_ hooks in the core framework, since IMHO they make things less readable. So having them in the core framework wouldn't help remove other code.

Alternatively, hooks have an important community aspect. If they are not core, peoples are a lot less likely to create and share custom hooks.

If hooks are good, then people will use them regardless of whether they're from the Flutter open source project or the, say, Hooks open source project.

That sounds not a bad idea. Hooks can run as a separated open source project. Will the core team take priority of the core change requirement from hook project? IMHO It's quite important for the success of hook project.

What is the "core change requirement"?

What is the "core change requirement"?

Devtools.
Mainly about analyzer plug-ins, but also potentially a plug-in system on flutter/devtools.

There's a lot of work involved there, that cannot be done by the community.

We wouldn't actually _use_ hooks in the core framework, since IMHO they make things less readable. So having them in the core framework wouldn't help remove other code.

With all due respect, but this sounds a bit ignorant. You should really give them a try! They are way more concise than dancing around with initState/dispose/setState/build for each single aspect of state.

Flutter is all about composition and using hooks is naturally following the composition pattern where using mixins on the other hand is the opposite of composition.

I imagine we will continue to consider making the analyzer extensible to be a high priority. Unfortunately, there are many other higher priorities, such as improving the experience for basic first-hour tasks and implementing tooling for the non-nullable-by-default change.

That said, I don't see why it couldn't be done by non-Googlers. Flutter and Dart are both open-source projects and many things get implemented by non-Googlers.

That said, I don't see why it couldn't be done by non-Googlers. Flutter and Dart are both open-source projects and many things get implemented by non-Googlers.

We're talking about months of work on multiple projects, for things that the team consider "low priority features", with many big breaking changes. And the impacted projects are very low level with almost no public documentation.

The investment required and the risks of rejection / being stuck in the middle are far too high. Especially when we're not getting any money out of it.

So while I understand your point, it's extremely unlikely

Is there any roadmap about it? Do you have any idea if and when it could be possible for hooks to land in flutter?

If Flutter is successful (which I hope it will) in 1 year every React developer trying to onboard to Flutter will scream when they find out there there is no first-class support for hooks here.

The Flutter team made a good decision copying the class-based React model, but that is a thing of the past now, functional components and hooks are the future, the Flutter team should wake up to this new reality if they want to keep on par.

Precise as cgarciae stated, React community is move on to hook and functional component going forward. And that make flutter look outdated, as programming model and productivity would not on par with other cross platform development solution.

Having try out both react and flutter recently, missing hook in flutter leave a big hole in regarding of productivity, consistence and maintainability apartment under comparison. It would not help organisation to adopt flutter in new project, or convince people switch from React base solution to flutter worth the effort.

I understand completely when someone building a toolset, low level framework implementation, boilerplate code might not seem much an issue. But if an app developer need to write a lot boilerplate "unnecessary" to getting something to work, the effect is undesired.

Depend what angle people looking at specific problem, the tradeoff/balance might look different. Not provide proper tooling or certain feature might make framework internal implementation looks more cleaner, but it just offload the responsibility to framework consumer, make client side implementation more complicated and clumsy than it have to be, which in turn does not help adaption of a giving framework. For an application developer, productivity and consistence does matter, a unify approach/standard is important for teamwork and community. A holistic approach should always consider people live in the other side of the fence.

Hooks should be easy to implement, but functional widgets are harder. That would require union types in Dart since you need to express something like:

‘Widget | Widget Function(BuildContext)’.

functional widgets are harder. That would require union types in Dart

That's far from enough.
There's still the question of:

  • how to pass parameters to functions? Currying?
  • once in the widget tree, two functional widgets should have a different runtimeType
  • how to plug widgets with devtools? (the debugFillProperties method of widgets)

I've thought about it for quite some time. I don't see any easy solution for functional widgets.
The only thing I can think of is a combination of code-generation and analyzer plugins (to have proper go-to-definition and stuff).

Actually, the code generation part made us drop out of your functional_widget package. It just creates to much jumping when reviewing code. So, that wouldn’t fly for me...

It just creates to much jumping when reviewing code

Hence why I mentioned an analyzer plugin.

With a custom analyzer plugin, we should be able to:

  • check that function isn't used directly and the class is preferred
  • have a proper "go to definition"/"peek"/..., such that clicking on the class redirects to the function

This should fix all the issues.
But we're going back to the "hooks needs a proper analyzer plugin system".

Maybe introducing functional widgets is not necessary:

Let's say using hooks is only allowed inside StatelessWidget build method.

From a technical point of view - it doesn't really matter (as far as I can think of now) if it's class or function. The important part is that you don't mix stateful classes and hooks. Under the hood, flutter renderer still could count hooks and their order if they're called inside build method and properly manage it.

In the future, if creating functional widgets would be possible, it's not breaking change. Also, it would be back-compatible, as it's not breaking existing apps.

I don't see any obvious issue with using hooks inside StatelessWidget that would take away the benefits of using hooks like composition.

I'm not sure, however, how it'd compare to cases like useCallback etc of react comparing to the ability of using instance methods anyway

The "we must add this because React developers will be angry" argument is invalid. (see 500+ comment JSX discussion).

Flutter is Flutter, and it has it's own language and design patterns.
I think we shouldn't add stuff to framework just for sake of making it more familiar to React devs, they can use the package if the want to.

I read the discussion and I think @Hixie as a flutter framework developer just saw his side of problem (Implementing and ... stuff) and had less perspective on how flutter app developers (which are his target audience) think, and use it in their development.

I as an android developer had such problem, try to develop a great back-end structure for my applications without any idea how my app users will experience when they see my ugly UI and hard to understand UX.

As other said before hook are great. no matter on who introduce it, either evil FB or Apple.
it just works. it separate state logic and their lifecycles. we can make some usefull other hooks on top of other, publish independent widgets, apis, tools, ... from app states, reuse our pre-produced ones in other projects, ....

And I think, if pre-adding a line in pubspec.yaml to import material or cupertino is hard to create a simple hello-word app!!!, there is nothing to discuss here.
But as StatefullWidget is very important for flutter eco-system, hooks and it's relevant have more importance in future of flutter and its eco-system and flutter developer community.

Just imagine how will flutter app development be simpler, bug-proof, easy to understand, expandable, readable, debug-able, portable, ... (any good thin plus able here pls 😁) with hooks directly supported with core (or something in middle between core and some complex widgets like material, ...) specially official.

To better understand my point, look how awful android development was with java and support libraries and how fancy and sweet is with Kotlin.
It also opens door for other good things like Coroutines, Flow, AndroidX + Kotlin support, new ui system (Compose)
Even it pushed java community to start and implement kotlin futures in their eco.

So pls drop any buffer in hooks, and react and just do it

Lack of official hooks support is the only reason I haven't switched from react native.

Hooks make life so much easier that I don't want to write it the old way ever again

Amazing part of "native hook"s is we can port many internal StatefulWidget or ... to this simple understandable form.
Also as flutter team declare Flutter and Dart made for easy to use, easy to understand, and fast learn curve. All of these can be true and better with Native Hooks.
And (initState/dispose/setState/build) way is not in this path. (we may need them in backend of platform but not for new developers or even designers who want to use code just to describe their ideas (not complex logic))

My read on this thread is that there are a lot of people excited about using hooks in Flutter, and some open questions regarding hooks:

  • Performance impact/measurement - in particular, efficiency of always invoking functions vs. seeing that state is ok to reuse without invoking a new function.
  • Ability (inability?) to play nicely with global keys and/or efficiently move around the tree.
  • Analyzer support/lints specific to hooks.
  • Ability to work as well with hot reload as plain old stateful/stateless widgets.
  • Potential need for additional framework API.

I'm sure all of these questions can be addressed, but addressing them isn't trivial. The problem isn't so much "should hooks be in the framework or should hooks live in a separate package." To some extent, that decision is already made - flutter_hooks has been available on pub.dev for over a year now, and appears to be a popular package. It's that making flutter_hooks a truly polished experience will require some significant work and investment, beyond what's already done.

A lot of that work _has_ already been done for core framework classes, and it took several engineering teams as well as multiple open source contributors years to get it to the point where it is. Sometimes it seems like there's an illusion of "if we just merge it to repo X, all of the unresoved things will resolve!" But the way these things happen is that people who are excited about them do the work of implementing them. @rrousselGit has done a lot of work around this already, and it looks like several other contributors have as well in the hooks repository.

What I'm trying to say in a nutshell is - hooks can work great without being in the Flutter repository, being in the Flutter repository won't accellerate solving its outstanding issues, and that anyone and everyone who wants to see Hooks work in Flutter is completely empowered to make that happen.

Well, in my opinions hooks should be a language feature similar to sync/async generators instead.
It doesn't have to be related to flutter at all.

The problems that hooks solve are:

  • declarative and reactive state management.
    State is imperative
  • state composition to fix DRY.
    All these XXController needs to be created+updated+disposed of and there's no way to factorize that logic.
  • readability, as it doesn't involve endless nesting of functions/widgets to achieve that result

But an alternate syntax could be:

class MyWidget extends HookWidget {
  const MyWidget({Key key, this.title}): super(key: key);

  final String title;

  Hook<Widget> build() hook* {
    final (flag, setFlag) = yield false;
    final (animationController) = yield* useAnimationController(duration: const Duration(seconds: 2));

    // TODO: do something with animationController
    return CheckBox(
      value: flag,
      onChanged: setFlag,
    );  
  }
}

Hook<AnimationController> useAnimationController({required Duration duration}) hook* {
  final (tickerProvider) = yield* useTickerProvider();
  final (animationController) = yield AnimationController(duration: duration, vsync: tickerProvider);
  animationController.duration = duration;

  return animationController;
}

This achieves the same effect as flutter_hook, but is independent of flutter and with multiple optimization factors that flutter_hook cannot do.

And this basically allows _anything_ to use hooks, not just widgets.

That's an interesting idea. It sounds like there are multiple language feature requests in there (something like defer from Go, something like a deterministic destructor from C++, some ability to implicitly compose functions into objects) - but this isn't really the right place to track that.

I think it would be valuable to identify the pain points people are having by not having something like hooks in Flutter, and filing issues specifically about that pain without picking a solution to start with. It is entirely possible, however, that some of these pain points might just be things that the framework is forcing in order to achieve goals about performance, quality, or usability trade-offs (as in, we could make pain point X better at the cost of making pain point Y much worse).

As it stands right now, I'm going to close this issue. There is a good package out there that is addressing this specific solution, and the solution itself is not something that is ready to merge into the framework in its current state (for reasons outlined above), and it's not clear that the solution would ever really benefit from being merged into the framework.

@dnfield Hooks work well 'as a family', only when you have all the main areas of requirements covered.

It'd be useless to use state hooks if then you'd hit the wall when you need some sort of effects after state changes.

Any hook by design requires significant changes inside the core of the renderer or introducing a new kind of core component.

Such an effort is not worth it for only one kind of hook (pain-point), so I'd say it's impossible to solve this problem as set of smaller issues. The single hook is not worth it to switch from stateful components and for sure not worth introducing significant changes in the rendering engine.

If this issue is meant to say "I want Flutter to be more like React but also be like Flutter", I'm not sure how actionable it is - and a GitHub issue is probably not the right way to track such a thing anyway, even if we grant such a thing makes sense to track.

Put another way: if this is a request for a rewrite of the core of Flutter, this is not the right way to approach it. I'm not sure what the right way to approach it would be, but it would probably start with just forking the repository and undertaking a massive effort.

I have a weird feeling when hooks are introduced to people who don't know them and maintain other technologies.

It seems reply often is something like "if you want X to be like React, use react".

My opinion is that hooks are a generic solution to many frontend problems where you need to reuse complex data logic. It's more like an idea that could be used in any technology.

Hooks, however, require some sort of switch in thinking about data flow before their value is fully visible. I think it might be a big issue when "requesting" hooks in other frameworks.

I think the React team did a great job trying to explain hooks, but maybe it creates some resistance because it made hooks seem strongly related to React.

I think React is mentioned next hooks so often simply because this is where they were invented. React is also the best source of information about hooks (so far).

In general - I'd describe the "pain point" as not being able to use a composition pattern for data logic directly in Flutter. Hooks are just an example of allowing that.

I also understand that introducing hooks is a huge task and I must say I'm not willing to undertake.

I personally do not understand the "the community attempted to fix that issue, so we do not have to do anything" argument.

A community fix does not mean that it couldn't be done better by Google.
Take expressions inside collections as an example.
The community could "fix" it by forking Row/Column/ListView/... to support null.
But Google fixed it by modifying the language.

Also, Flutter itself says it: Flutter is inspired from React.
This can be seen by how a big part of how a Widget is used is basically how a React class is used.

While this does not mean that Flutter should match React, I would expect the Flutter team to at least keep a close look at React updates and it's ecosystem.
This should at least provide a better answer to why "we don't want hooks in the framework" other than the community argument.

@rrousselGit @pie6k

I personally find Hooks API, the way it's in React, kind of difficult to grasp. I prefer the lifecycle methods and their descriptive naming.

I know this is a "me problem", but I support @dnfield comment saying we should maybe take the problems and implement solutions differently.

Also I have rarely came to a situation two separate widgets need to share the same logic (that's what I understood as main benefit of Hooks?)

And about Flutter being inspired by React, that's okay, but that doesn't imply it's gonna follow all React patterns and arhitecture forever.
One of main problems I had with React is there is so many ways different to do something, and "recommended practices" change on a daily basis. I understand it's the nature of software engineering, but I still think if there's something bad about existing ways, they should be attempted to improve… instead of piling up different ways to achieve the same thing.

I hope this offers you a slightly different perspective and doesn't offend anyone.

Huge respect for your contributions to the Flutter community.

Sad this issue was closed. It makes it seem like the Flutter team is ignorant of hooks or doesn't care about the current state of design patterns (I hope it isn't). This is not good for any technology, people who invest hundreds of hours want to know that what they are using is top-notch o can be on par with it, and right now the most productive pattern is hooks and Flutter is lagging behind, but its not even been considered or disregarded in favor of a convincingly better alternative by the maintainers.

@cgarciae no one is ignorant, @dnfield clearly said - instead of trying to squeeze in existing solutions, open the issues for corresponding problems you have, Flutter team will evaluate them and possibly come up with a solution that suits Flutter even better.

This is a feature the community has been strongly asking and going to ask. If issue is not the right place, do you guys have a feature request to register requirement from community?

@SpajicM I am entirely fine with "no" as an answer.
What I disagree with is the current justification.

Some notes:

These should give some intensive to discuss about hooks. Not necessarily implementing them, but at least exploring it.

In the end, it boils down to a communication issue.

  • Did the Flutter team contact the React team as offered by Dan Abramov?
  • Did the team experiment with hook in React?
  • Was an alternative considered to the problems that hooks solve?

We, as a community, know nothing about that.

Pushed a step further, I think it is ironical that the community was suggested to split this issue into "what are the problems that hooks solves", when the React team itself offered to explain the Flutter team what are these problems.

@rrousselGit I think the idea behind it is to hear the problems from the Flutter-specific side, directly from users, and take that as a starting point instead of taking React's reasoning, that's not to say their input wouldn't be valuable.

My opinion is it would be good to have a way to clearly separate between widget's logic and design - so I agree that there is a problem to be solved, but way React does it is somewhat confusing to me and I wish Flutter's future solution has a less dramatic paradigm change/learning curve. I don't have an idea in mind but I'm sure community together with a team could come up with something if being open-minded and not fixated to existing Hooks implementation.

I guess next step is to open an issue called:

_"Flutter needs a better way to isolate widget logic"_

I think https://svelte.dev/ has a different and better approach for solving these issues. As a first step , the Flutter team should realize that there is a problem and we need a solution.

I'm new to flutter and what I feel is the API has a lot of boilerplate. Thought Dart has a generic, it feels like I'm programming in Go where it's more common/easier to do copy and paste. I'm hoping there will be a huge refactoring when NNDB landed, especially using the extension method to it's fullest. Gradual API abstraction via something like an extension method might be worth to explore.

IMHO, the Flutter team is too keen on the idea of "everything is a Widget". Widgets are great for visual items and layouts, but not for data gettings/processing. Instead of cumbersome FutureBuilder, StreamBuilder, TweenAnimationBuilder etc. I would prefer a functional API:

Widget build(BuildContext context) {
    final a = useFuture(someFuture);
    final b = useStream(someStream);
    if (a.value == null || b.value == null) {
        return CircularProgressIndicator();
    }

    final value = a.value + b.value;
    final smoothedValue = animate(value, duration: Duration(milliseconds: 100), curve: Curves.easeInOut);

    return Slider(
        value: smoothedValue
    );
}

In fact, Flutter already uses hooks in some places. So instead of more "Fluttery"

MediaQueryGetter {
    builder: (BuildContext context, MediaQueryData data) {
        ...
    }
}

you can use
final data = MediaQuery.of(context);

Unfortunately, this mechanism(subscription while getting) only works in conjunction with InheritedWidget.

I'm not sure how much more progress we can make on this, but I did want to address a few points I'm seeing here:

  1. It's much harder to evaluate a _solution_ than to evaluate a _problem_ in a GitHub issue. When you present a solution, there's a much higher bar to reach to gain acceptance. You have to show that the solution is well formed, worth the effort it entails, and that it solves some set of real problems commensurate with the level of effort it requires (including not only initial prototyping and implementation, but also ongoing manitainence and quality). In other words, an issue where we discuss a specific pain point around managing data and widget state is likely to lead to a number of solutions, some of which could be adopted into the framework, some of which could become third party packages, and some of which would be nice but just cost too much.

  2. Google engineers working on Flutter and Dart are always looking to make it better, and are generally always busy. The same is true of the many non-Google engineers who contribute to Flutter. The closure of this bug does not mean that no Google engineer will ever work on making hooks work better with Flutter. The fact that the hooks package is owned by a community member does not somehow diminish the quality of the package or its value - nor does it diminish the ability to meet some of the shortcomings identified in this bug, for example better support for analysis/linting

  3. There are different reasons to accept or reject a feature. Sometimes it's that the feature is really cool, but doesn't quite fit with the architecture. Sometimes it's that the feature looks good on the surface, but has some major shortcomings that it hasn't addressed. Sometimes the feature is great, it would fit with a sufficent amount of effort, but the amount of effort it costs outweighs the value it delivers to users, or would take away from time needed for other even more valuable features. For Flutter in particular, sometimes it's just that we have a highly layered architecture that enables extension by third party packages, and many times it's better to preserve the laying and allow third parties to do great work than to include some new thing in the framework. We do this ourselves in packages like the new animations package that lives at https://github.com/flutter/packages/tree/master/packages/animations.

Finally, I've been on the other end of this. I am a package maintainer myself, and I've had feature proposals turned down that would have made my package easier to maintain or develop. My only advice is that if you have a great package that you like, keep working on it. Other people will recognize it and help out too, whether it's included in this repo or not.

Android new ComposeUI has hook like states: (preview2)

val state = remember { CardDesignerState() } // react: let state = useState(CardDesignerState())
val thing = stateFor<T?> { null } // react: let thing = useState()

also iOS new SwiftUI have similar things (but it's internally):

// from https://developer.apple.com/tutorials/swiftui/animating-views-and-transitions
Image(systemName: "chevron.right.circle")
                        .imageScale(.large)
                        .rotationEffect(.degrees(showDetail ? 90 : 0))
                        .scaleEffect(showDetail ? 1.5 : 1)
                        .padding()
                        .animation(.easeInOut)

imagine iOS's swiftUI use onCreate, onInit, onUpdate, onExit, ... 🤢

but the best framework (of course it is Flutter) still resist too use hooks idea, why?
Because it look likes React/ReactNative !!! or some amazing quotes from maintainer team:

I prefer to see the boilerplate

obviously against flutter idea to write UI with declarative syntax

I think hooks mixin is a good solution.
Have hooks anywhere we like and don't touch old-style developers codes and framework.
But this idea and any other great ideas need heavy integration with core libraries and It's good to see core maintainers to first-class support these features.
Also I can imagine a future after hooks integration, that many top level framework libraries (like material) heavily support and even use in them.

Flutter could be more beautiful:

// this is just scratch, not a complete and true use-case
build(context) {
    final angle = useAnimation(2*PI, 0, 5 /*seconds*/);
    return Image.from(myAwesomeImage)
        .padding(8)
        .scale(2.5)
        .rotate(angle);
}

@HKhademian totally agree. Lack of first-class support for anything hook-like (or in other terms - anything allowing proper composition of reusable business logic) is actually the only reason I didn't pick Flutter for my last project.

2. The fact that the hooks package is owned by a community member does not somehow diminish the quality of the package or its value - nor does it diminish the ability to meet some of the shortcomings identified in this bug, for example better support for analysis/linting

Do community members ghost packages? Yes. Is Google going to ghost core Flutter? Well, based on your stance here it appears that would have to be a possibility. Asserting that core Flutter is just as viable for consumption as community packages is... wrong at best and a lie at worst.

Furthermore, it has been demonstrated time and time again that unless there is buy in from @Hixie, who has demonstrated an affinity for using personal preference to override community requests, it doesn't matter what the community wants or needs. Without buy in, it doesn't happen. And if that's not the case, then the decision process is too opaque to see otherwise.

What interests me is that the people who decide if features live or die appear to have very little business experience building mobile apps. That point of view will always yield the most insight over which sugar to blend into Flutter.

I think we need a formalized process for deciding what features make it into Flutter that puts more weight on the community to contribute to the decision making process. Obviously not 100%, but right now it feels like it's about 5%, and a super flakey 5% at that. @timsneath

It's much harder to evaluate a solution than to evaluate a problem in a GitHub issue

The React team has offered to explain their reasoning behind Hooks at the very beginning of this issue.
This should fully cover the need to explain why hooks are needed, as nobody is better placed to explain hooks than the React team themselves.

Luke, I respect and appreciate your passion, but please stop with the ad hominem attacks. We are all working to try and build the best platform we can, making all kinds of trade-offs based on resource capacity, user research, stakeholder input, customer needs and community input.

Be kind, please. https://github.com/flutter/flutter/blob/master/CODE_OF_CONDUCT.md

No ad hominem attacks intended, thanks for the feedback. As per the CoC maybe we should get together to discuss what I'm trying to communicate.

The people who disagree should get together, try to understand each other's points of view, and work to find a design that addresses everyone's concerns.

Has there been any update on this, or where we can coordinate a solution? I am running into this with my Flutter projects, especially with Animations and Transitions. Hooks help to encapsulate this initState and dispose state, among others, into a single function and just use that function instead of setting everything up.

It does feel, at least to an outside observer / user of Flutter rather than a plugin maintainer, that there have been legitimate concerns that don't feel like they're being listened to, such as the other issue with Flutter Overlays (#50961), and they seem to be dismissed as not being real problems to users, rather than the maintainers. Again, no disrespect to the maintainers, this is just my opinion as someone casually reading this issue thread, I am not too familiar with any other issues that might be different.

With that being said, how can we proceed more generally in thinking of solutions to problems that users seem to legitimately have? I know Rust has an interesting RFC system that seems to work well for designing new solutions.

@satvikpendem The RFC process here is to file a bug describing the problem, and then once the problem is clearly described, to discuss possible solutions.

It seems that the problems have been explained so far, so then solutions can be discussed now, going by your comment. What can we do next, are there other solutions that work better than hooks or something similar?

If you let me know the bug# I can let you know if the issue describes a problem in sufficient detail that it makes sense to begin discussing possible solutions.

@hixie https://github.com/flutter/flutter/issues/51752

I also think we should have a follow up to Dan's comment: https://github.com/flutter/flutter/issues/25280#issuecomment-456404333
What was the outcome of this discussion?

Hi Remi, thanks so much for bug #51752. I know you've invested a ton of time in this space and contributed highly valuable packages here. Thank you x1000 for this!

To reiterate @dnfield's comment, it seems that we haven't yet aligned around the problem space and its significance. The bug above is a useful step towards that goal, and/or in discussing potential approaches to the problem. Your follow-up question here assumes that a conversation with the React team is the first step from here, but if we don't yet have alignment on the problem space, that seems premature.

Perhaps we can show full examples of apps that have such issues that would be fixed with hooks. We wouldn't necessarily rewrite them with hooks but just show how much copy pasting there is. Would that be something that's amenable to the discussion, @timsneath? Or would you be thinking of something else? I'm trying to figure out how to show the problem space as clearly as possible.

:wave: @timsneath
To be honest I don't quite understand why discussing with the React team would be premature.

Even without the community requesting for hooks, a discussion with the React team would still be very valuable.
React shares a lot of similarities with Flutter, and they have a few extra years of experience dealing with Widgets-like objects.

Discussing with them can only bring benefits to both parties.

As an example:
After creating flutter_hooks, I was contacted by Dan to discuss how I dealt with hot-reload for hooks.
My answer was "There was almost nothing to do because Flutter uses a typed language".
A few months down the road, they improved React's hot-reload by generating something similar to types with Babel

I'm sure that if the Flutter and React team discussed, many of such interactions could happen, and both techs would progress.

Some open-ended questions that could be asked without a specific issue:

  • Why hooks?
  • Why suspense/concurrent mode?
  • Why portals?

@satvikpendem The RFC process here is to file a bug describing the problem, and then once the problem is clearly described, to discuss possible solutions.

Does this mean that any discussions that are not a bug are ignored? I thought the purpose of RFC was for things that are not bugs, but usually to expand more subjective things like developer experience or tooling semantics.

If someone says, "I think we should have hooks because they are becoming idiomatic across multiple frameworks and people report improved experience and productivity," that's a valid discussion to have, but it is not a reproducible bug.

I'm absolutely certain nobody said "discussions that are not a bug will be ignored". Come on, let's work together in good faith, treating each other with respect and courtesy. We're all doing our best here, but with lots of other competing bugs, designs and ideas competing for our attention :)

@lukepighetti, ironically, "we should have hooks because other frameworks have them" is exactly the kind of conversation we're trying to avoid, actually -- because it leads to a design that is by definition optimized for other frameworks' needs. It's really helpful in the process to describe the problem that we're trying to solve in the context of Flutter, since that helps us all agree on whether the problem is the same or not, whether the solution should be the same, etc.

@rrousselGit -- sure, there are some useful general conversations we could have with the React team. I welcome the offer, and perhaps we should do that at some point. They have a lot of smarts on that team, for sure, and their offer is very gracious and kind. Right now, we'd primarily be talking with them because you told us to, rather than because we've got specific questions we are informed enough to discuss :)

And also, just a reminder: "the Flutter team" is just the people who contribute to Flutter. Some contributors work for Google, and some contributors play a stronger role in governing the architecture of the project, but you're also on the Flutter team as is anyone else who contributes to the project :)

As ever -- thank you -- for your patience in discussing this, for your contributions to the community, for continuing to push the project forward with creative ideas in this space!

To clarify, "bug" as we use it is a general term that refers to anything that might lead to a change. Could be a use case, could be an idea, could be a logic error, could be a typo in the documentation, something confusing on the Web site, whatever.

Perhaps we can show full examples of apps that have such issues that would be fixed with hooks. We wouldn't necessarily rewrite them with hooks but just show how much copy pasting there is.

@satvikpendem If the problem is "my application has too much boilerplate" then that's certainly a bug that you should file and we can discuss how to improve matters. Mention the bug # here so we know to continue the conversation in your bug.

Thanks for the comment @Hixie. My issue is broadly covered by the same bug that @rrousselGit mentioned (#51752) so I don't think I have more to add based on what I read in that issue.

@timsneath I'm not sure I understand your comment to @lukepighetti, as in, it feels like we've described the problem in the context of Flutter a few different times, such as this issue, #51752, and others. What else would we need to include? How might we help you be more informed about this problem space such that if we do talk to the React team or others that you would have enough knowledge to ask informed questions, as you say?

I agree that we shouldn't copy things from other frameworks just because React has them, for example, so it might be helpful to see other solutions to this problem of code duplication. Vue's founder @yyx990803 has posted some of his thoughts in Vue's RFC (https://www.github.com/vuejs/rfcs/tree/function-apis/active-rfcs%2F0000-function-api.md) which would be helpful to go through. A particular look at the sections about what problems are solved and why they respectfully disagree about the class based API is useful to read through.

Thanks for clarifying @Hixie , I misunderstood this broader (possibly internal?) definition of 'bug.'

@timsneath I'm not sure I follow. Another group of people, core react devs, already identified and communicated a set of problems, created a solution in an architecturally similar framework, and many front end teams across multiple frameworks are reporting success. I see no indication that this is a "solution before problem" GitHub issue. It appears that @Hixie doesn't agree that there is a problem to be solved, and it appears that this is being based on stylistic or maintenance choices which are not reflecting the developer experience benefits. I say that with the utmost respect while trying to understand where the reluctance to this RFC is coming from.

I don't normally recommend parroting features, but the RFC for hooks is not without prior art with good justification. The prior art is available from the core react team, and any justification we come up with will be repeating what they can and have communicated. @rrousselGit appears to be advocating for you guys to set up a meeting with them to discuss this topic, as they can provide far more insight than we can in a GitHub issue.

As a meta issue, for me personally, it would be helpful if there was a concrete process for getting broad RFCs incorporated into flutter/flutter roadmap that are brought forth by the community. We have a saying that external stakeholders are the ones that want the difficult and necessary work, that's why they have to be included and taken seriously. External in the context of flutter/flutter would be non-team, non-google, non-GDE.

I have documented our RFC process on our wiki.

External in the context of flutter/flutter would be non-team, non-google, non-GDE.

By definition if you are submitting an RFC you are a member of the team.

My issue is broadly covered by the same bug that @rrousselGit mentioned (#51752)

In that case I recommend participating in that dicussion; this particular issue is closed but that one is open. There have been a few descriptions of proposals in that issue, though none seem to do a good job. There has not yet been a particularly clear description of "hooks" there, it has only been mentioned in passing.

I still do not understand why we are expected to explain the problem when both the issues and the proposed solutions are very clearly documented by React and Vue.

The RFC of hooks contains about 1400 comments, introduction videos, documentations, and articles from many smart people.

We can disagree on the solution to these problems. But there shouldn't be a need to explain the problems

The problem was explained in #51752, was it not? Is that not the problem?

(As to why: Because pointing a development team to a 1400-comment RFC for a different product is not an effective way to communicate with that development team. I'm sorry if it feels like I'm being obtuse.)

Sorry to ping the megathread. Just wanted to say for anyone who's been following this one that I've left a few more thoughts from the React perspective in https://github.com/flutter/flutter/issues/51752#issuecomment-665380355 and would be happy to answer more questions if that would be useful.

I also wanted to express hope that this (and related threads) can stay civil and not pressure the maintainers with arguments like "it works for React". React and Flutter have significant differences in the programming model, and React Hooks specifically rely pretty heavily on some nuances of ours. They also have some quirks as a result which many might not accept.

I've changed my opinion on hooks. I think they are a fantastic pattern, but I just finished up a React Native contract and hooks have (in my opinion) fragmented the development system horribly for very little gain. Flutter is currently using a pattern very similar to React class components and there is a ton of tooling built around it. If the framework were to switch over to hooks as the primary state management solution it would fracture all the existing work and mental patterns that Flutter developers use for very little gain.

I think there is an argument that hooks are a superior pattern for productive development, but I think there is more compelling argument (like dartfmt core argument) that consistency over time is better than "better."

I should also note that when dealing with new React developers we often run into roadblocks with hooks creating unexpected results and have to teach them to use class components first. (A good comparison is the phenomenon that new developers have an easier time using for loops compared to collection methods like map/reduce/filter/fold). Hooks are an advanced pattern and we sometimes take that for granted. The frustrating thing here is that the React community is quickly phasing out documentation & support for class component patterns making it more difficult to offer this education or option for new developers.

I had mentioned in the other issue #51752 that perhaps we should work on creating a more Flutter specific version of hooks, as hooks themselves seem to have some drawbacks such as the useEffect(() => ..., [] ) pattern for only-once rendering. @Hixie made an interesting version with the Property and PropertyManager pattern that seems to do something similar to hooks but may not have these drawbacks. We should look more into alternatives to hooks because, at least for Flutter, it feels like there is something that works better than React style hooks but still solves the same problems.

Was this page helpful?
0 / 5 - 0 ratings