简体   繁体   中英

Flutter Provider. How to have multiple instances of the same provider type?

So I'm a little confused about how to port an application using setstate to provider.

Let's say I have a person model which extends provider. Now I also want to have multiple person reports. Each report has it's own properties such, title, created date etc plus a list of people.

The trouble I'm having understanding is how would I create a provider per person and per person report? All the examples I've seen of using provider appear to have just one instance of the provider.

Effectively I would want to be able to edit person 'A's values without it effecting person 'B's

EDIT:

Each instance of my object will need a separate state. How can provider manage states of multiple objects all of the same type?.

EDIT 2:

I'll try to clarify further with a different example. Imagine the counter widget that is the default example when creating a flutter app. What if I require a list of dynamically created counters (maybe 10, maybe 100 of them). Would each counter would have it's own provider controlling it's state and if so, how would we create that?

There is no hard rule on how to structure your data. From what i understand from you question:

 class Person{
  String name;
  Report reportData;
  
  Person(this.name, this.reportData);
}

class Report{
  String title;
  Map<String, dynamic> data;
  
  Report(this.title, this.data);
}

class PersonsData with ChangeNotifier
{
  List<Person> l1 = [];
  
  void addData()
  {
    l1.add(Person('John', Report('report1', {'dataTitle' : 'datDescription'})));
  }
}

Now with PersonsData class you can manage your persons. Every person has a report type object which represents the data within.

I'm not sure if I'm understanding your question correctly, but a provider does not contain data, it just makes it available, and if you're talking about the provider package it helps other parts of your app get notified when changes have been done to your data. while a model is what you can make instances of.

Your state objects must be uniquely named types, otherwise, Provider can't distinguish them.

You could create a base Person class and then extend that base class into PersonA , PersonB , etc.

Then they can be controlled separately, but still rely on the base class' functionality.

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class Person with ChangeNotifier {
  String name;

  Person(this.name);

  void changeName(String newName) {
    name = newName;
    notifyListeners();
  }
}

class PersonA extends Person {
  PersonA(String value) : super(value);
}

class PersonB extends Person {
  PersonB(String value) : super(value);
}

class ProviderDuplicatePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => PersonA('Billy Boy')),
        ChangeNotifierProvider(create: (_) => PersonB('Francis')),
      ],
      child: Scaffold(
        appBar: AppBar(
          title: Text('Provider Duplicate Types'),
        ),
        body: DuplicateProviderStateObjects(),
      )
    );
  }
}

class DuplicateProviderStateObjects extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          Column(
            children: [
              Text('Provider One:'),
              Text(Provider.of<PersonA>(context).name),
              ElevatedButton(
                child: Text('Change Person A'),
                onPressed: () => Provider.of<PersonA>(context, listen: false).changeName("Kong"),
              )
            ],
          ),
          Column(
            children: [
              Text('Provider Two:'),
              Text(context.watch<PersonB>().name),
              ElevatedButton(
                child: Text('Change Person B'),
                onPressed: () => Provider.of<PersonB>(context, listen: false).changeName("Godzilla"),
              )
            ],
          ),
        ],
      ),
    );
  }
}

I don't know if there is a way to create Providers dynamically, like in the example of edit2, but if you want to create multiple providers of the same type without repeating code you could pass a type T to the class which extends ChangeNotifier.

class Counter<T> extends ChangeNotifier {
    late int value;

    Counter() { value = 0; }

    int get getValue => value;

    void increase() {
        value += 1;
        notifyListeners();
    }
}

Passing different types should create different classes in memory that will manage the state of these different counters. Illustration:

class A {}
class B {}
class C {}

MultiProvider(
    providers: [
        ChangeNotifierProvider(
            create: (_) => Counter<A>()),
        ChangeNotifierProvider(
            create: (_) => Counter<B>()),
        ChangeNotifierProvider(
            create: (_) => Counter<C>()),
    ],
    child: Home(),
);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM