¿Cuál es la relación entre los widgets con estado y sin estado en Flutter?

105

Un widget con estado se define como cualquier widget que cambia su estado durante su vida útil. Pero es una práctica muy común que StatelessWidgeta tenga a StatefulWidgetuno como uno de sus hijos. ¿No se StatelessWidgetconvierte en estado si tiene StatefulWidgetcomo uno de sus hijos?

Intenté buscar en la documentación como parte del código de StatelessWidget, pero no pude averiguar cómo StatelessWidgetpuede tener Statefulwidgetcomo hijos y seguir siendo StatelessWidget.

¿Cuál es la relación y la diferencia entre los widgets con estado y sin estado en Flutter?

user462455
fuente
2
Puede componer su diseño a partir de diferentes tipos de widgets, sin embargo, eso no significa que esté heredando las características de la composición para afectar a cada widget. Lo que quiero decir es que puede tener un contenedor sin estado que tenga un elemento secundario de otro contenedor que se declare como StatefulWidget en otro lugar, el estado del contenedor solo afectará a este componente solo. Por lo tanto, se trata de tener una composición de diferentes tipos de widgets, cada uno funciona como lo necesita.
aziza
1
Para complicar las cosas aún más, hay una tercera tipo de widget: InheritedWidget; Que puede hacer una StatelessWidgetactualización.
Rémi Rousselet

Respuestas:

103

Un StatelessWidget nunca se reconstruirá por sí mismo (pero puede hacerlo a partir de eventos externos). Un StatefulWidget puede. Esa es la regla de oro.

PERO cualquier tipo de widget se puede volver a pintar en cualquier momento.

Sin estado solo significa que todas sus propiedades son inmutables y que la única forma de cambiarlas es crear una nueva instancia de ese widget. Por ejemplo, no bloquea el árbol de widgets.

Pero no debería importarle cuál es el tipo de sus hijos. No tiene ningún impacto en ti.

Rémi Rousselet
fuente
11
(Relativamente nuevo en el marco). ¿Cuál es la diferencia entre rebuildyrepaint
user462455
También a partir de los comentarios en el código del marco de flutter, aparentemente los StateFulWidgets también son inmutables.
user462455
3
La construcción de un widget es básicamente una llamada al método "build", seguida de la creación / actualización del cuadro de representación correspondiente; que es seguido por el proceso de pintura. Que imprimirá estos cuadros de renderizado en la pantalla.
Rémi Rousselet
las clases que heredan "StatefulWidget" son inmutables. Pero el estado (State <YourWidget>) en sí mismo es mutable.
Rémi Rousselet
1
@ RémiRousselet Los widgets con y sin estado reconstruyen cada fotograma, según flutter.dev/docs/get-started/flutter-for/…
Matt
82

StatefulWidget vs StatelessWidget.

ingrese la descripción de la imagen aquí

StatelessWidget : un widget que no requiere un estado mutable.

  • Un widget sin estado es un widget que describe parte de la interfaz de usuario mediante la construcción de una constelación de otros widgets que describen la interfaz de usuario de manera más concreta. El proceso de construcción continúa de forma recursiva hasta que la descripción de la interfaz de usuario es completamente concreta (por ejemplo, consiste enteramente en RenderObjectWidgets, que describen RenderObjects concretos).

  • El statelesswidget es útil cuando la parte de la interfaz de usuario que está describiendo no depende de nada más que la información de configuración en el propio objeto y el BuildContext en el que se infla el widget. Para composiciones que pueden cambiar dinámicamente, por ejemplo, debido a que tienen un estado controlado por reloj interno, o dependiendo de algún estado del sistema, considere usar StatefulWidget.

class GreenFrog extends StatelessWidget {
  const GreenFrog({ Key key }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(color: const Color(0xFF2DBD3A));
  }
}

StatefulWidget : un widget que tiene un estado mutable.

  • Los widgets con estado son útiles cuando la parte de la interfaz de usuario que está describiendo puede cambiar de forma dinámica.

Cuando Flutter construye un StatefulWidget, crea un objeto State. Este objeto es donde se guarda todo el estado mutable de ese widget.

El concepto de estado se define por dos cosas:

1) Los datos utilizados por el widget pueden cambiar.

2) Los datos no se pueden leer de forma sincrónica cuando se crea el widget. (Todos los estados deben estar establecidos en el momento en que se llama al método de construcción).

Ciclo de vida de StatefulWidget

El ciclo de vida tiene los siguientes pasos simplificados:

  1. createState () : cuando se le indica a Flutter que cree un StatefulWidget, llama inmediatamente createState().
  • Crea el estado mutable de este widget en una ubicación determinada del árbol.

  • Las subclases deben anular este método para devolver una instancia recién creada de su subclase de estado asociada:

@override
_MyState createState() => _MyState();
  1. montado == verdadero : todos los widgets tienen una this.mountedpropiedad bool . Se vuelve verdadero cuando buildContextse asigna. Es un error llamar setStatecuando se desmonta un widget. Si este objeto de estado se encuentra actualmente en un árbol.
  • Después de crear un objeto State y antes de llamar initState, el marco "monta" el objeto State asociándolo con un
    BuildContext. El objeto State permanece montado hasta que el marco
    llama dispose(), después de lo cual el marco nunca le pedirá al
    objeto State que vuelva a construir.

  • Es un error llamar a setState a menos que mount sea verdadero.

bool get mounted => _element != null;
  1. initState () : este es el primer método que se llama cuando se crea el widget (después del constructor de la clase, por supuesto).

initStatese llama una vez y solo una vez. Debe llamarsuper.initState().

  • Inicialice los datos que se basan en el BuildContext específico para la instancia creada del widget.

  • Inicialice las propiedades que dependen de estos widgets 'padre' en el árbol.

  • Suscríbase a Streams, ChangeNotifierso cualquier otro objeto que pueda cambiar los datos de este widget.

@override
initState() {
  super.initState();
  // Add listeners to this class
  cartItemStream.listen((data) {
    _updateWidget(data);
  });
}
  1. didChangeDependencies () : se llama cuando cambia una dependencia de este objeto de estado.
  • Este método también se llama inmediatamente después initState. Es seguro llamar BuildContext.inheritFromWidgetOfExactTypedesde este método.

  • Las subclases rara vez anulan este método porque el marco siempre llama a build después de cambios de dependencia. Algunas subclases anulan este método porque necesitan hacer un trabajo costoso (por ejemplo, búsquedas de red) cuando cambian sus dependencias, y ese trabajo sería demasiado costoso para cada compilación.

@protected
@mustCallSuper
void didChangeDependencies() { }
  1. build () : describe la parte de la interfaz de usuario representada por el widget.

El marco llama a este método en varias situaciones diferentes:

  • Después de llamar initState.
  • Después de llamar didUpdateWidget.
  • Después de recibir una llamada a setState.
  • Después de que cambie una dependencia de este objeto de estado (por ejemplo, un InheritedWidget al que hace referencia los cambios de compilación anterior).
  • Después de llamar a deactivate y luego reinsertar el objeto State en el árbol en otra ubicación.
  • El marco reemplaza el subárbol debajo de este widget con el widget devuelto por este método, ya sea actualizando el subárbol existente o eliminando el subárbol e inflando un nuevo subárbol, dependiendo de si el widget devuelto por este método puede actualizar la raíz del subárbol existente. , según lo determinado llamando Widget.canUpdate.

  • Normalmente, las implementaciones devuelven una constelación de widgets recién creada que se configura con información del constructor de este widget, el BuildContext dado y el estado interno de este objeto State.

@override
  Widget build(BuildContext context, MyButtonState state) {
    ... () { print("color: $color"); } ...
  }
  1. didUpdateWidget () : se llama cada vez que cambia la configuración del widget.
  • Si el widget principal se reconstruye y solicita que esta ubicación en el árbol se actualice para mostrar un nuevo widget con el mismo tipo de tiempo de ejecución y Widget.key, el marco actualizará la propiedad del widget de este objeto State para hacer referencia al nuevo widget y luego llamar a esto método con el widget anterior como argumento.

  • Anule este método para responder cuando cambie el widget (por ejemplo, para iniciar animaciones implícitas).

  • El marco siempre llama a build después de llamar a didUpdateWidget, lo que significa que cualquier llamada a setState en didUpdateWidget es redundante.

@mustCallSuper
@protected
void didUpdateWidget(covariant T oldWidget) { }
  1. setState () : siempre que cambie el estado interno de un objeto State, realice el cambio en una función a la que pase setState:
  • Llamar a setState notifica al marco que el estado interno de este objeto ha cambiado de una manera que podría afectar la interfaz de usuario en este subárbol, lo que hace que el marco programe una compilación para
    este objeto de estado.

  • Si simplemente cambia el estado directamente sin llamar a setState , es posible que el marco no programe una compilación y que la interfaz de usuario de este subárbol no se actualice para reflejar el nuevo estado.

setState(() { _myState = newValue });
  1. deactivate () : se llama a Deactivate cuando se elimina el estado del árbol, pero podría reinsertarse antes de que finalice el cambio de marco actual. Este método existe básicamente porque los objetos de estado se pueden mover de un punto a otro en un árbol.
  • El marco llama a este método cada vez que elimina este objeto State del árbol. En algunos casos, el marco reinsertará el objeto de estado en otra parte del árbol (por ejemplo, si el subárbol que contiene este objeto de estado se injerta de una ubicación en el árbol a otra). Si eso sucede, el marco se asegurará de que llame a build para darle al objeto State la oportunidad de adaptarse a su nueva ubicación en el árbol. Si el marco vuelve a insertar este subárbol, lo hará antes del final del fotograma de animación en el que se eliminó el subárbol del árbol. Por esta razón, los objetos de estado pueden posponer la liberación de la mayoría de los recursos hasta que el marco llame a su método de disposición.

Rara vez se usa.

@protected
@mustCallSuper
void deactivate() { }
  1. dispose () : se llama cuando este objeto se elimina del árbol de forma permanente.
  • El marco llama a este método cuando este objeto State nunca se volverá a compilar. Después de las llamadas al marco dispose(), el objeto State se considera desmontado y la propiedad montada es falsa. Es un error llamar a setState en este punto. Esta etapa del ciclo de vida es terminal: no hay forma de volver a montar un objeto de estado que se ha eliminado.

  • Las subclases deben anular este método para liberar cualquier recurso retenido por este objeto (por ejemplo, detener cualquier animación activa).

@protected
@mustCallSuper
void dispose() {
  assert(_debugLifecycleState == _StateLifecycle.ready);
  assert(() { _debugLifecycleState = _StateLifecycle.defunct; return true; }());
}

ingrese la descripción de la imagen aquí

Para obtener más información, vaya aquí aquí , aquí

Farhana
fuente
26

De la documentación en flutter.io :

... Lo importante a tener en cuenta aquí es que, en esencia, los widgets sin estado y con estado se comportan de la misma manera. Reconstruyen cada fotograma, la diferencia es que StatefulWidget tiene un objeto de estado que almacena datos de estado en los fotogramas y los restaura.

Si tiene dudas, recuerde siempre esta regla: si un widget cambia (el usuario interactúa con él, por ejemplo), tiene estado. Sin embargo, si un niño está reaccionando al cambio, el padre que lo contiene aún puede ser un widget sin estado si el padre no reacciona al cambio.

Saeed Jassani
fuente
14

Como se menciona en flutter docs

¿Cuál es el punto de?

