如何在不使用MultiProvider包装MaterialApp的情况下初始化Provider。

huangapple go评论144阅读模式
英文:

How to initialize Provider without wrapping MaterialApp with MultiProvider

问题

有没有一种替代方法来初始化Provider,而不是使用MaterialApp和MultiProvider包装它?

我目前在我的Flutter应用程序中使用Provider来管理状态。我将我的MaterialApp小部件与MultiProvider一起包装,以初始化所有提供程序。但是,我想知道是否有一种更高效的方法来做到这一点。

我尝试过在构建小部件时创建提供程序,但问题在于当导航到另一个屏幕时,它显示提供程序未找到的异常,如果我们在该小部件上创建一个新实例,则整个数据都会更改。

有没有一种不使用MaterialApp和MultiProvider包装Provider的方法来初始化Provider?如果是的话,最佳方法是什么?

谢谢你的帮助!

英文:

Is there an alternative method to initialize Provider rather than wrapping it with MaterialApp with MultiProvider?

I am currently using Provider to manage state in my Flutter app. I am wrapping my MaterialApp widget with MultiProvider to initialize all of my providers. However, I am wondering if there is a more efficient way to do this.

I have tried to create a provider while building a widget, but the issue right here was when navigating to another screen it shows provider not found exception and if we create a new instance on that widget the entire data is change.

Is there a way to initialize Provider without wrapping it with MaterialApp with MultiProvider? If so, what is the best way to do this?

Thanks for your help!

答案1

得分: 1

以下是您要翻译的代码部分:

创建提供程序在当前路线上,但要访问它,您需要分离上下文。

现在在下一个路线上传递当前提供程序

测试片段
void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage(),
    );
  }
}

class Counter extends ChangeNotifier {
  int _count = 0;

  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<Counter>(
      create: (_) => Counter(),
      child: Builder(
        builder: (context) {
          // we cant accass the context of the provider within the same context while context
          return Scaffold(
              body: Center(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Consumer<Counter>(
                  builder: (context, Counter counter, child) {
                    return Text("Count: ${counter.count}");
                  },
                ),
                ElevatedButton(
                  onPressed: () {
                    context.read<Counter>().increment();
                  },
                  child: const Text("Increment"),
                ),
                ElevatedButton(
                  onPressed: () {
                    final value = context.read<Counter>();
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                        builder: (context) => ChangeNotifierProvider<Counter>.value(
                          value: value,
                          builder: (context, child) {
                            return const NextPage();
                          },
                        ),
                      ),
                    );
                  },
                  child: const Text("Next Page"),
                ),
              ],
            ),
          ));
        },
      ),
    );
  }
}

class NextPage extends StatelessWidget {
  const NextPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Next Page"),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Consumer<Counter>(
              builder: (context, Counter counter, child) {
                return Text("Count: ${counter.count}");
              },
            ),
            ElevatedButton(
              onPressed: () {
                context.read<Counter>().increment();
              },
              child: const Text("Increment"),
            ),
          ],
        ),
      ),
    );
  }
}
英文:

You can create the providing on current route, but to access it, you need to separate the context.

return ChangeNotifierProvider&lt;Counter&gt;(
  create: (_) =&gt; Counter(),
    child: Builder(
      builder: (context) {
        // we cant accass the context of the provider within same context while context
        return Scaffold(

Now to pass the current provider on next route

final value = context.read&lt;Counter&gt;();
Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) =&gt; ChangeNotifierProvider&lt;Counter&gt;.value(
      value: value,
      builder: (context, child) {
        return const NextPage();
      },
    ),
  ),
);

Test snippet

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage(),
    );
  }
}

class Counter extends ChangeNotifier {
  int _count = 0;

  int get count =&gt; _count;

  void increment() {
    _count++;
    notifyListeners();
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider&lt;Counter&gt;(
      create: (_) =&gt; Counter(),
      child: Builder(
        builder: (context) {
          // we cant accass the context of the provider within same context while context
          return Scaffold(
              body: Center(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Consumer&lt;Counter&gt;(
                  builder: (context, Counter counter, child) {
                    return Text(&quot;Count: ${counter.count}&quot;);
                  },
                ),
                ElevatedButton(
                  onPressed: () {
                    context.read&lt;Counter&gt;().increment();
                  },
                  child: const Text(&quot;Increment&quot;),
                ),
                ElevatedButton(
                  onPressed: () {
                    final value = context.read&lt;Counter&gt;();
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                        builder: (context) =&gt; ChangeNotifierProvider&lt;Counter&gt;.value(
                          value: value,
                          builder: (context, child) {
                            return const NextPage();
                          },
                        ),
                      ),
                    );
                  },
                  child: const Text(&quot;Next Page&quot;),
                ),
              ],
            ),
          ));
        },
      ),
    );
  }
}

class NextPage extends StatelessWidget {
  const NextPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text(&quot;Next Page&quot;),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Consumer&lt;Counter&gt;(
              builder: (context, Counter counter, child) {
                return Text(&quot;Count: ${counter.count}&quot;);
              },
            ),
            ElevatedButton(
              onPressed: () {
                context.read&lt;Counter&gt;().increment();
              },
              child: const Text(&quot;Increment&quot;),
            ),
          ],
        ),
      ),
    );
  }
}

答案2

得分: 0

I'm afraid there's no alternative, if you want to declare multiple providers you will need to implement MultiProvider at some point, about using MaterialApp, that's up to you, since you can implement MultiProvider without using MaterialApp but I don't recommend you to do that since MaterialApp defines some constraints to how your app is rendered like margins to the top. About the other part of your question when you define a provider inside a widget this will only be available for child widgets this means widgets inside the parent one like:

// This works, a child widget can access its parent provider
ParentWidget(Defines Provider A) --> ChildWidget(Consumes Provider A)
// this doesn't work, a parent widget can't access a provider defined on a nested widget
ParentWidget(Cannot consume Provider A) --> ChildWidget(Defines Provider A) --> DeeperChildWidget(Consumes Provider A)

Now that this is clear I would like to know, why do you want to avoid the use of MultiProvider is there a specific reason for that?

英文:

I'm afraid there's no alternative, if you want to declare multiple providers you will need to implement MultiProvider at some point, about using MaterialApp, that's up to you, since you can implement MultiProvider without using MaterialApp but I don't recommend you to do that since MaterialApp defines some constraints to how your app is rendered like margins to the top. About the other part of your question when you define a provider inside a widget this will only be available for child widgets this means widgets inside the parent one like:

// This works, a child widget can access its parent provider
ParentWidget(Defines Provider A) --&gt; ChildWidget(Consumes Provider A)
// this doesn&#39;t work, a parent widget can&#39;t access a provider defined on a nested widget
ParentWidget(Cannot consume Provider A) --&gt; ChildWidget(Defines Provider A) --&gt; DeeperChildWidget(Consumes Provider A)

Now that this is clear I would like to know, why do you want to avoid the use of MultiProvider is there an specific reason for that?

huangapple
  • 本文由 发表于 2023年5月30日 12:45:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/76361679.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定