brianegan / new_flutter_template

Test ideas for a new flutter template
140 stars 23 forks source link

How should objects be constructed and passed down the tree? #9

Open brianegan opened 3 years ago

brianegan commented 3 years ago

There are many ways to pass values from parent to descendant Widgets. Passing via constructors can be educational for newer Flutter developers, but most projects appear to include some kind of library like Provider, Riverpod or get_it to make such passing easier.

Should the template provide concrete guidance on how to pass dependencies down the Widget tree, or should the template pass dependencies via normal Class constructors?

filiph commented 3 years ago

I'll add that this is a template, so it's understood that the approach isn't going to be the complete, final one. Many frameworks provide templates that don't even work at all (e.g. the detail view is always the same).

In templates, it is completely okay if the developer needs to replace the approach (or lack thereof) with something else right off the bat. Ideally, the process of replacing wouldn't be too painful, though.

fullmers commented 3 years ago

I think it makes more sense to use constructors, to keep it simple and easier to understand for people new to flutter.

You probably also don't want to "pick a winning team" by showcasing a particular library. Perhaps mention in the comments that there are a lot of ways to achieve the same goal and list the top 10 (or whatever) alternatives.

rexthecoder commented 3 years ago

Template based on another figurative template. Constructors should be the better option out there. Once you utilize other dependence like the one highlighted by you, it means a new developer has to learn that before they can use the template. Anything can happen in the future. What if everything change for the dependence, we have assumptions everywhere.

Suggestion 🍟

PiotrWpl commented 3 years ago

I think that we should avoid community solutions here, and should use plain Dart constructors for an example. This will allow to don't add an extra layer of complexity for newcomers.

Norbert515 commented 3 years ago

Constructor works great for very shallow trees or when being near to a leaf. I wouldn't use it to propagate global app state, though. Choosing a specific package, on the other hand, is hard too. That being said, I feel like people starting don't wanna have to choose 'The mechanism by which data is passed along the element tree', so having provider (which is the most well-known solution) be the default sounds good to me. Probably best to add documentation on what exactly provider is solving in that instance and how other packages could solve that too (with links)

brianegan commented 3 years ago

Thanks so much for the feedback so far, everyone :) Very good points all around!

nerder commented 3 years ago

I totally feel like that a template should have an agnostic approach on dependencies. Since this is targeting beginner-intermediate folks I feel like it would be counter productive to introduce an opinionated tool that hide all the complexity. Also true is that this tools are coming in with trade-offs which cost may vary from project to project, it will be a bit annoying to have to remove things from a template that is suppose to show me the simplest yet comprehensive way of starting up a project.

letsar commented 3 years ago

If people take this template as a guidance, I think that we shouldn't pass data through constructors. It makes things harder to maintain and has a lot of drawbacks. I think that we should show how to pass data through the widget tree thanks to InheritedWidgets without the help of an external package.

We could create a vanilla Flutter widget like this one:

class ValueProvider<T> extends StatelessWidget {
  const ValueProvider({
    Key key,
    @required this.value,
    @required this.child,
  })  : assert(child != null),
        super(key: key);

  final T value;
  final Widget child;

  @override
  Widget build(BuildContext context) {
    return _InheritedValue<T>(
      value: value,
      child: child,
    );
  }

  static T of<T>(BuildContext context) {
    return context
        .dependOnInheritedWidgetOfExactType<_InheritedValue<T>>()
        .value;
  }
}

class _InheritedValue<T> extends InheritedWidget {
  _InheritedValue({
    Key key,
    @required this.value,
    @required Widget child,
  }) : super(key: key, child: child);

  final T value;

  @override
  bool updateShouldNotify(_InheritedValue<T> oldWidget) {
    return oldWidget.value != value;
  }
}

This is a simple solution which mimics the common use case of the Provider package and shows how to use InheritedWidgets.

To retrieve data in the build method of a widget we would call this ValueProvider.of<T>(context).

takasea commented 3 years ago

How about writing with a key? dartpad