Algunos widgets tienen estado y otros no tienen estado. Si un widget cambia, el usuario interactúa con él, por ejemplo, tiene estado. El estado de un widget consta de valores que pueden cambiar, como el valor actual de un control deslizante o si una casilla de verificación está marcada. El estado de un widget se almacena en un objeto State, separando el estado del widget de su apariencia. Cuando el estado del widget cambia, el objeto de estado llama a setState () y le dice al marco que vuelva a dibujar el widget.

Un widget sin estado no tiene un estado interno que administrar. Icon, IconButton y Text son ejemplos de widgets sin estado, que subclasifican StatelessWidget.

Un widget con estado es dinámico. El usuario puede interactuar con un widget con estado (escribiendo en un formulario o moviendo un control deslizante, por ejemplo) o cambia con el tiempo (quizás una fuente de datos hace que la interfaz de usuario se actualice). Checkbox, Radio, Slider, InkWell, Form y TextField son ejemplos de widgets con estado, que subclase StatefulWidget.

https://flutter.io/tutorials/interactive/#stateful-stateless

Desaprender
fuente
10

El estado es información que (1) se puede leer sincrónicamente cuando se construye el widget y (2) puede cambiar durante la vida útil del widget. Es responsabilidad del implementador del widget asegurarse de que el estado sea notificado de inmediato cuando dicho estado cambie, utilizando State.setState.

StatefulWidget :

Un widget con estado es un widget que describe parte de la interfaz de usuario mediante la construcción de una constelación de otros widgets que describen la interfaz de usuario de manera más concreta. El proceso de construcción continúa de forma recursiva hasta que la descripción de la interfaz de usuario es completamente concreta (por ejemplo, consiste enteramente en RenderObjectWidgets, que describen RenderObjects concretos).

Los widgets con estado son útiles cuando la parte de la interfaz de usuario que está describiendo puede cambiar dinámicamente, por ejemplo, debido a que tiene un estado controlado por reloj interno o dependiendo de algún estado del sistema. Para las composiciones que dependen solo de la información de configuración en el propio objeto y el BuildContext en el que se infla el widget, considere usar StatelessWidget.

Las propias instancias de StatefulWidget son inmutables y almacenan su estado mutable, ya sea en objetos de estado separados que son creados por el método createState, o en objetos a los que ese estado se suscribe, por ejemplo, objetos Stream o ChangeNotifier, a los que las referencias se almacenan en campos finales en StatefulWidget. sí mismo.

StatelessWidget :

Un widget sin estado es un widget que describe parte de la interfaz de usuario mediante la construcción de una constelación de otros widgets que describen la interfaz de usuario de manera más concreta. El proceso de construcción continúa de forma recursiva hasta que la descripción de la interfaz de usuario es completamente concreta (por ejemplo, consiste enteramente en RenderObjectWidgets, que describen RenderObjects concretos).

Los widgets sin estado son útiles cuando la parte de la interfaz de usuario que está describiendo no depende de nada más que de la información de configuración del objeto en sí y del BuildContext en el que se infla el widget. Para composiciones que pueden cambiar dinámicamente, por ejemplo, debido a que tienen un estado controlado por reloj interno, o dependiendo de algún estado del sistema, considere usar StatefulWidget.

Krunal
fuente
9

Los widgets sin estado son widgets estáticos. Solo necesita pasar algunas propiedades antes de inicializar los widgets sin estado. No dependen de ningún cambio de datos o de comportamiento. Por ejemplo. Text, Icon, RaisedButton son widgets sin estado.

Los widgets con estado son widgets dinámicos, se pueden actualizar durante el tiempo de ejecución según la acción del usuario o el cambio de datos. Si un widget puede cambiar su estado durante el tiempo de ejecución, será un widget con estado.

Editar 15/11/2018

