flutter provider 4.0.4 翻译

 

 

更详细文档: documentation.

 

用法

暴露一个值

暴露一个新的 object 对象

Providers 不仅允许暴露一个值, 还能创建/监听/销毁它.

暴露一个新的 object 对象, 使用provider默认构造函数. 不要使用 .value 构造函数 , 否则会有副作用。

查看 stackoverflow 的回答 ,解析了为什么不要用 .value 构造函数创建一个值.

支持写法:

Provider(
  create: (_) => new MyModel(),
  child: ...
)

 

不建议写法:

ChangeNotifierProvider.value(
  value: new MyModel(),
  child: ...
)

 

不要用一个会变化的变量创建你的对象.这会导致,该变量变化的时候,你的对象没有跟着更新。

int count;

Provider(
  create: (_) => new MyModel(count),
  child: ...
)

如果你确实想用一个会变化的变量创建对象,使用 ProxyProvider:

int count;

ProxyProvider0(
  update: (_, __) => new MyModel(count),
  child: ...
)

 

重用已经存在的对象:

如果你已经有一个对象实例,并且想要暴露她, 你必须使用 .value 构造函数.否则的话,可能导致该对象还在使用的时候,就被清除了。

 

使用 ChangeNotifierProvider.value 提供一个已存在的 ChangeNotifier.

MyChangeNotifier variable;

ChangeNotifierProvider.value(
  value: variable,
  child: ...
)

 

不要通过默认构造函数重用已存在的 ChangeNotifier

MyChangeNotifier variable;

ChangeNotifierProvider(
  create: (_) => variable,
  child: ...
)

 

读取数据

最简单的读取方法是使用静态方法 Provider.of<T>(BuildContext context).

这个方法会从BuildContext开始查找组件树,并返回最近的类型为 T 的变量 (或者抛出没找到).

结合 暴露一个值的例子, 这个组件会读取暴露出来的字符串,并渲染 "Hello World."

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text(
      Don't forget to pass the type of the object you want to obtain to `Provider.of`!
      Provider.of<String>(context)
    );
  }
}

如果不使用Provider.of, 可以使用Consumer 和 Selector.

这在提高性能或者在无法获得BuildContext 的时候很有用。

 

查看 FAQ 或者 Consumer 和 Selector 文档获取更多内容.

MultiProvider 

如果在一个大的程序中注入很多的值, 可以将下面的嵌套

Provider<Something>(
  create: (_) => Something(),
  child: Provider<SomethingElse>(
    create: (_) => SomethingElse(),
    child: Provider<AnotherThing>(
      create: (_) => AnotherThing(),
      child: someWidget,
    ),
  ),
),

转化成

MultiProvider(
  providers: [
    Provider<Something>(create: (_) => Something()),
    Provider<SomethingElse>(create: (_) => SomethingElse()),
    Provider<AnotherThing>(create: (_) => AnotherThing()),
  ],
  child: someWidget,
)

 

ProxyProvider 

从3.0.0起, 有一个新的f provider: ProxyProvider.

ProxyProvider 将其他provider的多个值整合成一个新的对象, 并将结果发送给 Provider.

该新对象会在任何一个它依赖的provides更新的时候更新.

下面的例子用 ProxyProvider 基于counter 创建 translations.

Widget build(BuildContext context) {
  return MultiProvider(
    providers: [
      ChangeNotifierProvider(create: (_) => Counter()),
      ProxyProvider<Counter, Translations>(
        create: (_, counter, __) => Translations(counter.value),
      ),
    ],
    child: Foo(),
  );
}

class Translations {
  const Translations(this._value);

  final int _value;

  String get title => '你点击了 $_value times';
}

它可以有多个变化来源, 如:

  • ProxyProvider vs ProxyProvider2 vs ProxyProvider3, ...

类名后面的数字来源于其他providers .

  • ProxyProvider vs ChangeNotifierProxyProvider vs ListenableProxyProvider, ...

他们的工作方式相似,但 ChangeNotifierProxyProvider 会将它的值发送到ChangeNotifierProvider,而不是发送结果到 Provider, .

 

FAQ 

我在initState中获取Providers的时候报错 .

报错的原因是你在一个不会再次调用的生命周期中监听provider .

你要么使用另一个生命周期 (didChangeDependencies/build),或者显示指定你并不关心更新.

把下面代码

initState() {
  super.initState();
  print(Provider.of<Foo>(context).value);
}

改成

Value value;

didChangeDependencies() {
  super.didChangeDependencies();
  final value = Provider.of<Foo>(context).value;
  if (value != this.value) {
    this.value = value;
    print(value);
  }
}

或者

initState() {
  super.initState();
  print(Provider.of<Foo>(context, listen: false).value);
}

 

