[English](https://github.com/rrousselGit/provider/blob/master/packages/provider/README.md) | [French](https://github.com/rrousselGit/provider/blob/master/resources/translations/fr_FR/README.md) | [Português](https://github.com/rrousselGit/provider/blob/master/resources/translations/pt_br/README.md) | [简体中文](https://github.com/rrousselGit/provider/blob/master/resources/translations/zh-CN/README.md) | [Español](https://github.com/rrousselGit/provider/blob/master/resources/translations/es_MX/README.md) | [한국어](https://github.com/rrousselGit/provider/blob/master/resources/translations/ko-KR/README.md) | [বাংলা](https://github.com/rrousselGit/provider/blob/master/resources/translations/bn_BD/README.md) | [日本語](https://github.com/rrousselGit/provider/blob/master/resources/translations/ja_JP/README.md) | [Turkish](https://github.com/rrousselGit/provider/blob/master/resources/translations/tr_TR/README.md) | [Italian](https://github.com/rrousselGit/provider/blob/master/resources/translations/it_IT/README.md)
[![codecov](https://codecov.io/gh/rrousselGit/provider/branch/master/graph/badge.svg)](https://codecov.io/gh/rrousselGit/provider) [![Gitter](https://badges.gitter.im/flutter_provider/community.svg)](https://gitter.im/flutter_provider/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[](https://flutter.dev/docs/development/packages-and-plugins/favorites)
Un wrapper alrededor de [InheritedWidget]
para hacerlo más fácil de usar y más utilizable.
Al utilizar `provider` en lugar de escribir manualmente los [InheritedWidget], obtendrás:
- asignación/eliminación simplificada de los recursos
- lazy-loading
- un boilerplate muy reducido en lugar de hacer una nueva clase cada vez.
- compatibilidad con devtools
- una manera común de consumir esto [InheritedWidget]s (ver [Provider.of]/[Consumer]/[Selector])
- incrementa la escalabilidad de tus clases con un mecanismo de escucha (listener) que crece exponencialmente
en complejidad (tales como [ChangeNotifier], el cual es O(N²) al enviar notificaciones)
Para leer más acerca de `provider`, leé su [documentación](https://pub.dev/documentation/provider/latest/provider/provider-library.html).
Ver también:
- [La documentación oficial de Flutter en gestión de estado](https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple), la cual muestra como usar `provider` + [ChangeNotifier]
- [Ejemplos de arquitectura en Flutter](https://github.com/brianegan/flutter_architecture_samples/tree/master/change_notifier_provider), la cual contiene una implementación de una app usando `provider` + [ChangeNotifier]
- [flutter_bloc](https://github.com/felangel/bloc) y [Mobx](https://github.com/mobxjs/mobx.dart), los cuales usan `provider` en su arquitectura.
## Migrar de v3.x.0 a v4.0.0
- Los parámetros `builder` e `initialBuilder` de providers son eliminados.
- `initialBuilder` deberá ser reemplazado por `create`.
- `builder` de "proxy" providers deberá ser reemplazado por `update`
- `builder` de providers clásicos deberá ser reemplazado por `create`.
- las nuevas callbacks `create`/`update` son lazy-loaded, lo cual significa que serán llamadas
la primera vez que su valor sea leído, en lugar de la primera vez que el usuario sea creado.
Si esto no se quiere, puedes deshabilitar el lazy-loading pasando el valor `lazy: false` a
el provider de tu elección.
```dart
FutureProvider(
create: (_) async => doSomeHttpRequest(),
lazy: false,
child: ...
)
```
- `ProviderNotFoundError` es renombrado a `ProviderNotFoundException`.
- La interface `SingleChildCloneableWidget` es eliminada y reemplazada por un nuevo tipo
de widget `SingleChildWidget`.
Ve [este issue](https://github.com/rrousselGit/provider/issues/237) para detalles
acerca de como migrar.
- [Selector] ahora comparará más profundamente el valor anterior y nuevo si estas son colecciones.
Si este no quiere, puedes revertir el comportamiento pasando el parámetro `shouldRebuild` al
[Selector]
```dart
Selector(
shouldRebuild: (previous, next) => previous == next,
builder: ...,
)
```
- `DelegateWidget` y su familia han sido eliminados. En su lugar, para providers personalizados tendrán
subclasses directas [InheritedProvider] o un provider existente.
## Uso
### Exponiendo un valor
#### Exponiendo una nueva instancia del objeto
Los providers permiten no solo exponer un valor, sino también crear/escuchar/eliminar.
Para exponer un objeto recién creado, utilice el constructor por defecto de un provider.
_No uses_ el constructor `.value` si quieres **crear** un objeto, o
podrías tener efectos secundarios no deseados.
Ve [esta respuesta de stackoverflow](https://stackoverflow.com/questions/52249578/how-to-deal-with-unwanted-widget-build)
la cual explica en mayor detalle, por qué usar el constructor `.value` para crear nuevos valores no es óptimo.
- **DO** crea un nuevo objeto dentro de `create`.
```dart
Provider(
create: (_) => MyModel(),
child: ...
)
```
- **DON'T** usar `Provider.value` para crear tu objeto.
```dart
ChangeNotifierProvider.value(
value: MyModel(),
child: ...
)
```
- **DON'T** crear tu objeto de variables que pueden cambiar en el tiempo.
En esta situación, tu objeto nunca será actualizado cuando el
valor cambie.
```dart
int count;
Provider(
create: (_) => MyModel(count),
child: ...
)
```
Si quieres pasar variables que puede cambiar en el tiempo de tu objeto,
considera utilizar `ProxyProvider`:
```dart
int count;
ProxyProvider0(
update: (_, __) => MyModel(count),
child: ...
)
```
**NOTA**:
Cuando se utiliza la llamada de `create`/`update` de un provider, vale la pena señalar que en esta llamada
se llama `lazy` por defecto.
Lo que esto significa es que, hasta que el valor sea solicitado al menos una vez, el `create`/`update`
no se llamarán las callback.
Este comportamiento puede ser desactivado si quieres precalcular algo de lógica, usando el parámetro `lazy`:
```dart
MyProvider(
create: (_) => Something(),
lazy: false,
)
```
#### Reutilizando una instancia de un objeto existente:
Si ya tienes una instancia de un objeto y quieres exponerlo,
deberías usar el constructor `.value` de un proveedor.
Si no lo hace, puede llamar al método `dispose` de tu objeto cuando todavía está en uso.
- **DO** usa `ChangeNotifierProvider.value` para un provider tipo
[ChangeNotifier] existente.
```dart
MyChangeNotifier variable;
ChangeNotifierProvider.value(
value: variable,
child: ...
)
```
- **DON'T** reutiliza un [ChangeNotifier] existente usando su constructor por defecto.
```dart
MyChangeNotifier variable;
ChangeNotifierProvider(
create: (_) => variable,
child: ...
)
```
### Leyendo un valor
La manera mas fácil de leer un valor es usando los métodos de su extensión en [BuildContext]:
- `context.watch()`, el cual hace que el widget escuche los cambios en `T`.
- `context.read()`, este regresa `T` sin escucharlo.
- `context.select(R cb(T value))`, permite al widget escuchar solo una pequeña parte de `T`.
O utiliza el método estático `Provider.of(context)`, el cual se comporta similar a `watch` y cuando le pasa el valor `false`
al parámetro `listen` como `Provider.of(context, liste: false)` se comportará similar a `read`
Vale la pena decir que `context.read()` no hará que tu widget haga un rebuild cuando el valor cambia y no puede ser
llamado dentro de `StatelessWidget.build`/`State.build`. Por otro lado, puede ser llamado libremente fuera de estos métodos.
Estos métodos buscarán en el árbol de los widgets a partir del widget asociado
con el `BuildContext` pasado, y devolverá la variable de tipo más cercano
`T` encontrada (o lanzara una `exception` si no encuentra nada).
Vale la pena señalar que esta operación es O(1). No implica realmente recorrer
en el árbol de los widgets.
Combinado con el primer ejemplo de [exponer un valor](#exposing-a-value), este
el widget leerá el `String` expuesto y mostrará "Hola Mundo".
```dart
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 `watch`!
context.watch(),
);
}
}
```
Otra opción, en lugar de utilizar estos métodos, podemos usar [Consumer] y [Selector].
Estos pueden ayudar a optimizar el desempeño o cuando es difícil de obtener
el `BuildContext` descendiente del provider
Ve las [FAQ](https://github.com/rrousselGit/provider#my-widget-rebuilds-too-often-what-can-i-do) o la documentación de [Consumer](https://pub.dev/documentation/provider/latest/provider/Consumer-class.html)
y [Selector](https://pub.dev/documentation/provider/latest/provider/Selector-class.html) para más información.
### MultiProvider
Cuando inyectamos muchos valores en una aplicación grande, `Provider` puede convertirse
muy anidado rápidamente.
```dart
Provider(
create: (_) => Something(),
child: Provider(
create: (_) => SomethingElse(),
child: Provider(
create: (_) => AnotherThing(),
child: someWidget,
),
),
),
```
A:
```dart
MultiProvider(
providers: [
Provider(create: (_) => Something()),
Provider(create: (_) => SomethingElse()),
Provider(create: (_) => AnotherThing()),
],
child: someWidget,
)
```
El comportamiento de ambos ejemplos es el mismo. `Multiprovider` solo cambia la
apariencia del código.
### ProxyProvider
Desde la versión 3.0.0, existe un nuevo tipo de provider: `ProxyProvider`.
`ProxyProvider` es un provider que combina múltiples valores de otros provider
dentro de un nuevo objeto, y envía el resultado a `Provider`.
Este nuevo objeto será actualizado cuando uno de los providers de los que depende
sea actualizado.
El siguiente ejemplo usa `ProxyProvider` para construir una traducción de acuerdo a un contador
que viene de otro provider.
```dart
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => Counter()),
ProxyProvider(
update: (_, counter, __) => Translations(counter.value),
),
],
child: Foo(),
);
}
class Translations {
const Translations(this._value);
final int _value;
String get title => 'You clicked $_value times';
}
```
Viene con múltiples variaciones, tales como:
- `ProxyProvider` vs `ProxyProvider2` vs `ProxyProvider3`, ...
El dígito después del nombre de la clase es el número de providers que
`ProxyProvider` depende.
- `ProxyProvider` vs `ChangeNotifierProxyProvider` vs `ListenableProxyProvider`, ...
Todos trabajan de manera similar, pero en lugar de enviar el resultado del `Provider`,
el `ChangeNotifierProxyProvider` enviará su valor a un `ChangeNotifierProvider`.
### FAQ
#### Puedo ver el contenido de mis objetos?
Flutter viene con [devtools](https://github.com/flutter/devtools), el cual muestra
cómo el árbol de widgets, está en un momento determinado.
Ya que los providers son widgets, también son visibles en las devtools:
De ahí, si tu presionas un provider, serás capaz de ver los valores que contiene:
(screenshot de las devtools usando la carpeta de `example`)
#### Devtool solo muestran "Instance of MyClass". Que puedo hacer?
Por defecto, devtool necesita `toString`, el cual por defecto es "Instance of MyClass".
Para algo más útil, tienes dos opciones:
- Usa el API [Diagnosticable](https://api.flutter.dev/flutter/foundation/Diagnosticable-mixin.html) de Flutter.
Para la mayoría de los casos, esto se logrará utilizando [DiagnosticableTreeMixin]
en tus objetos, siguiendo la implementación personalizada de [debugFillProperties](https://api.flutter.dev/flutter/foundation/DiagnosticableTreeMixin/debugFillProperties.html).
```dart
class MyClass with DiagnosticableTreeMixin {
MyClass({this.a, this.b});
final int a;
final String b;
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
// list all the properties of your class here.
// See the documentation of debugFillProperties for more information.
properties.add(IntProperty('a', a));
properties.add(StringProperty('b', b));
}
}
```
- override `toString`.
Si no puedes usar [DiagnosticableTreeMixin] (como si tu clase estuviera en un paquete
que no depende de Flutter), entonces puedes simplemente usar el método override `toString`.
Esto es más fácil que usar [DiagnosticableTreeMixin] pero es menos poderoso:
No podrás expandir/contraer los detalles de tu objeto.
```dart
class MyClass with DiagnosticableTreeMixin {
MyClass({this.a, this.b});
final int a;
final String b;
@override
String toString() {
return '$runtimeType(a: $a, b: $b)';
}
}
```
#### Me aparece una exception cuando obtengo Providers dentro de `initState`. Que puedo hacer?
Esta excepción ocurre porque estás tratando de escuchar a un provider de un
life-cycle que nunca jamás será llamado de nuevo.
Significa que debes usar otro ciclo de vida (`build`), o explícitamente
específica que no te importan las actualizaciones.
Entonces, en lugar de:
```dart
initState() {
super.initState();
print(context.watch().value);
}
```
puedes hacer esto:
```dart
Value value;
Widget build(BuildContext context) {
final value = context.watch().value;
if (value != this.value) {
this.value = value;
print(value);
}
}
```
El cual imprime `value` cuando sea que cambie (y solo cuando cambie)
También puedes hacer esto:
```dart
initState() {
super.initState();
print(context.read().value);
}
```
El cual imprimirá `value` una vez _e ignorará las actualizaciones._
#### Como manejar hot-reload en mis objetos?
Puedes hacer que el objeto de tu provider implemente `ReassembleHandler`:
```dart
class Example extends ChangeNotifier implements ReassembleHandler {
@override
void reassemble() {
print('Did hot-reload');
}
}
```
Después úsalo de forma normal con `provider`:
```dart
ChangeNotifierProvider(create: (_) => Example()),
```
#### Utilizo [ChangeNotifier] y tengo una exception cuando se actualiza, que sucede?
Es probable que esto ocurra porque se está modificando el [ChangeNotifier] de uno de
sus descendientes, _mientras que el árbol de los widgets se está construyendo_.
Una situación típica en la que esto ocurre es cuando se inicia una petición http, donde
el futuro está almacenado dentro del notifier:
```dart
initState() {
super.initState();
context.read().fetchSomething();
}
```
Esto no está permitido, porque la actualización es inmediata.
Lo que significa que algunos widgets pueden construir _antes_ de la mutación, mientras que otros
widgets construirán _después_ de la mutación.
Esto podría causar inconsistencias en su UI y por lo tanto no está permitido.
En su lugar, deberías realizar esa mutación en un lugar que afectará a todo
el árbol por igual:
- directamente dentro del `create` de tu provider/constructor de tu modelo:
```dart
class MyNotifier with ChangeNotifier {
MyNotifier() {
_fetchSomething();
}
Future _fetchSomething() async {}
}
```
Esto es útil cuando no existe un "parámetro externo".
- asincronamente al final del frame
```dart
initState() {
super.initState();
Future.microtask(() =>
context.read(context).fetchSomething(someValue);
);
}
```
Esto es ligeramente menos ideal, pero permite pasar parámetros a la mutación.
#### Tengo que usar [ChangeNotifier] para estados complejos?
No.
Puedes utilizar un objeto para representar tu estado. Por ejemplo, otra opción
es usar la arquitectura de `Provider.value()` combinada con `StatefulWidget`.
Aquí está un ejemplo del counter usando tal arquitectura:
```dart
class Example extends StatefulWidget {
const Example({Key key, this.child}) : super(key: key);
final Widget child;
@override
ExampleState createState() => ExampleState();
}
class ExampleState extends State {
int _count;
void increment() {
setState(() {
_count++;
});
}
@override
Widget build(BuildContext context) {
return Provider.value(
value: _count,
child: Provider.value(
value: this,
child: widget.child,
),
);
}
}
```
donde podemos leer el estado haciendo esto:
```dart
return Text(context.watch().toString());
```
y modificar el estado con:
```dart
return FloatingActionButton(
onPressed: () => context.read().increment(),
child: Icon(Icons.plus_one),
);
```
También, puedes crear tu propio provider.
#### Puedo hacer mi propio Provider?
Si. `provider` muestra todos los pequeños componentes para hacer el tuyo.
Esto incluye:
- `SingleChildStatelessWidget`, para hacer que el widget funcione con `MultiProvider`.
Esta interfaz es expuesta como parte de `package:provider/single_child_widget`
- [InheritedProvider], el `InheritedWidget` genérico obtenido cuando hacemos `context.watch`.
Aquí está un ejemplo de un provider personalizado para usar `ValueNotifier` como estado:
https://gist.github.com/rrousselGit/4910f3125e41600df3c2577e26967c91
#### Mi widget hace muchos rebuilds, que puedo hacer?
En lugar de usar `context.watch`, puedes usar `context.select` para escuchar solo a un conjunto
específico de propiedades en el objeto obtenido
Por ejemplo, podrías escribir esto:
```dart
Widget build(BuildContext context) {
final person = context.watch();
return Text(person.name);
}
```
Podría provocar que el widget haga rebuild, si otro aparte de `name` cambia.
En su lugar, puedes usar `context.select` para escuchar solo los cambios en la propiedad `name`:
```dart
Widget build(BuildContext context) {
final name = context.select((Person p) => p.name);
return Text(name);
}
```
De esta manera, el widget no realizará rebuilds innecesarios si algo aparte de `name` cambia.
Similarmente, puedes utilizar [Consumer]/[Selector].
Su propiedad `child` opcional permite solo hacer rebuild en una parte especifica del
árbol de widgets.
```dart
Foo(
child: Consumer(
builder: (_, a, child) {
return Bar(a: a, child: child);
},
child: Baz(),
),
)
```
En este ejemplo, solo `Bar` hará un rebuild cuando `A` actualice. `Foo` y `Baz` no harán builds
innecesarios.
#### Puedo obtener dos providers diferentes usando el mismo tipo?
No. Aunque puedes tener varios providers compartiendo el mismo tipo, un widget
será capaz de obtener sólo uno de ellos: el ancestro más cercano.
En cambio, debe dar explícitamente a ambos proveedores un tipo diferente
En lugar de:
```dart
Provider(
create: (_) => 'England',
child: Provider(
create: (_) => 'London',
child: ...,
),
),
```
Utiliza:
```dart
Provider(
create: (_) => Country('England'),
child: Provider(
create: (_) => City('London'),
child: ...,
),
),
```
#### Puedo consumir una interfaz y proveer una implementación?
Sí, se debe dar una pista del tipo al compilador para indicar que la interfaz se consumirá, con la implementación prevista en create.
```dart
abstract class ProviderInterface with ChangeNotifier {
...
}
class ProviderImplementation with ChangeNotifier implements ProviderInterface {
...
}
class Foo extends StatelessWidget {
@override
build(context) {
final provider = Provider.of(context);
return ...
}
}
ChangeNotifierProvider(
create: (_) => ProviderImplementation(),
child: Foo(),
),
```
### Providers existentes
`provider` nos muestra algunos tipos diferentes de "provider" para diferentes tipos de objetos.
La lista completa de todos los objetos disponibles esta [aquí](https://pub.dev/documentation/provider/latest/provider/provider-library.html)
| Nombre | Descripción |
| ----------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Provider](https://pub.dartlang.org/documentation/provider/latest/provider/Provider-class.html) | La forma más básica de provider. Toma un valor y lo expone, sea cual sea el valor. |
| [ListenableProvider](https://pub.dartlang.org/documentation/provider/latest/provider/ListenableProvider-class.html) | Un proveedor específico para el objeto Listenable. ListenableProvider escuchará el objeto y pedirá a los widgets que dependen de él que lo reconstruyan siempre que se llame al listener. |
| [ChangeNotifierProvider](https://pub.dartlang.org/documentation/provider/latest/provider/ChangeNotifierProvider-class.html) | Se especifica el tipo de ListenableProvider para ChangeNotifier. Este llamará automáticamente `ChangeNotifier.dispose` cuando lo necesite. |
| [ValueListenableProvider](https://pub.dartlang.org/documentation/provider/latest/provider/ValueListenableProvider-class.html) | Escucha al ValueListenable y solo muestra `ValueListenable.value`. |
| [StreamProvider](https://pub.dartlang.org/documentation/provider/latest/provider/StreamProvider-class.html) | Escucha a un Stream y muestra el último valor emitido. |
| [FutureProvider](https://pub.dartlang.org/documentation/provider/latest/provider/FutureProvider-class.html) | Toma un `Future` y actualiza a sus dependientes cuando el futuro es completado. |
[provider.of]: https://pub.dev/documentation/provider/latest/provider/Provider/of.html
[selector]: https://pub.dev/documentation/provider/latest/provider/Selector-class.html
[consumer]: https://pub.dev/documentation/provider/latest/provider/Consumer-class.html
[changenotifier]: https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html
[inheritedwidget]: https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html
[inheritedprovider]: https://pub.dev/documentation/provider/latest/provider/InheritedProvider-class.html
[diagnosticabletreemixin]: https://api.flutter.dev/flutter/foundation/DiagnosticableTreeMixin-mixin.html