Los widgets sin estado pueden volver a renderizarse si los datos de entrada / externos cambiaron (los datos externos son datos que se pasan a través del constructor). Debido a que los widgets sin estado no tienen un estado, se procesarán una vez y no se actualizarán, sino que solo se actualizarán cuando cambien los datos externos.

Considerando que los widgets con estado con estado tienen un estado interno y pueden volver a renderizarse si los datos de entrada cambian o si cambia el estado del widget.

Los widgets sin estado y con estado tienen un ciclo de vida diferente.

Developine
fuente
Incluso después de pasar un nuevo dato desde el exterior al Statelesswidget, también podemos cambiarlo en tiempo de ejecución, pero no se llama Statefulwidget (a diferencia de la última línea).
CopsOnRoad
¿Puede explicar cómo se puede "actualizar un widget sin estado cuando cambian los datos externos"? (Con "los datos externos son datos que se pasan a través del constructor".) ¿No se llamará al constructor una sola vez? ¿Cómo cambian los datos que pasan a través del constructor?
user1596274
8

Puedo pensar en una analogía muy simple. Tienes un mueble con libros, adornos y un televisor. El mobiliario es apátrida, no hace nada, no se mueve. En el televisor, por el otro lado, puedes encenderlo, apagarlo, cambiar de canal, reproducir una película si tiene algún DVD adjunto, etc. El televisor tiene un estado interno que afecta su comportamiento. En los muebles no tienes estado. La presencia del televisor en los muebles no le agrega un estado. Espero que esto ayude.

Daniel Carrera
fuente
Esto no responde a la pregunta específica del autor de la pregunta.
Isaías
1
¡Esta es una gran analogía!
William Terrill
6

Respuesta a la pregunta de Stack Overflow: estado frente a apatridia .

En Flutter, la diferencia es que los widgets sin estado se pueden definir solo con todos los argumentos del constructor. Si crea dos widgets sin estado con los mismos argumentos, serán los mismos.

Sin embargo, un widget con estado no es necesariamente lo mismo que otro creado con los mismos argumentos de constructor. Podría estar en un estado diferente.
En realidad, un widget con estado es inmutable (sin estado) en sí mismo, pero Flutter administra un objeto de estado separado y lo asocia con el widget, como se explica en el documento StatefulWidget . Esto significa que cuando Flutter reconstruye un widget con estado, comprobará si debería reutilizar un objeto de estado anterior y, si lo desea, adjuntará ese objeto de estado al widget.

El widget padre no tiene estado porque no le importa el estado de su hijo. El niño con estado en sí mismo (o técnicamente Flutter) se hará cargo de su propio estado.
En general, estoy de acuerdo en que esto hace que el widget principal tenga estado, porque dos padres pueden contener dos hijos con estados diferentes y, por lo tanto, ser técnicamente diferentes ellos mismos. Pero desde el punto de vista de Flutter, construye el widget padre sin preocuparse por el estado y solo cuando construya el hijo considerará su estado.

J0hj0h
fuente
5

¿Qué son los widgets con estado y sin estado?

TL; DR: un widget que le permite actualizar la pantalla es un widget con estado. Un widget que no lo tiene es Stateless.

Más detalladamente, un widget dinámico con contenido que puede cambiar debería ser un widget con estado. Un widget sin estado solo puede cambiar el contenido cuando se cambian los parámetros y, por lo tanto, debe realizarse por encima del punto de su ubicación en la jerarquía del widget. Una pantalla o widget que contenga contenido estático debe ser un widget sin estado, pero para cambiar el contenido, debe tener estado.

Encontré este contenido relativo en una historia de medio interesante. ¡De nada!

Winnie Nyambura
fuente
4

Sin estado: el estado del widget se crea SOLO UNA VEZ, luego puede actualizar los valores pero no el estado explícito. Esto también queda claro a partir de su estructura. Es por eso que solo tiene una clase que se extiende con StatelessWidget. Entonces, si digo, nunca podrán volver a ejecutar el build()método.