我使用了ChangeNotifier,更新的时候报错。 

这很可能是因为你在组件树正在构建的时候修改了 ChangeNotifier 的子元素.

一个经典的场景是,发起一个 http 请求,其 future保存在 notifier 中:

initState() {
  super.initState();
  Provider.of<Foo>(context).fetchSomething();
}

这是不允许的,因为因为修改是立马发生的。

这意味着,可能在发生改变前,一些组件已经进行 build 了, 而其他的组件会在发生改变后 build. 这可能会导致用户界面不一致,因此是不允许的。

你应该将改变放到一个对整个数都平等影响的地方:

  • 直接放到你的model:
class MyNotifier with ChangeNotifier {
  MyNotifier() {
    _fetchSomething();
  }

  Future<void> _fetchSomething() async {}
}

这在没有外部参数的情况下很有用.

  • 在帧的末尾异步调用:
initState() {
  super.initState();
  Future.microtask(() =>
    Provider.of<Foo>(context).fetchSomething(someValue);
  );
}

虽然不完美,但允许传递参数

 

在复杂的state中,我必须用 ChangeNotifier 吗?

你可以用任何的 object 代表你的 state. 例如, 另一种架构是用 Provider.value() 结合 StatefulWidget.

这里是一个使用者样结构 计数器的例子:

class Example extends StatefulWidget {
  const Example({Key key, this.child}) : super(key: key);

  final Widget child;

  @override
  ExampleState createState() => ExampleState();
}

class ExampleState extends State<Example> {
  int _count;

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

  @override
  Widget build(BuildContext context) {
    return Provider.value(
      value: _count,
      child: Provider.value(
        value: this,
        child: widget.child,
      ),
    );
  }
}

读取state:

return Text(Provider.of<int>(context).toString());

修改state:

return FloatingActionButton(
  onPressed: Provider.of<ExampleState>(context).increment,
  child: Icon(Icons.plus_one),
);

或者,您可以创建自己的provider.

 

我可以创建自己的Provider吗?

是的. provider 由一系列暴露了的小组件组成

包括:

  • SingleChildCloneableWidget, to make any widget works with MultiProvider.
  • InheritedProvider, the generic InheritedWidget obtained when doing Provider.of.
  • DelegateWidget/BuilderDelegate/ValueDelegate to help handle the logic of "MyProvider() that creates an object" vs "MyProvider.value() that can update over time".

这是一个自定义 provider,使用 ValueNotifier作为state的例子: https://gist.github.com/rrousselGit/4910f3125e41600df3c2577e26967c91

 

我的组件 rebuilds 太频繁怎么办?

使用Consumer/Selector代替Provider.of .

他们的可选子参数参数允许 rebuild 组件树的具体某一部分:

Foo(
  child: Consumer<A>(
    builder: (_, a, child) {
      return Bar(a: a, child: child);
    },
    child: Baz(),
  ),
)

在这个例子中, 只有 Bar 会在A更新的时候l rebuild . Foo 和 Baz 不会更新.

更进一步,如果对组件树没影响,你可以用 Selector忽略变化 :

Selector<List, int>(
  selector: (_, list) => list.length,
  builder: (_, length, __) {
    return Text('$length');
  }
);

这例子只有在list长度改变的时候才会rebuild. item改变的时候不会更新.

 

我能够使用同一个type获取不同的 providers 吗?

不行,但你可以有多个共享一个type的 providers, 一个组件只能获取他们中的一个:最近的祖先

相反,必须显式地为两个providers指定不同的类型

错误

Provider<String>(
  create: (_) => 'England',
  child: Provider<String>(
    create: (_) => 'London',
    child: ...,
  ),
),

推荐

Provider<Country>(
  create: (_) => Country('England'),
  child: Provider<City>(
    create: (_) => City('London'),
    child: ...,
  ),
),

Existing providers 

provider 为不同的对象提供了不同的 "provider"

全部对象列表 在这

名称

描述

Provider

provider中最基础的Provider. 接收一个值,并把它暴露出去。

ListenableProvider

用于监听对象的 provider . ListenableProvider 会监听对象并在监听被调用的时候rebuild依赖它的组件.

ChangeNotifierProvider

一个特殊的 ListenableProvider 用于改变通知. 它会在需要的时候自动调用 ChangeNotifier.dispose.

ValueListenableProvider

侦听ValueListenable并仅公开ValueListenable.value。

StreamProvider

监听 Stream流,并暴露出最后emitt的值.

FutureProvider

接收一个 Future ,并在future完成时更新依赖。

 

翻译完真想吐槽TMD的,这官方文档写得真差,不知所云。

建议看一下:https://book.flutterchina.club/chapter7/provider.html ,这个作者自己封装了一个简单的provider,各种原理都很清晰。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值