Con estado : los widgets pueden actualizar su ESTADO (localmente) y sus valores varias veces cuando se activa un evento . Esa es la razón, la implementación también es diferente. En esto, tenemos 2 clases, una es StatefulWidgety la otra es su controlador de implementación de estado, es decir State<YourWidget>. Entonces, si digo, pueden volver a ejecutar el build()método una y otra vez en función de los eventos activados.

El siguiente diagrama le ayudará.

ingrese la descripción de la imagen aquí

Rohit Mandiwal
fuente
1

Al escribir una aplicación, normalmente creará nuevos widgets que son subclases de StatelessWidget o StatefulWidget

Aquí hay algunas diferencias entre StatelessWidgety StatefulWidgetwidgets:

Widget sin estado:

  1. Un widget que tiene un estado inmutable.
  2. Los widgets sin estado son widgets estáticos.
  3. No dependen de ningún cambio de datos o de comportamiento.
  4. Los widgets sin estado no tienen un estado, se procesarán una vez y no se actualizarán, sino que solo se actualizarán cuando cambien los datos externos.
  5. Por ejemplo: Text, Icon, RaisedButtonson sin estado widgets.

Widget sin estado:

  1. Un widget que tiene un estado mutable.
  2. Los widgets con estado son widgets dinámicos.
  3. Se pueden actualizar durante el tiempo de ejecución según la acción del usuario o el cambio de datos.
  4. Los widgets con estado tienen un estado interno y pueden volver a renderizarse si los datos de entrada cambian o si cambia el estado del widget.
  5. Por ejemplo: Checkbox, Radio Button, Sliderson Stateful Reproductores
Paresh Mangukiya
fuente
1

descargo de responsabilidad: - comencé a trabajar en flutter desde la semana pasada :)

El widget sin estado y completo tiene su propio ciclo de vida para crear y actualizar la interfaz de usuario. sin embargo, puede usar sin estado o con estado para representar la interfaz de usuario, pero prácticamente con estado son más útiles cuando la interfaz de usuario es total o parcialmente dependiente de los datos externos (como - renderizar una lista usando api) mientras que el uso de un widget sin estado para representar la interfaz de usuario estática como cualquier pantalla de entrada es una buena práctica.

avinash
fuente
1
Creo que el autor quiso decir lo contrario: · D
Roc Boronat
0

En palabras simples:

Como sabemos, cada widget es una vista en movimiento. Que tiene sus propias clases. Cuando usamos esas clases, creamos un objeto de ellas. Damos valores a sus diferentes variables / propiedades. Ex. Estamos creando un widget de texto para poder asignarle Cadena, Color, Tamaño de fuente, Familia de fuentes. Entonces, al dar esto, estamos definiendo sus propiedades mientras lo creamos. Hasta este punto, los widgets sin estado o con estado son iguales pero,

Cuando queramos cambiar / actualizar sus propiedades (digamos String o Color) una y otra vez después, deberíamos usar el widget Stateful.

Y cuando no queremos cambiar sus propiedades después de definir la primera vez, es un widget sin estado.

eso significa que nos preocupamos por los datos que el widget contiene / controla / muestra.

Entonces, Stateless es menos datos y Stateful está lleno de datos.

Ahora, si define una clase que no tiene estado, eso significa que a esta clase no le importa / tiene variables en ella o dice datos en su propia clase, es decir, nivel de clase, pero podría tener otro widget / clase en ella que se preocupa por los datos, es decir, tiene estado . Por lo tanto, no tienen ningún impacto entre sí.

Por favor corríjame si me equivoco aquí.

vivek s
fuente
0

¿Qué son los widgets con estado y sin estado?

Widget sin estado: los widgets sin estado se compilan solo cuando se trata de cambios principales.

Widgets con estado: los widgets completos de estado mantienen el estado del widget y se pueden reconstruir cuando cambia el estado.

mewadaarvind
fuente